require 'rest_client' require 'json' require 'active_support' require 'active_support/core_ext' require 'oauth2' require 'encryptor' class ZooppaApiV3 # Initializes the Rest Request # resource: string - resource name - must be plural (i.e. 'invitations', 'companies') # method: sym - HTTP VERB (:post, :put, :delete, :get) # cookies: Rails cookies Object - from controller - is required when 'authenticate' is set to true # params: hash - params from controller # id: integer - resource id - required for show, update & destroy action only # authenticate: boolean - API call requires authentication (true) or not (false)? # api_version: string - specifies version of API - default: v2 # # Here we use KEYWORD ARGUMENTS (new in ruby 2.0.0): http://magazine.rubyist.net/?Ruby200SpecialEn-kwarg def initialize(**args) @api_host = args.fetch(:api_host) { 'http://localhost:3000/' } @version = args.fetch(:version) { 'v3' } @app_secret = args.fetch(:app_secret) { 'app_secret' } @app_id = args.fetch(:app_id) { 'app_id' } @encrypt = args.fetch(:encrypt) { true } # needed for encrypting the access token @iv = args.fetch(:iv) { '' } end def method_missing(method,*args,&block) puts "Params #{@params}" puts "Filter params: #{@filter_params }" eigenclass = class << self; self; end eigenclass.class_eval do define_method(method) do @resource = method.to_s return self end end send(method, *args, &block) end def update_attributes(params) @method = :patch @params = params self end def create(params) @method = :post @params = params self end def where(*args) @method = :get @filter_params = '' args.each_with_index do |filter, index| @filter_params += '&' unless @filter_params == '' @filter_params += "filters[filter_#{index}]=#{filter}" end self end def sort(sort_by) @method = :get @sort_params = "sort_by#{sort_by.to_query('')}" self end def find(id) @method = :get @id = id.to_s self end def page(page) @method = :get @page_params = "page=#{page.to_s}" self end def per_page(per_page) @method = :get @per_page_params = "per_page=#{per_page.to_s}" self end def delete @method = :delete self end def execute(token = nil) @url = build_url add_auth_token(token) if token if [:post, :put, :patch].include?(@method) JSON.parse(RestClient.send(@method, @url, @params)) else JSON.parse(RestClient.send(@method, @url)) end end # TODO: find a better solution for that def clean_up @filter_params = nil end # Builds the URL (adds an id of provided) def build_url puts "Complete params: #{complete_parameters(query_params, pagination_params)}" puts "Complete params: #{complete_parameters(query_params, pagination_params)}" url = @api_host + 'api/' + @version + '/' + @resource url += '/' + @id if @id url += '.json' if [:delete, :get].include?(@method) @params = complete_parameters(query_params, pagination_params) if [:delete, :get].include?(@method) url += '?' + @params unless @params == '' end clean_up url end def complete_parameters(query_params, pagination_params) if query_params != '' && pagination_params != '' return [query_params, pagination_params].join('&') elsif query_params == '' return pagination_params elsif pagination_params == '' return query_params else return '' end end def query_params puts "query params: execute" query_params = '' if @filter_params query_params += @filter_params end if @sort_params query_params += '&' unless query_params == '' query_params += @sort_params end return query_params end def pagination_params pagination_params = '' if @page_params pagination_params += @page_params end if @per_page_params pagination_params += '&' unless pagination_params == '' pagination_params += @per_page_params end return pagination_params end # Adds the auth_token to the params hash or url (depending on the HTTP verb) def add_auth_token(token) if @encrypt token = decrypt_token(token) end if [:get, :delete].include?(@method) && !@params.empty? @url += '&access_token=' + token elsif [:get, :delete].include?(@method) && @params.empty? @url += '?access_token=' + token else @params.merge!(access_token: token) end end def authenticate(email, password) client = OAuth2::Client.new( @app_id, @app_secret, site: @api_host ) token = client.password.get_token(email, password).token @encrypt ? encrypt_token(token) : token rescue => e parse_error_message(e) end def decrypt_token(encrypted_token) Encryptor.decrypt(encrypted_token, :key => @app_id, :iv => @iv, :salt => @app_secret) end def encrypt_token(token) Encryptor.encrypt(token, :key => @app_id, :iv => @iv, :salt => @app_secret) end def parse_error_message(e) msg = e.try(:code) == 'invalid_resource_owner' ? 'Invalid email or password.' : 'There seems to be a connection problem' { error: msg } end end