office_autopilot_api 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c7d7c8092131eb0c00fdf8b4f6e6d0056d29489f
4
+ data.tar.gz: 4c13482acbab47bb54ef2df6207742c116516d92
5
+ SHA512:
6
+ metadata.gz: 88de50b2078e5548909f52f1d1496523c5eeacced13f025f7b2d2500acb27ed1722b8b9c9d67fe91945fa636f2c7ed2aea5131dcaa2ccf592916b7cd4942594a
7
+ data.tar.gz: d3143011e8bcc35c5b84f76305fc2b725fbb30f45c4e160c937837a4b9736551a85ecb70746660fa5c16b8dde26d2860bda82b73c16466c60d5551ff03400b81
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ .rvmrc
4
+ .idea
5
+ Gemfile.lock
6
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in office_autopilot.gemspec
4
+ gemspec
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Prashant Nadarajan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,71 @@
1
+ The OfficeAutopilot Ruby Gem
2
+ ============================
3
+ A Ruby wrapper for the OfficeAutopilot API
4
+
5
+ Installation
6
+ ------------
7
+ gem install office_autopilot_api
8
+
9
+ Usage Examples
10
+ --------------
11
+ require "rubygems"
12
+ require "office_autopilot_api"
13
+
14
+ client = OfficeAutopilotApi::Client.new(:api_id => 'xxx', :api_key => 'yyy')
15
+
16
+ # Search Contacts
17
+ puts client.contacts_search(:field => 'E-Mail', :op => 'e', :value => 'prashant@example.com')
18
+ # results truncated for brevity but ALL fields (including custom fields) are returned
19
+ => [{"id"=>"7",
20
+ "Contact Information"=>{"First Name"=>"testing", "Last Name"=>"testing", "E-Mail"=>"prashant@example.com"},
21
+ "Lead Information"=>{"Contact Owner"=>"XXX", "First Referrer"=>"", "Last Referrer"=>""},
22
+ "Sequences and Tags"=>{"Sequences"=>"*/*", "Contact Tags"=>""},
23
+ "Purchase History"=>{}
24
+ }]
25
+
26
+ # Add Contact
27
+ puts client.contacts_add({ 'Contact Information' => {'First Name' => 'Turtle', 'Last Name' => 'Jones', 'E-Mail' => 'mrturtles@example.com'} })
28
+ => {"id"=>"24", "Contact Information"=>{"First Name"=>"Turtle", "Last Name"=>"Jones", "E-Mail"=>"mrturtles@example.com"}}
29
+
30
+ Documentation
31
+ -------------
32
+
33
+ #### Currently supported API methods:
34
+
35
+ **Contacts:**
36
+
37
+ * contacts_search
38
+
39
+ * contacts_add
40
+
41
+ * contacts_pull_tag
42
+
43
+ * contacts_fetch_sequences
44
+
45
+ * contacts_key
46
+
47
+ * contacts_fetch
48
+
49
+
50
+ [**OfficeAutopilot API Docs**](http://wiki.sendpepper.com/w/page/19528683/API-Documentation)
51
+
52
+ Todo
53
+ ----
54
+
55
+ * support ALL API calls
56
+
57
+ Submitting a Pull Request
58
+ -------------------------
59
+ 1. Fork the project.
60
+ 2. Create a topic branch.
61
+ 3. Implement your feature or bug fix.
62
+ 4. Add documentation for your feature or bug fix.
63
+ 5. Add specs for your feature or bug fix.
64
+ 6. Run <tt>bundle exec rake spec</tt>. If your changes are not 100% covered, go back to step 5.
65
+ 7. Commit and push your changes.
66
+ 8. Submit a pull request. Please do not include changes to the gemspec or version file. (If you want to create your own version for some reason, please do so in a separate commit.)
67
+
68
+ Copyright
69
+ ---------
70
+ Copyright (c) 2011 Prashant Nadarajan.
71
+ See [LICENSE](https://github.com/parasquid/office_autopilot/blob/master/MIT_LICENSE) for details.
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :test => :spec
8
+ task :default => :spec
@@ -0,0 +1 @@
1
+ require 'office_autopilot_api/client'
@@ -0,0 +1,51 @@
1
+ require 'builder'
2
+ require 'nokogiri'
3
+
4
+ require File.expand_path('../error', __FILE__)
5
+ require File.expand_path('../request', __FILE__)
6
+ require File.expand_path('../client/contacts', __FILE__)
7
+
8
+ module OfficeAutopilotApi
9
+ class Client
10
+
11
+ include Contacts
12
+
13
+ def initialize(options)
14
+ @api = {
15
+ :api_id => options[:api_id],
16
+ :api_key => options[:api_key]
17
+ }
18
+
19
+ raise ArgumentError, "Missing required parameter: api_id" if @api[:api_id].nil?
20
+ raise ArgumentError, "Missing required parameter: api_key" if @api[:api_key].nil?
21
+ end
22
+
23
+ def api_id
24
+ @api[:api_id]
25
+ end
26
+
27
+ def api_key
28
+ @api[:api_key]
29
+ end
30
+
31
+ def auth
32
+ { 'Appid' => api_id, 'Key' => api_key }
33
+ end
34
+
35
+ def request(method, path, options)
36
+ options[:body].merge!(auth)
37
+ handle_response( OfficeAutopilotApi::Request.send(method, path, options) )
38
+ end
39
+
40
+ def handle_response(response)
41
+ xml = Nokogiri::XML(response)
42
+
43
+ if xml.at_css('result').content =~ /failure/i
44
+ raise OfficeAutopilotApi::XmlError if xml.at_css('result error').content =~ /Invalid XML/i
45
+ end
46
+
47
+ response
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,160 @@
1
+ module OfficeAutopilotApi
2
+ class Client
3
+ module Contacts
4
+
5
+ CONTACTS_ENDPOINT = '/cdata.php'
6
+
7
+ def contacts_search(options)
8
+ xml = xml_for_search(options)
9
+ response = request(:post, CONTACTS_ENDPOINT, :body => {'reqType' => 'search', 'data' => xml})
10
+ parse_contacts_xml(response)
11
+ end
12
+
13
+ def contacts_add(options)
14
+ xml = xml_for_contact(options)
15
+ response = request(:post, CONTACTS_ENDPOINT, :body => {'reqType' => 'add', 'return_id' => '1', 'data' => xml})
16
+ parse_contacts_xml(response)[0]
17
+ end
18
+
19
+ def contacts_update(options)
20
+ xml = xml_for_contact(options)
21
+ response = request(:post, CONTACTS_ENDPOINT, :body => {'reqType' => 'update', 'return_id' => '1', 'data' => xml})
22
+ parse_contacts_xml(response)[0]
23
+ end
24
+
25
+ def contacts_pull_tag
26
+ response = request(:post, CONTACTS_ENDPOINT, :body => {'reqType' => 'pull_tag'})
27
+ parse_xml(response, "tag")
28
+ end
29
+
30
+ def contacts_fetch_sequences
31
+ response = request(:post, CONTACTS_ENDPOINT, :body => {'reqType' => 'fetch_sequences'})
32
+ parse_xml(response, "sequence")
33
+ end
34
+
35
+ def contacts_key
36
+ response = request(:post, CONTACTS_ENDPOINT, :body => {'reqType' => 'key'})
37
+ parse_contacts_key_xml(response)
38
+ end
39
+
40
+ def contacts_fetch(ids)
41
+ xml = xml_for_fetch("contact", ids)
42
+ response = request(:post, CONTACTS_ENDPOINT, :body => {'reqType' => 'fetch', 'data' => xml})
43
+ parse_contacts_xml(response)
44
+ end
45
+
46
+ private
47
+
48
+ def parse_contacts_xml(response)
49
+ contacts = []
50
+ xml = Nokogiri::XML(response)
51
+ xml.css('result contact').each do |node|
52
+ contact = {}
53
+ contact['id'] = node['id']
54
+
55
+ node.css('Group_Tag').each do |group_tag|
56
+ group_tag_name = group_tag['name']
57
+ contact[group_tag_name] = {}
58
+
59
+ group_tag.css('field').each do |field|
60
+ field_name = field['name']
61
+ contact[group_tag_name][field_name] = field.content
62
+ end
63
+ end
64
+ contacts << contact
65
+ end
66
+ contacts
67
+ end
68
+
69
+ def parse_contacts_key_xml(response)
70
+ groups = {}
71
+
72
+ xml = Nokogiri::XML(response)
73
+ xml.css('result contact Group_Tag').each do |group_tag|
74
+ group = { 'fields' => {} }
75
+ group['editable'] = group_tag['editable'] == '1'
76
+
77
+ group_tag.css('field').each do |field_node|
78
+ field_type = field_node['type']
79
+ field_info = { 'type' => field_type }
80
+ field_info['editable'] = field_node['editable'] == '1'
81
+
82
+ case field_type
83
+ when 'tdrop'
84
+ options = []
85
+ field_info['options'] = options
86
+ field_node.css('option').each do |option_node|
87
+ options << option_node.content
88
+ end
89
+ when 'list'
90
+ list = {}
91
+ field_info['list'] = list
92
+ field_node.css('list').each do |list_node|
93
+ list[list_node['id']] = list_node.content
94
+ end
95
+ end
96
+ group['fields'][field_node['name']] = field_info
97
+ end
98
+ groups[group_tag['name']] = group
99
+ end
100
+ groups
101
+ end
102
+
103
+ def parse_xml(response, element_name)
104
+ result = {}
105
+ xml = Nokogiri::XML(response)
106
+ xml.css("result #{element_name}").each do |node|
107
+ id = node['id']
108
+ result[id] = node.content
109
+ end
110
+ result
111
+ end
112
+
113
+ def xml_for_contact(options)
114
+ attrs = {}
115
+ id = options.delete('id')
116
+ attrs[:id] = id if id
117
+ action = options.delete('action')
118
+
119
+ xml = Builder::XmlMarkup.new
120
+ xml.contact(attrs) do
121
+ options.each_key do |group_tag|
122
+ xml.Group_Tag(:name => group_tag) do
123
+ options[group_tag].each do |field, value|
124
+ xml_params = {:name => field}
125
+ xml_params[:action] = action unless action.nil? || action.blank?
126
+ xml.field(value, xml_params)
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ def xml_for_fetch(type, ids)
134
+ xml = ""
135
+ ids.each do |id|
136
+ xml << "<#{type}_id>#{id}</#{type}_id>"
137
+ end
138
+ xml
139
+ end
140
+
141
+ def xml_for_search(options)
142
+ if options.is_a?(Hash)
143
+ options = [options]
144
+ end
145
+
146
+ xml = Builder::XmlMarkup.new
147
+ xml.search do
148
+ options.each do |option|
149
+ xml.equation do
150
+ xml.field option[:field]
151
+ xml.op option[:op]
152
+ xml.value option[:value]
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,7 @@
1
+ module OfficeAutopilotApi
2
+ # Custom error class for rescuing from all OfficeAutopilot errors
3
+ class Error < StandardError; end
4
+
5
+ # Raised when OfficeAutopilot returns <result>failure<error>Invalid XML</error></result>
6
+ class XmlError < Error; end
7
+ end
@@ -0,0 +1,11 @@
1
+ require 'httparty'
2
+
3
+ module OfficeAutopilotApi
4
+ class Request
5
+
6
+ include HTTParty
7
+ base_uri 'http://api.moon-ray.com'
8
+ format :plain
9
+
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module OfficeAutopilotApi
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "office_autopilot_api/version"
4
+
5
+ Gem::Specification.new do |s|
6
+
7
+ s.add_development_dependency('rake', '~> 0.8')
8
+ s.add_development_dependency('rspec', '~> 2.5')
9
+ s.add_development_dependency('webmock', '~> 1.6')
10
+
11
+ s.add_runtime_dependency('httparty', '~> 0.7')
12
+ s.add_runtime_dependency('builder', '>= 2.1.2')
13
+ s.add_runtime_dependency('nokogiri', '~> 1.4')
14
+
15
+ s.name = "office_autopilot_api"
16
+ s.version = OfficeAutopilotApi::VERSION
17
+ s.platform = Gem::Platform::RUBY
18
+ s.authors = ["Prashant Nadarajan", "parasquid"]
19
+ s.email = ["prashant.nadarajan@gmail.com", 'parasquid']
20
+ s.homepage = "https://github.com/parasquid/office_autopilot"
21
+ s.summary = %q{Ruby wrapper for the OfficeAutopilot API}
22
+ s.description = %q{A Ruby wrapper for the OfficeAutopilot API}
23
+
24
+ s.rubyforge_project = "office_autopilot_api"
25
+
26
+ s.files = `git ls-files`.split("\n")
27
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
28
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
29
+ s.require_paths = ["lib"]
30
+ end
@@ -0,0 +1,69 @@
1
+ <result>
2
+ <contact id='7' date='1299671887' dlm='1299674450' score='0.00' purl='prashant' bulk_mail='1'>
3
+ <Group_Tag name='Contact Information'>
4
+ <field name="First Name">prashant</field>
5
+ <field name="Last Name">nadarajan</field>
6
+ <field name="E-Mail">prashant@example.com</field>
7
+ <field name="Home Phone"/>
8
+ <field name="Title"/>
9
+ <field name="Office Phone"/>
10
+ <field name="Cell Phone"/>
11
+ <field name="Fax"/>
12
+ <field name="Address"/>
13
+ <field name="Company"/>
14
+ <field name="Address 2"/>
15
+ <field name="City"/>
16
+ <field name="State"/>
17
+ <field name="Zip Code"/>
18
+ <field name="Website "/>
19
+ <field name="Country"/>
20
+ <field name="Birthday"/>
21
+ </Group_Tag>
22
+ <Group_Tag name='Lead Information'>
23
+ <field name="Contact Owner">Don Corleone</field>
24
+ <field name="First Referrer"/>
25
+ <field name="Last Referrer"/>
26
+ <field name="Lead Source"/>
27
+ <field name="Campaign"/>
28
+ <field name="Ad"/>
29
+ <field name="Media"/>
30
+ </Group_Tag>
31
+ <Group_Tag name='Sequences and Tags'>
32
+ <field name="Sequences">*/*</field>
33
+ <field name="Contact Tags"/>
34
+ </Group_Tag>
35
+ <Group_Tag name='Purchase History'></Group_Tag>
36
+ <Group_Tag name='Most Recent Charge'>
37
+ <field name="Charge Amount">$0.00</field>
38
+ <field name="Charge Invoice #"/>
39
+ </Group_Tag>
40
+ <Group_Tag name='Affiliate Data'>
41
+ <field name="Affiliate Program"/>
42
+ <field name="Number of Sales"/>
43
+ <field name="$ Sales">$0.00</field>
44
+ <field name="Paypal E-mail"/>
45
+ <field name="Affiliate Paypal"/>
46
+ </Group_Tag>
47
+ <Group_Tag
48
+ name='Most Recent Invoice'>
49
+ <field name="Invoice #"/>
50
+ <field name="Total Invoice Amount">$0.00</field>
51
+ </Group_Tag>
52
+ <Group_Tag name='Lead Status'>
53
+ <field name="Lead Status"/>
54
+ <field name="Preferencia Contacto"/>
55
+ </Group_Tag>
56
+ <Group_Tag name='Credit Card'>
57
+ <field name="Card Type"/>
58
+ <field name="Card Expiration Month"/>
59
+ <field name="Charge Result"/>
60
+ <field name="Card Expiration Year"/>
61
+ <field name="Card Number (Last 4)"/>
62
+ <field name="Payment Center Link"/>
63
+ </Group_Tag>
64
+ <Group_Tag name='Invoices'></Group_Tag>
65
+ <Group_Tag name='Subscriptions and Payment Plans'></Group_Tag>
66
+ <Group_Tag name='Website Subscribers'></Group_Tag>
67
+ </contact>
68
+ <status>Success</status>
69
+ </result>