nimble-api 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/README.md +141 -0
- data/Rakefile +33 -0
- data/lib/nimble/base.rb +95 -0
- data/lib/nimble/contact.rb +119 -0
- data/lib/nimble/contacts.rb +19 -0
- data/lib/nimble/version.rb +5 -0
- data/lib/nimble-api.rb +15 -0
- data/nimble_api.gemspec +39 -0
- data/spec/integration/contact_spec.rb +131 -0
- data/spec/integration/contacts_spec.rb +41 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/unit/base_spec.rb +69 -0
- metadata +146 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fd7b880d49fe9c8e605358cdea4fb5c61621ec89
|
4
|
+
data.tar.gz: 65245f911f34dd7bc7273ca3e75c99d02d2f8cd5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 058cc21fb0085e9af501265ee63f2b88d8342e7ee6b0d5bd7a48734f0a84a54336d3507fad38c8c8d75993b90b62d1a5e7fa1b8cfc1b7eb0550da0f706f1f098
|
7
|
+
data.tar.gz: efe7defa1ab729c55f856667652795b2ed8716dde0874729b8f1a1f381cee1544106e2dc8f2976f5ce9b1c11558ec77e732497c989a738d8b92f91d77e02a50e
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
NimbleApi
|
2
|
+
=========
|
3
|
+
|
4
|
+
Ruby wrapper for the nimble api. The wrapper provides classes for Contacts and Contact.
|
5
|
+
|
6
|
+
References:
|
7
|
+
* http://nimble.readthedocs.org/en/latest/
|
8
|
+
* https://github.com/nimblecrm/omniauth-nimble
|
9
|
+
* https://github.com/nimblecrm/ruby-example (use this to fetch your 'refresh' token)
|
10
|
+
|
11
|
+
## Configuration
|
12
|
+
|
13
|
+
The nimble api uses oauth for authorization. As such, you are required to obtain a client secret, token and registered callback url for each domain (including your localhost for testing) before starting to use this wrapper. Once you have obtained these keys, you will need to generate a refresh token. This allows you to access the API without needing to do the oauth dance to recreate your api client each time.
|
14
|
+
|
15
|
+
To use this wrapper, configure the NimbleApiApi with the following:
|
16
|
+
|
17
|
+
NimbleApi.configure do |c|
|
18
|
+
c.client_id = ENV['CLIENT_ID']
|
19
|
+
c.client_secret = ENV['CLIENT_SECRET']
|
20
|
+
c.refresh_token = ENV['REFRESH_TOKEN']
|
21
|
+
end
|
22
|
+
|
23
|
+
If you plan to use this with rails, create config/initializers/nimble.rb with this contents. Reminder that you will need a set of all three ENV variables for each callback url that you plan to deploy, including localhost for testing.
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
# Configure with your id, secret and refresh token for your application
|
28
|
+
NimbleApi.configure do |c|
|
29
|
+
c.client_id = ENV['CLIENT_ID']
|
30
|
+
c.client_secret = ENV['CLIENT_SECRET']
|
31
|
+
c.refresh_token = ENV['REFRESH_TOKEN']
|
32
|
+
end
|
33
|
+
|
34
|
+
# Create a nimble object
|
35
|
+
@nimble = NimbleApi()
|
36
|
+
|
37
|
+
# Create a person hash - email is required
|
38
|
+
@person = {
|
39
|
+
'first name' => 'Fred',
|
40
|
+
'last name' => 'Flintstone',
|
41
|
+
'email' => 'fred@bedrock.org',
|
42
|
+
'tags' => 'test'
|
43
|
+
}
|
44
|
+
|
45
|
+
# Use the hash to create a contact and save it to your Nimble account
|
46
|
+
fred = @nimble.contact.create @person
|
47
|
+
|
48
|
+
fred.save
|
49
|
+
|
50
|
+
# Update one element, or multiple
|
51
|
+
fred.update("parent company" => [{ "modifier"=>"","value"=>"Cogswell Cogs"}])
|
52
|
+
|
53
|
+
# Find a contact by their email address
|
54
|
+
fred = @nimble.contact.by_email 'fred@bedrock.org'
|
55
|
+
|
56
|
+
# Find a contact by id
|
57
|
+
fred = @nimble.contact.fetch "54444842faed29141e5c7300"
|
58
|
+
|
59
|
+
# Use convenience methods to display the id, email and fields
|
60
|
+
> fred.id
|
61
|
+
=> "54444842faed29141e5c7300"
|
62
|
+
|
63
|
+
> fred.email
|
64
|
+
=> "fred@bedrock.org"
|
65
|
+
|
66
|
+
> fred.fields
|
67
|
+
=> {"last name"=>[{"group"=>"Basic Info", ... "value"=>"Flintstone", "label"=>"last name"}],
|
68
|
+
"first name"=>[{"group"=>"Basic Info", ... "value"=>"Fred", "label"=>"first name"}],
|
69
|
+
"lead status"=>[{"group"=>"Lead Details", ... "value"=>"Not Qualified", "label"=>"lead status"}],
|
70
|
+
"email"=>[{"group"=>"Contact Info", ... "value"=>"fred@bedrock.org", "label"=>"email"}],
|
71
|
+
"source"=>[{"group"=>"Basic Info", ... "value"=>"m", "label"=>"source"}],
|
72
|
+
"parent company"=>[{ ... "value"=>"Cogswell Cogs", "label"=>"parent company"}]}
|
73
|
+
|
74
|
+
> fred.note "This is your note"
|
75
|
+
=> {"note"=>"This is your note", ... "note_preview"=>"This is your note" ...
|
76
|
+
|
77
|
+
> fred.task 'next week', 'Big Subject', 'little notes'
|
78
|
+
=> {"due_date"=>"2014-10-29T19:00:00+00:00", "updated"=>"2014-10-19T23:31:43+00:00", "tags"=>[], ....
|
79
|
+
|
80
|
+
> @nimble.contacts.list
|
81
|
+
=> {"meta"=>{"per_page"=>30, "total"=>238, "pages"=>8, "page"=>1}, "resources"=>[...]
|
82
|
+
|
83
|
+
>@nimble.contacts.list(fields: ['first name', 'last name', 'email'])
|
84
|
+
=> ... limited to just these fields
|
85
|
+
|
86
|
+
>@nimble.contacts.list(keyword: 'fred')
|
87
|
+
=> {"meta"=>{"per_page"=>30, "total"=>1, "pages"=>1, "page"=>1}, "resources"=>[ ... just one ... ]
|
88
|
+
|
89
|
+
## Contacts
|
90
|
+
|
91
|
+
Provides list and list_ids, each taking params as described by the nimble api documentation http://nimble.readthedocs.org/en/latest/responses/#contact-list
|
92
|
+
|
93
|
+
## Contact
|
94
|
+
|
95
|
+
Provides a Contact object which can perform a number of instance methods:
|
96
|
+
|
97
|
+
### create
|
98
|
+
Create a new contact by providing a person definition with contact fields.
|
99
|
+
|
100
|
+
@nimble = NimbleApi()
|
101
|
+
person = {
|
102
|
+
'first name' => 'Fred',
|
103
|
+
'last name' => 'Flintstone',
|
104
|
+
'email' => 'fred@bedrock.org',
|
105
|
+
'tags' => 'test'
|
106
|
+
}
|
107
|
+
|
108
|
+
fred = @nimble.contact.create @person
|
109
|
+
|
110
|
+
|
111
|
+
### save
|
112
|
+
Save the contact, results will populate @contact within the object
|
113
|
+
|
114
|
+
fred.save
|
115
|
+
fred.contact['fields'] # accesses returned field values
|
116
|
+
|
117
|
+
### by_email
|
118
|
+
Find a contact by email address
|
119
|
+
|
120
|
+
### fetch, alias: get
|
121
|
+
Find a contact by id. Can also be called from an instance in order to refresh the contact data
|
122
|
+
|
123
|
+
### id, email, fields
|
124
|
+
Convenience methods to access the contact id, first email address and fields hash
|
125
|
+
|
126
|
+
### update
|
127
|
+
Update with new fields contents
|
128
|
+
|
129
|
+
fred.update("parent company" => [{ "modifier"=>"","value"=>"Cogswell Cogs"}])
|
130
|
+
fred.fetch
|
131
|
+
fred.fields['parent company'].first['value'].should eq 'Cogswell Cogs'
|
132
|
+
|
133
|
+
### note
|
134
|
+
Adds a note for the contact
|
135
|
+
|
136
|
+
|
137
|
+
### notes
|
138
|
+
Return notes
|
139
|
+
|
140
|
+
### task
|
141
|
+
Add a task for the contact with due_date, subject and optional notes. The due_date parameter supports the Chronic parser (https://github.com/mojombo/chronic) so that you can use strings such as: 'tomorrow', 'next week', 'thursday'.
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
rescue LoadError
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'rake'
|
7
|
+
require 'rspec/core/rake_task'
|
8
|
+
require 'bundler/gem_tasks'
|
9
|
+
|
10
|
+
desc "Build Gem"
|
11
|
+
task :default do
|
12
|
+
system "gem build nimble_api.gemspec"
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Run specs"
|
16
|
+
RSpec::Core::RakeTask.new('spec') do |t|
|
17
|
+
t.rspec_opts = %w{--colour --format progress}
|
18
|
+
t.pattern = 'spec/*_spec.rb', 'spec/*/*_spec.rb'
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Run unit specs"
|
22
|
+
RSpec::Core::RakeTask.new('spec:unit') do |t|
|
23
|
+
t.rspec_opts = %w{--colour --format progress}
|
24
|
+
t.pattern = 'spec/unit/*_spec.rb', 'spec/unit/*/*_spec.rb'
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Run integration specs"
|
28
|
+
# Before running integration tests, you need to specify
|
29
|
+
# a valid CLIENT_ID, CLIENT_SECRET and REFRESH_TOKEN in the spec/spec_helper.rb file.
|
30
|
+
RSpec::Core::RakeTask.new('spec:integration') do |t|
|
31
|
+
t.rspec_opts = %w{--colour --format progress}
|
32
|
+
t.pattern = 'spec/integration/*_spec.rb'
|
33
|
+
end
|
data/lib/nimble/base.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
module NimbleApi
|
2
|
+
class Base
|
3
|
+
|
4
|
+
def initialize(options)
|
5
|
+
NimbleApi.client_id = options.fetch(:client_id) { raise ArgumentError.new(":client_id is a required argument to initialize NimbleApi") if NimbleApi.client_id.nil?}
|
6
|
+
NimbleApi.client_secret = options.fetch(:client_secret) { raise ArgumentError.new(":client_secret is a required argument to initialize NimbleApi") if NimbleApi.client_secret.nil?}
|
7
|
+
NimbleApi.refresh_token = options.fetch(:refresh_token) { raise ArgumentError.new(":refresh_token is a required argument to initialize NimbleApi") if NimbleApi.refresh_token.nil?}
|
8
|
+
|
9
|
+
NimbleApi.host = options.fetch(:host) {"api.nimble.com"}
|
10
|
+
NimbleApi.callback_path = options.fetch(:callback_path) { "/auth/nimble/callback" }
|
11
|
+
NimbleApi.api_version = options.fetch(:api_version) { "v1" }
|
12
|
+
|
13
|
+
@conn = Faraday.new(:url => "https://#{NimbleApi.host}" ) do |faraday|
|
14
|
+
faraday.request :url_encoded # form-encode POST params
|
15
|
+
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
|
16
|
+
end
|
17
|
+
self.refresh
|
18
|
+
end
|
19
|
+
|
20
|
+
def base_url
|
21
|
+
"https://#{NimbleApi.host}/api/#{NimbleApi.api_version}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def refresh
|
25
|
+
params = {
|
26
|
+
client_id: NimbleApi.client_id,
|
27
|
+
client_secret: NimbleApi.client_secret,
|
28
|
+
grant_type: 'refresh_token',
|
29
|
+
refresh_token: NimbleApi.refresh_token,
|
30
|
+
redirect_uri: NimbleApi.callback_path
|
31
|
+
}
|
32
|
+
resp = @conn.post '/oauth/token', params
|
33
|
+
access_token = (JSON resp.body)['access_token']
|
34
|
+
@conn.headers = { 'Authorization' => "Bearer #{access_token}" }
|
35
|
+
end
|
36
|
+
|
37
|
+
def get endpoint, params={}
|
38
|
+
resp = @conn.get "#{base_url}/#{endpoint}", params
|
39
|
+
raise NimbleApi::Error.new(resp) if resp['errors']
|
40
|
+
return JSON resp.body
|
41
|
+
end
|
42
|
+
|
43
|
+
def post endpoint, params
|
44
|
+
resp = @conn.post do |req|
|
45
|
+
req.url "#{base_url}/#{endpoint}"
|
46
|
+
req.headers['Content-Type'] = 'application/json'
|
47
|
+
req.body = params.to_json
|
48
|
+
end
|
49
|
+
raise NimbleApi::Error.new(resp) if resp['errors']
|
50
|
+
return JSON resp.body
|
51
|
+
end
|
52
|
+
|
53
|
+
def put endpoint, params
|
54
|
+
resp = @conn.put do |req|
|
55
|
+
req.url "#{base_url}/#{endpoint}"
|
56
|
+
req.headers['Content-Type'] = 'application/json'
|
57
|
+
req.body = params.to_json
|
58
|
+
end
|
59
|
+
raise NimbleApi::Error.new(resp) if resp['errors']
|
60
|
+
return JSON resp.body
|
61
|
+
end
|
62
|
+
|
63
|
+
def delete endpoint
|
64
|
+
resp = @conn.delete "#{base_url}/#{endpoint}"
|
65
|
+
raise NimbleApi::Error.new(resp) if resp['errors']
|
66
|
+
return JSON resp.body
|
67
|
+
end
|
68
|
+
|
69
|
+
def contacts
|
70
|
+
NimbleApi::Contacts.new(self)
|
71
|
+
end
|
72
|
+
|
73
|
+
def contact
|
74
|
+
NimbleApi::Contact.new(self)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
class << self
|
81
|
+
attr_accessor :conn,
|
82
|
+
:client_id,
|
83
|
+
:client_secret,
|
84
|
+
:refresh_token,
|
85
|
+
:host,
|
86
|
+
:callback_path,
|
87
|
+
:api_version
|
88
|
+
|
89
|
+
def configure
|
90
|
+
yield self
|
91
|
+
true
|
92
|
+
end
|
93
|
+
alias :config :configure
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module NimbleApi
|
2
|
+
|
3
|
+
class Contact
|
4
|
+
|
5
|
+
attr_accessor :contact
|
6
|
+
def initialize(nimble)
|
7
|
+
@nimble = nimble
|
8
|
+
end
|
9
|
+
|
10
|
+
def create params
|
11
|
+
# email is used as unique id
|
12
|
+
@email = params['email']
|
13
|
+
if params['address']
|
14
|
+
address = {"city" => params['address'], "street" => "", "zip" => "", "country" => ""}.to_json
|
15
|
+
end
|
16
|
+
@person = {
|
17
|
+
"fields" => {
|
18
|
+
"first name" => [{"value" => params['first name'],"modifier" => ""}],
|
19
|
+
"last name" => [{ "value"=> params['last name'],"modifier" => ""}],
|
20
|
+
"parent company" => [{ "modifier"=>"","value"=>params['company']}],
|
21
|
+
"linkedin" => [{"modifier"=>"", "value"=>params['linkedin']}],
|
22
|
+
"URL" => [{ "modifier"=>"other", "value"=>params['website']}],
|
23
|
+
"email" => [{"modifier"=>"work", "value"=>params['email']}],
|
24
|
+
"lead status" => [{"modifier"=>"", "value"=>"Not Qualified"}],
|
25
|
+
"title" => [{"modifier" => "", "value" => params['headline']}],
|
26
|
+
"address" => [ { "modifier" => "work","value" => address }]
|
27
|
+
},
|
28
|
+
"tags" => [params['tags']],
|
29
|
+
"record_type" => "person"
|
30
|
+
}
|
31
|
+
# remove empty fields
|
32
|
+
@person['fields'].keys.each {|k| @person['fields'].delete(k) if @person['fields'][k][0]['value'].nil? }
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
# convenience methods
|
37
|
+
def id
|
38
|
+
self.contact['id']
|
39
|
+
end
|
40
|
+
|
41
|
+
def email
|
42
|
+
self.contact['fields']['email'].first['value']
|
43
|
+
end
|
44
|
+
|
45
|
+
def fields
|
46
|
+
self.contact['fields']
|
47
|
+
end
|
48
|
+
|
49
|
+
# Checks for duplicates by email
|
50
|
+
def save
|
51
|
+
raise 'must call contact.create(params) before save' unless @person
|
52
|
+
raise 'must set email address for unique checking before save' unless @email
|
53
|
+
if @email
|
54
|
+
raise "#{@email} already exists!" unless self.by_email(@email).nil?
|
55
|
+
end
|
56
|
+
self.contact = @nimble.post 'contact', @person
|
57
|
+
return nil unless self.contact
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
def by_email email
|
62
|
+
query = { "and" => [{ "email" => { "is"=> email } },{ "record type"=> { "is"=> "person" }} ] }
|
63
|
+
resp = @nimble.get 'contacts', { :query => query.to_json }
|
64
|
+
self.contact = resp['resources'].first
|
65
|
+
return nil unless self.contact
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
def fetch id=nil
|
70
|
+
id ||= self.id
|
71
|
+
resp = @nimble.get "contact/#{id}"
|
72
|
+
self.contact = resp['resources'].first
|
73
|
+
return nil unless self.contact
|
74
|
+
self
|
75
|
+
end
|
76
|
+
alias_method :get, :fetch
|
77
|
+
|
78
|
+
def update fields
|
79
|
+
self.contact = @nimble.put "contact/#{self.id}", { fields: fields }
|
80
|
+
return nil unless self.contact
|
81
|
+
self
|
82
|
+
end
|
83
|
+
|
84
|
+
def notes params=nil
|
85
|
+
@nimble.get "contact/#{self.id}/notes", params
|
86
|
+
end
|
87
|
+
|
88
|
+
def note note, preview=nil
|
89
|
+
preview ||= note[0..64]
|
90
|
+
params = {
|
91
|
+
contact_ids: [ self.id ],
|
92
|
+
note: note,
|
93
|
+
note_preview: preview
|
94
|
+
}
|
95
|
+
@nimble.post "contacts/notes", params
|
96
|
+
end
|
97
|
+
|
98
|
+
def delete_note id
|
99
|
+
@nimble.delete "contact/notes/#{id}"
|
100
|
+
end
|
101
|
+
|
102
|
+
def delete id=nil
|
103
|
+
id ||= self.id
|
104
|
+
@nimble.delete "contact/#{id}"
|
105
|
+
end
|
106
|
+
|
107
|
+
def task due_date, subject, notes=nil
|
108
|
+
due = Chronic.parse(due_date).strftime('%Y-%m-%d %H:%M')
|
109
|
+
params = {
|
110
|
+
related_to: [ self.id ],
|
111
|
+
subject: subject,
|
112
|
+
due_date: due
|
113
|
+
}
|
114
|
+
params[:notes] = notes if notes
|
115
|
+
@nimble.post "activities/task", params
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module NimbleApi
|
2
|
+
|
3
|
+
class Contacts
|
4
|
+
|
5
|
+
def initialize(nimble)
|
6
|
+
@nimble = nimble
|
7
|
+
end
|
8
|
+
|
9
|
+
def list params={}
|
10
|
+
params[:fields] = params[:fields].join(',') if params[:fields]
|
11
|
+
params[:record_type] ||= 'person'
|
12
|
+
@nimble.get "contacts", params
|
13
|
+
end
|
14
|
+
|
15
|
+
def list_ids params={}
|
16
|
+
@nimble.get "contacts/ids", params
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/nimble-api.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'faraday'
|
3
|
+
require 'chronic'
|
4
|
+
|
5
|
+
require "nimble/version"
|
6
|
+
require 'nimble/base'
|
7
|
+
require 'nimble/contacts'
|
8
|
+
require 'nimble/contact'
|
9
|
+
|
10
|
+
def NimbleApi(options={})
|
11
|
+
options[:client_id] = NimbleApi.client_id if NimbleApi.client_id
|
12
|
+
options[:client_secret] = NimbleApi.client_secret if NimbleApi.client_secret
|
13
|
+
options[:refresh_token] = NimbleApi.refresh_token if NimbleApi.refresh_token
|
14
|
+
NimbleApi::Base.new(options)
|
15
|
+
end
|
data/nimble_api.gemspec
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'nimble/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
|
8
|
+
spec.name = "nimble-api"
|
9
|
+
spec.version = NimbleApi::VERSION
|
10
|
+
spec.homepage = "https://github.com/aptos/NimbleApi"
|
11
|
+
spec.platform = Gem::Platform::RUBY
|
12
|
+
spec.license = 'Apache'
|
13
|
+
|
14
|
+
spec.summary = "Nimble CRM Api Wrapper"
|
15
|
+
spec.description = "Ruby wrapper for the Nimble CRM Api."
|
16
|
+
|
17
|
+
spec.authors = ["Brian Wilkerson"]
|
18
|
+
spec.email = "brian@taskit.io"
|
19
|
+
|
20
|
+
spec.files = `git ls-files`.split($/)
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
|
25
|
+
spec.post_install_message = %q{
|
26
|
+
---------------------------------------------------------------
|
27
|
+
Nimble CRM Api has been installed
|
28
|
+
----------------------------------------------------------------
|
29
|
+
}
|
30
|
+
|
31
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
32
|
+
spec.add_development_dependency "rspec", "~> 2.14"
|
33
|
+
spec.add_development_dependency "rake", "~> 10.1"
|
34
|
+
|
35
|
+
spec.add_dependency "faraday", "~> 0.9"
|
36
|
+
spec.add_dependency "chronic", "~> 0.10"
|
37
|
+
spec.add_dependency "json", "~> 1.7"
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe NimbleApi::Contact do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
NimbleApi.configure do |c|
|
7
|
+
c.client_id = CLIENT_ID
|
8
|
+
c.client_secret = CLIENT_SECRET
|
9
|
+
c.refresh_token = REFRESH_TOKEN
|
10
|
+
end
|
11
|
+
|
12
|
+
@person = {
|
13
|
+
'first name' => 'Fred',
|
14
|
+
'last name' => 'Flintstone',
|
15
|
+
'email' => 'fred@bedrock.org',
|
16
|
+
'tags' => 'test'
|
17
|
+
}
|
18
|
+
@nimble = NimbleApi()
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should create contact" do
|
22
|
+
expect do
|
23
|
+
NimbleApi()
|
24
|
+
@nimble.contact.create @person
|
25
|
+
end.to_not raise_error
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "when contact does not exist" do
|
29
|
+
|
30
|
+
before :each do
|
31
|
+
fred = @nimble.contact.by_email 'fred@bedrock.org'
|
32
|
+
fred.delete if fred
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should save contact" do
|
36
|
+
fred = @nimble.contact.create @person
|
37
|
+
resp = fred.save
|
38
|
+
resp.should_not be_nil
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns nil for missing contact by_email" do
|
42
|
+
@nimble.contact.by_email('nobody@noplace.home').should be_nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "when contact exists" do
|
47
|
+
|
48
|
+
before :each do
|
49
|
+
@fred = @nimble.contact.by_email 'fred@bedrock.org'
|
50
|
+
unless @fred
|
51
|
+
@fred = @nimble.contact.create @person
|
52
|
+
@fred.save
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "can find contact by_email" do
|
57
|
+
resp = @nimble.contact.by_email 'fred@bedrock.org'
|
58
|
+
resp.should_not be_nil
|
59
|
+
end
|
60
|
+
|
61
|
+
it "returns contact by id" do
|
62
|
+
found = @nimble.contact.fetch @fred.id
|
63
|
+
found.should_not be_nil
|
64
|
+
end
|
65
|
+
|
66
|
+
it "updates contact" do
|
67
|
+
@fred.update("parent company" => [{ "modifier"=>"","value"=>"Cogswell Cogs"}])
|
68
|
+
@fred.fetch
|
69
|
+
@fred.fields['parent company'].first['value'].should eq 'Cogswell Cogs'
|
70
|
+
end
|
71
|
+
|
72
|
+
it "can delete with object" do
|
73
|
+
resp = @fred.delete
|
74
|
+
resp['status'].should eq 'ok'
|
75
|
+
end
|
76
|
+
|
77
|
+
it "can delete with id" do
|
78
|
+
resp = @nimble.contact.delete @fred.id
|
79
|
+
resp['status'].should eq 'ok'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "notes" do
|
84
|
+
before :each do
|
85
|
+
@fred = @nimble.contact.by_email 'fred@bedrock.org'
|
86
|
+
unless @fred
|
87
|
+
@fred = @nimble.contact.create @person
|
88
|
+
@fred.save
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
it "gets all notes" do
|
93
|
+
@fred.note "This is your note"
|
94
|
+
notes = @fred.notes
|
95
|
+
notes['meta']['total'].should > 0
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
it "can add a note" do
|
100
|
+
timestamp = Time.now
|
101
|
+
@fred.note "This note sent at #{timestamp}"
|
102
|
+
notes = @fred.notes
|
103
|
+
notes['resources'].first['note'].should match timestamp.to_s
|
104
|
+
end
|
105
|
+
|
106
|
+
it "can delete a note" do
|
107
|
+
timestamp = Time.now
|
108
|
+
@fred.note "This note sent at #{timestamp}"
|
109
|
+
notes = @fred.notes
|
110
|
+
id = notes['resources'].first['note']['id']
|
111
|
+
resp = @fred.delete_note id
|
112
|
+
resp['id'].should eq id
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "tasks" do
|
117
|
+
before :each do
|
118
|
+
@fred = @nimble.contact.by_email 'fred@bedrock.org'
|
119
|
+
unless @fred
|
120
|
+
@fred = @nimble.contact.create @person
|
121
|
+
@fred.save
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it "can add a task" do
|
126
|
+
note = @fred.task 'next week', 'Big Subject', 'little notes'
|
127
|
+
note['subject'].should eq 'Big Subject'
|
128
|
+
note['due_date'].should match Chronic.parse('next week').strftime('%Y-%m-%d')
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe NimbleApi::Contacts do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
NimbleApi.configure do |c|
|
7
|
+
c.client_id = CLIENT_ID
|
8
|
+
c.client_secret = CLIENT_SECRET
|
9
|
+
c.refresh_token = REFRESH_TOKEN
|
10
|
+
end
|
11
|
+
@nimble = NimbleApi()
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "list" do
|
15
|
+
it "should retrieve contacts" do
|
16
|
+
resp = @nimble.contacts.list
|
17
|
+
resp['meta']['total'].should > 0
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should specify fields" do
|
21
|
+
resp = @nimble.contacts.list(fields: ['first name', 'email'])
|
22
|
+
resp['resources'][0]['fields'].keys.should eq ['first name', 'email']
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should limit to record_type = person" do
|
26
|
+
resp = @nimble.contacts.list(fields: ['first name', 'email'])
|
27
|
+
resp['resources'][0]['record_type'].should eq 'person'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can supress tags" do
|
31
|
+
resp = @nimble.contacts.list(tags: 0)
|
32
|
+
resp['resources'][0].keys.include?('tags').should eq false
|
33
|
+
end
|
34
|
+
|
35
|
+
it "supports keyword param" do
|
36
|
+
resp = @nimble.contacts.list(keyword: 'winnie')
|
37
|
+
resp['resources'][0]['fields']['first name'][0]['value'].should eq 'winnie'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
$:.unshift File.expand_path("../lib", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
require 'bundler/setup'
|
6
|
+
Bundler.setup(:development)
|
7
|
+
|
8
|
+
require "rspec"
|
9
|
+
require "nimble"
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.expect_with :rspec do |c|
|
13
|
+
c.syntax = [:should, :expect]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Insert your id, secret and refresh token here, or add to your ENV
|
18
|
+
CLIENT_ID = ENV['NIMBLE_CLIENT_ID']
|
19
|
+
CLIENT_SECRET = ENV['NIMBLE_CLIENT_SECRET']
|
20
|
+
REFRESH_TOKEN = ENV['NIMBLE_REFRESH_TOKEN']
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe NimbleApi::Base do
|
4
|
+
|
5
|
+
it "should raise an error if the client_id has not been set" do
|
6
|
+
NimbleApi.configure do |c|
|
7
|
+
c.client_id = nil
|
8
|
+
end
|
9
|
+
expect do
|
10
|
+
NimbleApi()
|
11
|
+
end.to raise_error ArgumentError
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can be called directly if the keys have been set via NimbleApi.configure" do
|
15
|
+
NimbleApi.configure do |config|
|
16
|
+
config.client_id = "qwer"
|
17
|
+
config.client_secret = "1234"
|
18
|
+
config.refresh_token = "qwer-1234"
|
19
|
+
end
|
20
|
+
expect do
|
21
|
+
NimbleApi()
|
22
|
+
end.to_not raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
it "can be instanced with the keys as a param" do
|
26
|
+
expect do
|
27
|
+
NimbleApi({ :client_id => "qwer", :client_secret => "1234", :refresh_token =>"qwer-1234" })
|
28
|
+
end.to_not raise_error
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
describe "configuration" do
|
33
|
+
|
34
|
+
before(:each) do
|
35
|
+
NimbleApi.configure do |config|
|
36
|
+
config.client_id = "qwer"
|
37
|
+
config.client_secret = "1234"
|
38
|
+
config.refresh_token = "qwer-1234"
|
39
|
+
config.host = "nimble.com"
|
40
|
+
config.callback_path = "/auth/callback"
|
41
|
+
config.api_version = "v2"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "allows me to set my client_id" do
|
46
|
+
NimbleApi.client_id.should eql 'qwer'
|
47
|
+
end
|
48
|
+
|
49
|
+
it "allows me to set my client_secret" do
|
50
|
+
NimbleApi.client_secret.should eql '1234'
|
51
|
+
end
|
52
|
+
|
53
|
+
it "allows me to set my refresh_token" do
|
54
|
+
NimbleApi.refresh_token.should eql 'qwer-1234'
|
55
|
+
end
|
56
|
+
|
57
|
+
it "allows me to set my host" do
|
58
|
+
NimbleApi.host.should eql 'nimble.com'
|
59
|
+
end
|
60
|
+
|
61
|
+
it "allows me to set my callback_path" do
|
62
|
+
NimbleApi.callback_path.should eql "/auth/callback"
|
63
|
+
end
|
64
|
+
|
65
|
+
it "allows me to set my api_version" do
|
66
|
+
NimbleApi.api_version.should eql 'v2'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nimble-api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brian Wilkerson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.14'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.14'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: faraday
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.9'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.9'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: chronic
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.10'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.10'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: json
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.7'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.7'
|
97
|
+
description: Ruby wrapper for the Nimble CRM Api.
|
98
|
+
email: brian@taskit.io
|
99
|
+
executables: []
|
100
|
+
extensions: []
|
101
|
+
extra_rdoc_files: []
|
102
|
+
files:
|
103
|
+
- Gemfile
|
104
|
+
- README.md
|
105
|
+
- Rakefile
|
106
|
+
- lib/nimble-api.rb
|
107
|
+
- lib/nimble/base.rb
|
108
|
+
- lib/nimble/contact.rb
|
109
|
+
- lib/nimble/contacts.rb
|
110
|
+
- lib/nimble/version.rb
|
111
|
+
- nimble_api.gemspec
|
112
|
+
- spec/integration/contact_spec.rb
|
113
|
+
- spec/integration/contacts_spec.rb
|
114
|
+
- spec/spec_helper.rb
|
115
|
+
- spec/unit/base_spec.rb
|
116
|
+
homepage: https://github.com/aptos/NimbleApi
|
117
|
+
licenses:
|
118
|
+
- Apache
|
119
|
+
metadata: {}
|
120
|
+
post_install_message: "\n ---------------------------------------------------------------\n
|
121
|
+
\ Nimble CRM Api has been installed\n ----------------------------------------------------------------\n
|
122
|
+
\ "
|
123
|
+
rdoc_options: []
|
124
|
+
require_paths:
|
125
|
+
- lib
|
126
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - '>='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - '>='
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
requirements: []
|
137
|
+
rubyforge_project:
|
138
|
+
rubygems_version: 2.0.3
|
139
|
+
signing_key:
|
140
|
+
specification_version: 4
|
141
|
+
summary: Nimble CRM Api Wrapper
|
142
|
+
test_files:
|
143
|
+
- spec/integration/contact_spec.rb
|
144
|
+
- spec/integration/contacts_spec.rb
|
145
|
+
- spec/spec_helper.rb
|
146
|
+
- spec/unit/base_spec.rb
|