From c3176c59df9a303d4ede1e33b4e236b6fd0b1a1c Mon Sep 17 00:00:00 2001 From: Corey Finley Date: Wed, 28 Oct 2015 18:12:07 -0400 Subject: [PATCH] Extends interaction with Marketo API Inorder to fit our needs when interacting with Marketo, I've extended this gem to connect with more of Marketo's API * Adds paging token gathering * Adds Activities module. Gathering activity types and activities * Adds Opportunities module. Gathering oppotunity types and description * Adds CrudLeads#describe_lead --- .gitignore | 2 + Gemfile.lock | 6 +- lib/mrkt.rb | 7 ++ lib/mrkt/concerns/activities.rb | 12 +++ lib/mrkt/concerns/crud_leads.rb | 4 + lib/mrkt/concerns/opportunities.rb | 19 +++++ lib/mrkt/concerns/paging_token.rb | 21 ++++++ spec/concerns/activities_spec.rb | 101 ++++++++++++++++++++++++++ spec/concerns/crud_leads_spec.rb | 48 ++++++++++++ spec/concerns/opportunities_spec.rb | 109 ++++++++++++++++++++++++++++ spec/concerns/paging_token_spec.rb | 24 ++++++ 11 files changed, 350 insertions(+), 3 deletions(-) create mode 100644 lib/mrkt/concerns/activities.rb create mode 100644 lib/mrkt/concerns/opportunities.rb create mode 100644 lib/mrkt/concerns/paging_token.rb create mode 100644 spec/concerns/activities_spec.rb create mode 100644 spec/concerns/opportunities_spec.rb create mode 100644 spec/concerns/paging_token_spec.rb diff --git a/.gitignore b/.gitignore index 6ef4a16..e127e08 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ /pkg/ /spec/reports/ /tmp/ +/.ruby-version +/tags diff --git a/Gemfile.lock b/Gemfile.lock index 244466b..7635ea1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -21,9 +21,9 @@ GEM safe_yaml (~> 1.0.0) diff-lcs (1.2.5) docile (1.1.5) - faraday (0.9.1) + faraday (0.9.2) multipart-post (>= 1.2, < 3) - faraday_middleware (0.9.1) + faraday_middleware (0.9.2) faraday (>= 0.7.4, < 0.10) json (1.8.2) method_source (0.8.2) @@ -86,4 +86,4 @@ DEPENDENCIES webmock (~> 1.21.0) BUNDLED WITH - 1.10.6 + 1.11.2 diff --git a/lib/mrkt.rb b/lib/mrkt.rb index 2d14cd0..d618c08 100644 --- a/lib/mrkt.rb +++ b/lib/mrkt.rb @@ -3,6 +3,9 @@ require 'mrkt/concerns/connection' require 'mrkt/concerns/authentication' +require 'mrkt/concerns/activities' +require 'mrkt/concerns/opportunities' +require 'mrkt/concerns/paging_token' require 'mrkt/concerns/crud_helpers' require 'mrkt/concerns/crud_campaigns' require 'mrkt/concerns/crud_leads' @@ -13,11 +16,14 @@ module Mrkt class Client include Connection include Authentication + include Activities + include PagingToken include CrudHelpers include CrudCampaigns include CrudLeads include CrudLists include ImportLeads + include Opportunities attr_accessor :debug @@ -35,6 +41,7 @@ def initialize(options = {}) authenticate! resp = connection.send(http_method, path, payload) do |req| + req.options.params_encoder = Faraday::FlatParamsEncoder add_authorization(req) block.call(req) unless block.nil? end diff --git a/lib/mrkt/concerns/activities.rb b/lib/mrkt/concerns/activities.rb new file mode 100644 index 0000000..4a78512 --- /dev/null +++ b/lib/mrkt/concerns/activities.rb @@ -0,0 +1,12 @@ +module Mrkt + module Activities + def get_activity_types + get("/rest/v1/activities/types.json") + end + + def get_activities(page_token, date, activity_type_ids) + params = { nextPageToken: page_token, activityTypeIds: activity_type_ids } + get("/rest/v1/activities.json", params) + end + end +end diff --git a/lib/mrkt/concerns/crud_leads.rb b/lib/mrkt/concerns/crud_leads.rb index 529f6d0..915df70 100644 --- a/lib/mrkt/concerns/crud_leads.rb +++ b/lib/mrkt/concerns/crud_leads.rb @@ -12,6 +12,10 @@ def get_leads(filter_type, filter_values, fields: nil, batch_size: nil, next_pag get('/rest/v1/leads.json', params) end + def describe_lead + get('/rest/v1/leads/describe.json') + end + def createupdate_leads(leads, action: 'createOrUpdate', lookup_field: nil, partition_name: nil, async_processing: nil) post('/rest/v1/leads.json') do |req| params = { diff --git a/lib/mrkt/concerns/opportunities.rb b/lib/mrkt/concerns/opportunities.rb new file mode 100644 index 0000000..aa9c7c6 --- /dev/null +++ b/lib/mrkt/concerns/opportunities.rb @@ -0,0 +1,19 @@ +module Mrkt + module Opportunities + def get_opportunities(filter_type, filter_values, fields: nil, batch_size: nil, next_page_token: nil) + params = { + filterType: filter_type, + filterValues: filter_values.join(',') + } + params[:fields] = fields if fields + params[:batchSize] = batch_size if batch_size + params[:nextPageToken] = next_page_token if next_page_token + + get('/rest/v1/opportunities.json', params) + end + + def describe_opportunity + get('/rest/v1/opportunities/describe.json') + end + end +end diff --git a/lib/mrkt/concerns/paging_token.rb b/lib/mrkt/concerns/paging_token.rb new file mode 100644 index 0000000..6c5b901 --- /dev/null +++ b/lib/mrkt/concerns/paging_token.rb @@ -0,0 +1,21 @@ +module Mrkt + module PagingToken + def get_paging_token(date) + params = { sinceDatetime: format_date(date) } + + get("/rest/v1/activities/pagingtoken.json", params)[:nextPageToken] + end + + private + + def format_date(date) + date = Date.parse(date) if date.is_a? String + + unless date.is_a? Date + fail ArgumentError.new("Expected Date or String. Got #{date.class}") + end + + date.strftime("%FT%T") + end + end +end diff --git a/spec/concerns/activities_spec.rb b/spec/concerns/activities_spec.rb new file mode 100644 index 0000000..d4c8dba --- /dev/null +++ b/spec/concerns/activities_spec.rb @@ -0,0 +1,101 @@ +describe Mrkt::Activities do + include_context 'initialized client' + + describe '#get_activity_types' do + let(:response_stub) do + { + "requestId":"6e78#148ad3b76f1", + "success":true, + "result":[ + { + "id":1, + "name":"Visit Webpage", + "description":"User visits web page", + "primaryAttribute":{ + "name":"Webpage ID", + "dataType":"integer" + }, + "attributes":[ + { "name":"Client IP Address", "dataType":"string" }, + { "name":"Query Parameters", "dataType":"string" }, + { "name":"Referrer URL", "dataType":"string" }, + { "name":"Search Engine", "dataType":"string" }, + { "name":"Search Query", "dataType":"string" }, + { "name":"User Agent", "dataType":"string" }, + { "name":"Webpage URL", "dataType":"string" } + ] + }, + { + "id":2, + "name":"Fill Out Form", + "description":"User fills out and submits form on web page", + "primaryAttribute":{ + "name":"Webform ID", + "dataType":"integer" + }, + "attributes":[ + { "name":"Client IP Address", "dataType":"string" }, + { "name":"Form Fields", "dataType":"text" }, + { "name":"Query Parameters", "dataType":"string" }, + { "name":"Referrer URL", "dataType":"string" }, + { "name":"User Agent", "dataType":"string" }, + { "name":"Webpage ID", "dataType":"integer" } + ] + } + ] + } + end + subject { client.get_activity_types } + + before do + stub_request(:get, "https://#{host}/rest/v1/activities/types.json") + .to_return(json_stub(response_stub)) + end + + it { is_expected.to eq(response_stub) } + end + + describe '#get_activities' do + let(:date) { Date.new(2013, 9, 25) } + let(:first_page_token) { "GIYDAOBNGEYS2MBWKQYDAORQGA5DAMBOGAYDAKZQGAYDALBQ" } + let(:activity_type_ids) { [1, 12] } + let(:first_response_stub) do + { + "requestId":"a9ae#148add1e53d", + "success":true, + "nextPageToken":"EYS2MBWKQYDAORQGA5D", + "moreResult":true, + "result":[ + { + "id":2, + "leadId":6, + "activityDate":"2013-09-25T00:39:45+0000", + "activityTypeId":12, + "primaryAttributeValueId":6, + "primaryAttributeValue":"Owyliphys Iledil", + "attributes":[ { "name":"Source Type", "value":"Web page visit" } ] + }, + { + "id":3, + "leadId":9, + "activityDate":"2013-09-25T06:56:35+0000", + "activityTypeId":1, + "primaryAttributeValueId":4, + "primaryAttributeValue":"anti-phishing", + "attributes":[ { "name":"Query Parameters", "value":nil } ] + } + ] + } + end + + subject { client.get_activities(first_page_token, date, activity_type_ids) } + + before do + activity_type_ids_params = activity_type_ids.map { |id| "activityTypeIds=#{id}" }.join("&") + stub_request(:get, "https://#{host}/rest/v1/activities.json?nextPageToken=#{first_page_token}&#{activity_type_ids_params}") + .to_return(json_stub(first_response_stub)) + end + + it { is_expected.to eq(first_response_stub) } + end +end diff --git a/spec/concerns/crud_leads_spec.rb b/spec/concerns/crud_leads_spec.rb index d446831..ce73f4d 100644 --- a/spec/concerns/crud_leads_spec.rb +++ b/spec/concerns/crud_leads_spec.rb @@ -31,6 +31,54 @@ it { is_expected.to eq(response_stub) } end + describe '#describe_lead' do + let(:response_stub) do + { + "requestId":"37ca#1475b74e276", + "success":true, + "result":[ + { + "id":2, + "displayName":"Company Name", + "dataType":"string", + "length":255, + "rest":{ + "name":"company", + "readOnly":false + }, + "soap":{ + "name":"Company", + "readOnly":false + } + }, + { + "id":3, + "displayName":"Site", + "dataType":"string", + "length":255, + "rest":{ + "name":"site", + "readOnly":false + }, + "soap":{ + "name":"Site", + "readOnly":false + } + } + ] + } + end + + subject { client.describe_lead } + + before do + stub_request(:get, "https://#{host}/rest/v1/leads/describe.json") + .to_return(json_stub(response_stub)) + end + + it { is_expected.to eq(response_stub) } + end + describe '#createupdate_leads' do let(:leads) do [ diff --git a/spec/concerns/opportunities_spec.rb b/spec/concerns/opportunities_spec.rb new file mode 100644 index 0000000..a59af11 --- /dev/null +++ b/spec/concerns/opportunities_spec.rb @@ -0,0 +1,109 @@ +describe Mrkt::Opportunities do + include_context 'initialized client' + + describe '#get_opportunities' do + let(:filter_type) { 'seq' } + let(:filter_values) { [0, 1] } + let(:response_stub) do + { + "requestId":"e42b#14272d07d78", + "success":true, + "result":[ + { + "seq":0, + "marketoGUID":"da42707c-4dc4-4fc1-9fef-f30a3017240a", + "externalOpportunityId":"19UYA31581L000000", + "name":"Chairs", + "description":"Chairs", + "amount":"1604.47", + "source":"Inbound Sales Call/Email" + }, + { + "seq":1, + "marketoGUID":"da42707c-4dc4-4fc1-9fef-f30a3017240b", + "externalOpportunityId":"29UYA31581L000000", + "name":"Big Dog Day Care-Phase12", + "description":"Big Dog Day Care-Phase12", + "amount":"1604.47", + "source":"Email" + } + ] + } + end + subject { client.get_opportunities(filter_type, filter_values) } + + before do + stub_request(:get, "https://#{host}/rest/v1/opportunities.json") + .with(query: { filterType: filter_type, filterValues: filter_values.join(',') }) + .to_return(json_stub(response_stub)) + end + + it { is_expected.to eq(response_stub) } + end + + describe '#describe_opportunity' do + let(:response_stub) do + { + "requestId":"185d6#14b51985ff0", + "success":true, + "result":[ + { + "name":"opportunity", + "displayName":"Opportunity", + "createdAt":"2015-02-03T22:36:23Z", + "updatedAt":"2015-02-03T22:36:24Z", + "idField":"marketoGUID", + "dedupeFields":[ + "externalOpportunityId" + ], + "searchableFields":[ + [ + "externalOpportunityId" + ], + [ + "marketoGUID" + ] + ], + "fields":[ + { + "name":"marketoGUID", + "displayName":"Marketo GUID", + "dataType":"string", + "length":36, + "updateable":false + }, + { + "name":"createdAt", + "displayName":"Created At", + "dataType":"datetime", + "updateable":false + }, + { + "name":"updatedAt", + "displayName":"Updated At", + "dataType":"datetime", + "updateable":false + }, + { + "name":"externalOpportunityId", + "displayName":"External Opportunity Id", + "dataType":"string", + "length":50, + "updateable":false + } + ] + } + ] + } + end + + subject { client.describe_opportunity } + + before do + stub_request(:get, "https://#{host}/rest/v1/opportunities/describe.json") + .to_return(json_stub(response_stub)) + end + + it { is_expected.to eq(response_stub) } + end +end diff --git a/spec/concerns/paging_token_spec.rb b/spec/concerns/paging_token_spec.rb new file mode 100644 index 0000000..af5dbf4 --- /dev/null +++ b/spec/concerns/paging_token_spec.rb @@ -0,0 +1,24 @@ +describe Mrkt::CrudLeads do + include_context 'initialized client' + + describe '#get_activity_types' do + let(:date) { Date.parse("2014-09-25") } + let(:next_page_token) { "GIYDAOBNGEYS2MBWKQYDAORQGA5DAMBOGAYDAKZQGAYDALBQ" } + let(:response_stub) do + { + "requestId": "1607c#14884f3e74e", + "success": true, + "nextPageToken": next_page_token + } + end + subject { client.get_paging_token(date) } + + before do + stub_request(:get, "https://#{host}/rest/v1/activities/pagingtoken.json") + .with(query: { sinceDatetime: date.strftime("%FT%T") }) + .to_return(json_stub(response_stub)) + end + + it { is_expected.to eq(next_page_token) } + end +end