freshsales 0.0.1 → 0.0.2
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.
- checksums.yaml +4 -4
- data/.github_changelog_generator +2 -0
- data/Gemfile.lock +14 -1
- data/README.md +73 -16
- data/Rakefile +230 -0
- data/freshsales.gemspec +5 -0
- data/lib/freshsales/api.rb +7 -6
- data/lib/freshsales/client.rb +41 -11
- data/lib/freshsales/cursor.rb +5 -5
- data/lib/freshsales/version.rb +1 -1
- metadata +51 -3
- data/TODO +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d54635b139964c033e9532c4b1974e7fa293e74c
|
4
|
+
data.tar.gz: b4d785ec4f4231c9790b875dd26ad190127fcde0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0fb676c8e26e2f2d3a8ad4cbe2791b6d8921ef73f92599fd6ff36a5d77eb98b7cb9eb25d596e9ec6aac6837f99f5b3ff5f2e086abe17198d89b868333d94a885
|
7
|
+
data.tar.gz: 92bab7498a879736d76417dcc71083c8ab68fe9958be9a3a9c9f884def51da56007f375913f180d23a965ba614c841afb8a0df055a8e1fce223d16a5ebd68283
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
freshsales (0.0.
|
4
|
+
freshsales (0.0.2)
|
5
5
|
faraday (~> 0.9.1)
|
6
6
|
multi_json (~> 1.11.0)
|
7
7
|
|
@@ -19,6 +19,7 @@ GEM
|
|
19
19
|
builder (3.2.3)
|
20
20
|
byebug (10.0.2)
|
21
21
|
coderay (1.1.2)
|
22
|
+
colored (1.2)
|
22
23
|
concurrent-ruby (1.0.5)
|
23
24
|
coveralls (0.8.21)
|
24
25
|
json (>= 1.8, < 3)
|
@@ -26,6 +27,8 @@ GEM
|
|
26
27
|
term-ansicolor (~> 1.3)
|
27
28
|
thor (~> 0.19.4)
|
28
29
|
tins (~> 1.6)
|
30
|
+
crack (0.4.3)
|
31
|
+
safe_yaml (~> 1.0.0)
|
29
32
|
diff-lcs (1.3)
|
30
33
|
docile (1.1.5)
|
31
34
|
faraday (0.9.2)
|
@@ -40,6 +43,8 @@ GEM
|
|
40
43
|
rainbow (>= 2.1)
|
41
44
|
rake (>= 10.0)
|
42
45
|
retriable (~> 2.1)
|
46
|
+
hashdiff (0.3.7)
|
47
|
+
highline (1.7.10)
|
43
48
|
i18n (1.0.0)
|
44
49
|
concurrent-ruby (~> 1.0)
|
45
50
|
json (2.1.0)
|
@@ -86,6 +91,7 @@ GEM
|
|
86
91
|
ruby-progressbar (~> 1.7)
|
87
92
|
unicode-display_width (~> 1.0, >= 1.0.1)
|
88
93
|
ruby-progressbar (1.9.0)
|
94
|
+
safe_yaml (1.0.4)
|
89
95
|
sawyer (0.8.1)
|
90
96
|
addressable (>= 2.3.5, < 2.6)
|
91
97
|
faraday (~> 0.8, < 1.0)
|
@@ -102,20 +108,27 @@ GEM
|
|
102
108
|
tzinfo (1.2.5)
|
103
109
|
thread_safe (~> 0.1)
|
104
110
|
unicode-display_width (1.3.0)
|
111
|
+
webmock (3.3.0)
|
112
|
+
addressable (>= 2.3.6)
|
113
|
+
crack (>= 0.3.2)
|
114
|
+
hashdiff
|
105
115
|
|
106
116
|
PLATFORMS
|
107
117
|
ruby
|
108
118
|
|
109
119
|
DEPENDENCIES
|
110
120
|
bundler (~> 1.13)
|
121
|
+
colored (>= 1.2, < 2.0.0)
|
111
122
|
coveralls
|
112
123
|
freshsales!
|
113
124
|
github_changelog_generator
|
125
|
+
highline (~> 1.7.10)
|
114
126
|
pry-byebug
|
115
127
|
rake (~> 10.0)
|
116
128
|
rspec (~> 3.1.0)
|
117
129
|
rspec_junit_formatter (~> 0.2.3)
|
118
130
|
rubocop (~> 0.52.1)
|
131
|
+
webmock (~> 3.3.0)
|
119
132
|
|
120
133
|
BUNDLED WITH
|
121
134
|
1.16.1
|
data/README.md
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
#
|
1
|
+
# Freshsales
|
2
2
|
|
3
3
|
[](https://github.com/DragonBox/freshsales/blob/master/LICENSE)
|
4
|
-
[](https://rubygems.org/gems/freshsales)
|
5
5
|
[](https://circleci.com/gh/DragonBox/freshsales)
|
6
6
|
[](https://coveralls.io/github/DragonBox/freshsales?branch=master)
|
7
7
|
|
8
|
-
Freshsales is a ruby wrapper around Freshsales API.
|
8
|
+
Freshsales is a ruby wrapper around [Freshsales API](https://www.freshsales.io/api/)
|
9
9
|
|
10
10
|
---
|
11
11
|
|
@@ -15,46 +15,103 @@ Freshsales is a ruby wrapper around Freshsales API.
|
|
15
15
|
gem install freshsales
|
16
16
|
```
|
17
17
|
|
18
|
+
### Requirements
|
19
|
+
|
20
|
+
A Freshsales account and an API key. You can set your API key here.
|
21
|
+
|
22
|
+
https://yourdomain.freshsales.io/personal-settings/api-settings
|
23
|
+
|
18
24
|
## Getting started
|
19
25
|
|
20
26
|
```ruby
|
21
|
-
|
22
|
-
|
23
|
-
config[:freshsales_domain] = "yourdomain" # from https://yourdomain.freshsales.io/
|
24
|
-
Freshsales::API.new(config)
|
27
|
+
# given https://yourdomain.freshsales.io/ and your API key
|
28
|
+
freshsales = Freshsales::API.new(freshsales_domain: "yourdomain", freshsales_apikey: "...")
|
25
29
|
```
|
26
30
|
|
31
|
+
### Design philosophy
|
32
|
+
|
33
|
+
Freshsales expose resources using a RESTful API allowing to [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) those resources. It also provides extra features such as search.
|
34
|
+
|
35
|
+
Inspired by [gibbon](https://github.com/amro/gibbon), this library provides a simple dynamic language to construct the URLs required to query those resources.
|
36
|
+
|
37
|
+
E.g. `freshsales.leads.post(body: requestbody)` would represent a `POST /api/leads/` request and return a `Freshsale::Response` instance.
|
38
|
+
|
39
|
+
The json data (`requestbody`) can be passed as string or Hashes.
|
40
|
+
|
41
|
+
The received json data can be obtained as raw or Hashes (with symbolized keys or not).
|
42
|
+
|
27
43
|
## Examples
|
28
44
|
|
29
|
-
|
45
|
+
### Create / Read / Update / Search / Delete resources
|
30
46
|
|
31
47
|
```ruby
|
32
48
|
email = "sample@sample.com"
|
33
49
|
|
34
50
|
lead_data = %({"lead":{"last_name":"Sampleton (sample)", "email": "#{email}"}})
|
35
51
|
|
36
|
-
#
|
52
|
+
# Create lead
|
37
53
|
result = freshsales.leads.post(body: lead_data)
|
38
54
|
lead_id = result.body['lead']['id']
|
39
55
|
|
40
56
|
updated_lead_data = %({"lead":{"mobile_number":"1-926-555-9999", "email": "#{email}"}})
|
41
57
|
|
42
|
-
#
|
43
|
-
freshsales.leads(lead_id).put(body: updated_lead_data).body
|
44
|
-
|
45
|
-
# get the lead
|
58
|
+
# Read the lead
|
46
59
|
freshsales.leads(lead_id).get.body
|
47
60
|
|
48
|
-
#
|
61
|
+
# Update the lead
|
62
|
+
freshsales.leads(lead_id).put(body: updated_lead_data).body
|
63
|
+
|
64
|
+
# Search the lead by email
|
49
65
|
sample = freshsales.search.get(params: {include: "lead", q: email}).body.first
|
50
66
|
|
51
|
-
#
|
67
|
+
# Delete it
|
52
68
|
freshsales.leads(lead_id).delete
|
53
69
|
```
|
54
70
|
|
71
|
+
### Finding a particular view
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
filters = freshsales.contacts.filters.get
|
75
|
+
|
76
|
+
view_id = filters.body['filters'].select{|f| "All Contacts" == f['name'] }.first['id']
|
77
|
+
```
|
78
|
+
|
79
|
+
### Paginated resources
|
80
|
+
|
81
|
+
Some resources are paginated and controlled by the `per_page` and `page` parameters.
|
82
|
+
|
83
|
+
While you can return individual pages like this:
|
84
|
+
```ruby
|
85
|
+
freshsales.contacts.view(view_id).get(params: {"per_page": 100, "page": 2})).body
|
86
|
+
```
|
87
|
+
|
88
|
+
the library also allows to iterate over all pages either one element at a time or one page at a time, lazily making the requests for the different pages when required by the client.
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
freshsales.contacts.view(view_id).get_all.each do |contact|
|
92
|
+
# do something with this contact, which may come from any page
|
93
|
+
end
|
94
|
+
|
95
|
+
page_params = { "per_page": 100, "sort": "id", "sort_type": "asc", "include": "owner,creater,source"}
|
96
|
+
freshsales.contacts.view(view_id).get_all_pages(params: page_params).each do |contact_page|
|
97
|
+
# do something with this page's data which may contain up to 100 contacts and
|
98
|
+
# their associated owner, creater and source data
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
102
|
+
`get_all` and `get_all_pages` return a `Freshsale::Cursor` whose `each` method returns a ruby `Enumerator` when no block is given.
|
103
|
+
|
104
|
+
**tip** Enumerators in ruby can be used as [Enumerable](https://ruby-doc.org/core/Enumerable.html). This allows you to apply collection operations on them, even chain them, to transform or filter the returned data.
|
105
|
+
|
106
|
+
E.g. if you wanted to restrict the number of elements/pages you could do `get_all[_pages].each.take(100)[.each]`.
|
107
|
+
|
55
108
|
### Troubleshoot
|
56
109
|
|
57
|
-
Enable the `debug` option
|
110
|
+
Enable the `debug` option (`Freshsales::API.new(debug: true)`)
|
111
|
+
|
112
|
+
### WIP / first public release
|
113
|
+
|
114
|
+
The library is a work in progress. There will be a couple of API changes before the first public version is officially rolled out. Check [the issues targeted for the 0.1.0 milestone](https://github.com/DragonBox/freshsales/issues?q=is%3Aopen+is%3Aissue+milestone%3A0.1.0)
|
58
115
|
|
59
116
|
### Solve SSL Errors
|
60
117
|
|
data/Rakefile
CHANGED
@@ -24,9 +24,239 @@ require "bundler/gem_tasks"
|
|
24
24
|
require "rspec/core/rake_task"
|
25
25
|
require 'rubocop/rake_task'
|
26
26
|
|
27
|
+
require 'logger'
|
28
|
+
require 'colored'
|
29
|
+
require 'highline/import'
|
30
|
+
module UI
|
31
|
+
# raised from crash!
|
32
|
+
class UICrash < StandardError
|
33
|
+
end
|
34
|
+
|
35
|
+
class EPipeIgnorerLogDevice < Logger::LogDevice
|
36
|
+
def initialize(logdev)
|
37
|
+
@logdev = logdev
|
38
|
+
end
|
39
|
+
|
40
|
+
# rubocop:disable HandleExceptions
|
41
|
+
def write(message)
|
42
|
+
@logdev.write(message)
|
43
|
+
rescue Errno::EPIPE
|
44
|
+
# ignored
|
45
|
+
end
|
46
|
+
# rubocop:enable HandleExceptions
|
47
|
+
end
|
48
|
+
class << self
|
49
|
+
def log
|
50
|
+
return @log if @log
|
51
|
+
|
52
|
+
$stdout.sync = true
|
53
|
+
|
54
|
+
@log ||= Logger.new(EPipeIgnorerLogDevice.new($stdout))
|
55
|
+
|
56
|
+
@log.formatter = proc do |severity, datetime, _progname, msg|
|
57
|
+
"#{format_string(datetime, severity)}#{msg}\n"
|
58
|
+
end
|
59
|
+
|
60
|
+
@log
|
61
|
+
end
|
62
|
+
|
63
|
+
def verbose?
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
def format_string(datetime = Time.now, severity = "")
|
68
|
+
timestamp ||= if verbose?
|
69
|
+
'%Y-%m-%d %H:%M:%S.%2N'
|
70
|
+
else
|
71
|
+
'%H:%M:%S'
|
72
|
+
end
|
73
|
+
s = []
|
74
|
+
s << "#{severity} " if verbose? && severity && !severity.empty?
|
75
|
+
s << "[#{datetime.strftime(timestamp)}] " if timestamp
|
76
|
+
s.join('')
|
77
|
+
end
|
78
|
+
|
79
|
+
def confirm(message)
|
80
|
+
verify_interactive!(message)
|
81
|
+
agree("#{format_string}#{message.to_s.yellow} (y/n)", true)
|
82
|
+
end
|
83
|
+
|
84
|
+
def user_error!(message)
|
85
|
+
raise StandardError.new(message.to_s.red)
|
86
|
+
end
|
87
|
+
|
88
|
+
def input(message)
|
89
|
+
verify_interactive!(message)
|
90
|
+
ask("#{format_string}#{message.to_s.yellow}").to_s.strip
|
91
|
+
end
|
92
|
+
|
93
|
+
def error(message)
|
94
|
+
log.error(message.to_s.red)
|
95
|
+
end
|
96
|
+
|
97
|
+
def important(message)
|
98
|
+
log.error(message.to_s.yellow)
|
99
|
+
end
|
100
|
+
|
101
|
+
def success(message)
|
102
|
+
log.error(message.to_s.green)
|
103
|
+
end
|
104
|
+
|
105
|
+
def message(message)
|
106
|
+
log.info(message.to_s)
|
107
|
+
end
|
108
|
+
|
109
|
+
def deprecated(message)
|
110
|
+
log.error(message.to_s.bold.blue)
|
111
|
+
end
|
112
|
+
|
113
|
+
def command(message)
|
114
|
+
log.info("$ #{message}".cyan.underline)
|
115
|
+
end
|
116
|
+
|
117
|
+
def interactive?
|
118
|
+
interactive = true
|
119
|
+
interactive = false if $stdout.isatty == false
|
120
|
+
# interactive = false if Helper.ci?
|
121
|
+
return interactive
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def verify_interactive!(message)
|
127
|
+
return if interactive?
|
128
|
+
important(message)
|
129
|
+
crash!("Could not retrieve response as the program runs in non-interactive mode")
|
130
|
+
end
|
131
|
+
|
132
|
+
def crash!(exception)
|
133
|
+
raise UICrash.new, exception.to_s
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
27
138
|
RSpec::Core::RakeTask.new(:spec)
|
28
139
|
RuboCop::RakeTask.new
|
29
140
|
|
141
|
+
class GithubChangelogGenerator
|
142
|
+
PATH = '.github_changelog_generator'.freeze
|
143
|
+
class << self
|
144
|
+
def future_release
|
145
|
+
s = File.read(PATH)
|
146
|
+
s.split("\n").each do |line|
|
147
|
+
m = line.match(/future-release=v(.*)/)
|
148
|
+
return m[1] if m
|
149
|
+
end
|
150
|
+
raise "Couldn't find future-release in #{PATH}"
|
151
|
+
end
|
152
|
+
|
153
|
+
def future_release=(nextv)
|
154
|
+
s = File.read(PATH)
|
155
|
+
lines = s.split("\n").map do |line|
|
156
|
+
m = line.match(/future-release=v(.*)/)
|
157
|
+
if m
|
158
|
+
"future-release=v#{nextv}"
|
159
|
+
else
|
160
|
+
line
|
161
|
+
end
|
162
|
+
end
|
163
|
+
File.write(PATH, lines.join("\n") + "\n")
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class FreshsalesCode
|
169
|
+
PATH = 'lib/freshsales/version.rb'.freeze
|
170
|
+
class << self
|
171
|
+
def version=(version)
|
172
|
+
s = File.read(PATH)
|
173
|
+
lines = s.split("\n").map do |line|
|
174
|
+
m = line.match(/(.*VERSION = ['"]).*(['"].freeze.*)/)
|
175
|
+
if m
|
176
|
+
"#{m[1]}#{version}#{m[2]}"
|
177
|
+
else
|
178
|
+
line
|
179
|
+
end
|
180
|
+
end
|
181
|
+
File.write(PATH, lines.join("\n") + "\n")
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
require 'English'
|
187
|
+
def run_command(command, error_message = nil)
|
188
|
+
output = `#{command}`
|
189
|
+
unless $CHILD_STATUS.success?
|
190
|
+
error_message = "Failed to run command '#{command}'" if error_message.nil?
|
191
|
+
UI.user_error!(error_message)
|
192
|
+
end
|
193
|
+
output
|
194
|
+
end
|
195
|
+
|
196
|
+
task :ensure_git_clean do
|
197
|
+
branch = run_command('git rev-parse --abbrev-ref HEAD', "Couldn't get current git branch").strip
|
198
|
+
UI.user_error!("You are not on 'master' but on '#{branch}'") unless branch == "master"
|
199
|
+
output = run_command('git status --porcelain', "Couldn't get git status")
|
200
|
+
UI.user_error!("git status not clean:\n#{output}") unless output == ""
|
201
|
+
end
|
202
|
+
|
203
|
+
# ensure ready to prepare a PR
|
204
|
+
task :prepare_git_pr, [:pr_branch] do |_t, args|
|
205
|
+
pr_branch = args['pr_branch']
|
206
|
+
raise "Missing pr_branch argument" unless pr_branch
|
207
|
+
UI.user_error! "Prepare git PR stopped by user" unless UI.confirm("Creating PR branch #{pr_branch}")
|
208
|
+
run_command("git checkout -b #{pr_branch}")
|
209
|
+
end
|
210
|
+
|
211
|
+
desc 'Prepare a release: check repo status, generate changelog, create PR'
|
212
|
+
task pre_release: 'ensure_git_clean' do
|
213
|
+
require 'freshsales/version'
|
214
|
+
nextversion = Freshsales::VERSION
|
215
|
+
|
216
|
+
# check not already released
|
217
|
+
output = run_command("git tag -l v#{nextversion}").strip
|
218
|
+
UI.user_error! "Version '#{nextversion}' already released. Run 'rake bump'" unless output == ''
|
219
|
+
|
220
|
+
gh_future_release = GithubChangelogGenerator.future_release
|
221
|
+
UI.user_error! "GithubChangelogGenerator version #{gh_future_release} != #{nextversion}" unless gh_future_release == nextversion
|
222
|
+
|
223
|
+
pr_branch = "release_#{nextversion}"
|
224
|
+
Rake::Task["prepare_git_pr"].invoke(pr_branch)
|
225
|
+
|
226
|
+
Rake::Task["changelog"].invoke
|
227
|
+
|
228
|
+
sh('git diff')
|
229
|
+
# FIXME: cleanup branch, etc
|
230
|
+
UI.user_error! "Pre release stopped by user." unless UI.confirm("CHANGELOG PR for version #{nextversion}. Confirm?")
|
231
|
+
|
232
|
+
msg = "Preparing release for #{nextversion}"
|
233
|
+
sh 'git add CHANGELOG.md'
|
234
|
+
sh "git commit -m '#{msg}'"
|
235
|
+
sh "git push lacostej" # FIXME: hardcoded
|
236
|
+
# FIXME: check hub present
|
237
|
+
sh "hub pull-request -m '#{msg}'" # requires hub pre-release " -l nochangelog"
|
238
|
+
sh 'git checkout master'
|
239
|
+
sh "git branch -D #{pr_branch}"
|
240
|
+
end
|
241
|
+
|
242
|
+
desc 'Bump the version number to the version entered interactively; pushes a commit to master'
|
243
|
+
task bump: 'ensure_git_clean' do
|
244
|
+
nextversion = UI.input "Next version will be:"
|
245
|
+
UI.user_error! "Bump version stopped by user" unless UI.confirm("Next version will be #{nextversion}. Confirm?")
|
246
|
+
FreshsalesCode.version = nextversion
|
247
|
+
GithubChangelogGenerator.future_release = nextversion
|
248
|
+
sh 'rspec'
|
249
|
+
sh 'git add .github_changelog_generator lib/freshsales/version.rb Gemfile.lock'
|
250
|
+
sh "git commit -m 'Bump version to #{nextversion}'"
|
251
|
+
sh 'git push'
|
252
|
+
end
|
253
|
+
|
254
|
+
desc 'Update the changelog, no commit made'
|
255
|
+
task :changelog do
|
256
|
+
puts "Updating changelog #{ENV['CHANGELOG_GITHUB_TOKEN']}"
|
257
|
+
sh "github_changelog_generator" if ENV['CHANGELOG_GITHUB_TOKEN']
|
258
|
+
end
|
259
|
+
|
30
260
|
desc 'Run all rspec tests'
|
31
261
|
task :test_all do
|
32
262
|
formatter = "--format progress"
|
data/freshsales.gemspec
CHANGED
@@ -34,4 +34,9 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.add_development_dependency "rspec", "~> 3.1.0"
|
35
35
|
spec.add_development_dependency 'rspec_junit_formatter', '~> 0.2.3'
|
36
36
|
spec.add_development_dependency 'rubocop', '~> 0.52.1'
|
37
|
+
spec.add_development_dependency "webmock", "~> 3.3.0"
|
38
|
+
spec.add_development_dependency "colored", '>= 1.2', '< 2.0.0'
|
39
|
+
spec.add_development_dependency "highline", "~> 1.7.10"
|
40
|
+
|
41
|
+
|
37
42
|
end
|
data/lib/freshsales/api.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
module Freshsales
|
2
2
|
class API
|
3
|
-
attr_accessor :
|
3
|
+
attr_accessor :freshsales_apikey, :freshsales_domain, :debug, :symbolize_keys, :logger, :faraday_adapter, :proxy, :raw_data
|
4
4
|
|
5
5
|
def initialize(opts = {})
|
6
|
-
@
|
6
|
+
@freshsales_apikey = opts.fetch(:freshsales_apikey, ENV["FRESHSALES_APIKEY"])
|
7
7
|
@freshsales_domain = opts.fetch(:freshsales_domain, ENV["FRESHSALES_DOMAIN"])
|
8
|
-
@
|
8
|
+
@raw_data = opts.fetch(:raw_data, false)
|
9
|
+
@symbolize_keys = opts.fetch(:symbolize_keys, false)
|
9
10
|
@debug = opts.fetch(:debug, false)
|
10
|
-
@logger = ::Logger.new(STDOUT)
|
11
|
-
@
|
12
|
-
@proxy =
|
11
|
+
@logger = opts.fetch(:logger, ::Logger.new(STDOUT))
|
12
|
+
@faraday_adapter = opts.fetch(:faraday_adapter, Faraday.default_adapter)
|
13
|
+
@proxy = opts.fetch(:proxy, ENV["FRESHSALES_PROXY"])
|
13
14
|
|
14
15
|
@client = Client.new(self)
|
15
16
|
end
|
data/lib/freshsales/client.rb
CHANGED
@@ -18,20 +18,24 @@ module Freshsales
|
|
18
18
|
parsed_response = nil
|
19
19
|
|
20
20
|
if response.body && !response.body.empty?
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
rescue MultiJson::ParseError
|
26
|
-
error_params = { title: "UNPARSEABLE_RESPONSE", status_code: 500 }
|
27
|
-
error = FreshsalesError.new("Unparseable response: '#{response.body}'", error_params)
|
28
|
-
raise error
|
29
|
-
end
|
21
|
+
headers = response.headers
|
22
|
+
body = response.body
|
23
|
+
body = jsonify_body(body) unless @config.raw_data
|
24
|
+
parsed_response = Response.new(headers: headers, body: body)
|
30
25
|
end
|
31
26
|
|
32
27
|
parsed_response
|
33
28
|
end
|
34
29
|
|
30
|
+
def jsonify_body(body, ignore_parsing_errors: false)
|
31
|
+
MultiJson.load(body, symbolize_keys: @config.symbolize_keys)
|
32
|
+
rescue MultiJson::ParseError => e
|
33
|
+
return if ignore_parsing_errors
|
34
|
+
error_params = { detail: e.message, status_code: 500, raw_body: body }
|
35
|
+
error = FreshsalesError.new("Unparseable response", error_params)
|
36
|
+
raise error
|
37
|
+
end
|
38
|
+
|
35
39
|
def freshsales_domain
|
36
40
|
"https://#{@config.freshsales_domain}.freshsales.io"
|
37
41
|
end
|
@@ -47,6 +51,32 @@ module Freshsales
|
|
47
51
|
end
|
48
52
|
request.url path
|
49
53
|
end
|
54
|
+
rescue StandardError => e
|
55
|
+
handle_request_error(e)
|
56
|
+
end
|
57
|
+
|
58
|
+
def handle_request_error(error)
|
59
|
+
error_params = {}
|
60
|
+
if error.is_a?(Faraday::Error::ClientError) && error.response
|
61
|
+
error_params[:status_code] = error.response[:status]
|
62
|
+
error_params[:raw_body] = error.response[:body]
|
63
|
+
|
64
|
+
parsed_response = jsonify_body(error.response[:body], ignore_parsing_errors: true)
|
65
|
+
|
66
|
+
if parsed_response
|
67
|
+
error_params[:body] = parsed_response
|
68
|
+
|
69
|
+
code_key = @config.symbolize_keys ? :code : "code"
|
70
|
+
message_key = @config.symbolize_keys ? :message : "message"
|
71
|
+
|
72
|
+
error_params[:code] = parsed_response[code_key] if parsed_response[code_key]
|
73
|
+
error_params[:detail] = parsed_response[message_key] if parsed_response[message_key]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
message = error_params[:detail] || error.message
|
77
|
+
error_to_raise = FreshsalesError.new(message, error_params)
|
78
|
+
|
79
|
+
raise error_to_raise
|
50
80
|
end
|
51
81
|
|
52
82
|
def connection
|
@@ -55,13 +85,13 @@ module Freshsales
|
|
55
85
|
Faraday.new(freshsales_domain, proxy: @config.proxy, ssl: { version: "TLSv1_2" }) do |c|
|
56
86
|
# c.request :url_encoded
|
57
87
|
c.response :raise_error
|
58
|
-
c.use Faraday::Request::Authorization, 'Token', "token=#{@config.
|
88
|
+
c.use Faraday::Request::Authorization, 'Token', "token=#{@config.freshsales_apikey}"
|
59
89
|
if @config.debug
|
60
90
|
c.response :logger, @config.logger, bodies: true do |logger|
|
61
91
|
logger.filter(/(Token token=)(\w+)/, '\1[HIDDEN]')
|
62
92
|
end
|
63
93
|
end
|
64
|
-
c.adapter @config.
|
94
|
+
c.adapter @config.faraday_adapter
|
65
95
|
end
|
66
96
|
end
|
67
97
|
end
|
data/lib/freshsales/cursor.rb
CHANGED
@@ -2,7 +2,7 @@ module Freshsales
|
|
2
2
|
class Cursor
|
3
3
|
include Enumerable
|
4
4
|
|
5
|
-
def initialize(client, path, type, collection_name, args)
|
5
|
+
def initialize(client, path, type, collection_name, args = {})
|
6
6
|
@client = client
|
7
7
|
@path = path
|
8
8
|
@type = type
|
@@ -41,8 +41,6 @@ module Freshsales
|
|
41
41
|
@client.logger
|
42
42
|
end
|
43
43
|
|
44
|
-
MAX = 100_000 # FIXME: get rid off or configure
|
45
|
-
|
46
44
|
def fetch_next_page
|
47
45
|
nextpage = @page + 1
|
48
46
|
@args[:params] = params.merge(page: nextpage)
|
@@ -68,8 +66,10 @@ module Freshsales
|
|
68
66
|
logger.debug "Found #{j.count} elements #{@type} #{@collection_name}"
|
69
67
|
|
70
68
|
data = j
|
69
|
+
elsif j.is_a? String
|
70
|
+
raise "Unexpected data type received #{j.class}. Are you combining pagination with raw_data? Unsupported for now"
|
71
71
|
else
|
72
|
-
raise "Unexpected data type received #{j.class}"
|
72
|
+
raise "Unexpected data type received #{j.class}."
|
73
73
|
end
|
74
74
|
|
75
75
|
@last_response = last
|
@@ -78,7 +78,7 @@ module Freshsales
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def last?
|
81
|
-
@last_response
|
81
|
+
@last_response
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
data/lib/freshsales/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: freshsales
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jerome Lacoste
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-04-
|
11
|
+
date: 2018-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -150,6 +150,54 @@ dependencies:
|
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: 0.52.1
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: webmock
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 3.3.0
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 3.3.0
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: colored
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '1.2'
|
174
|
+
- - "<"
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: 2.0.0
|
177
|
+
type: :development
|
178
|
+
prerelease: false
|
179
|
+
version_requirements: !ruby/object:Gem::Requirement
|
180
|
+
requirements:
|
181
|
+
- - ">="
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
version: '1.2'
|
184
|
+
- - "<"
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: 2.0.0
|
187
|
+
- !ruby/object:Gem::Dependency
|
188
|
+
name: highline
|
189
|
+
requirement: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - "~>"
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: 1.7.10
|
194
|
+
type: :development
|
195
|
+
prerelease: false
|
196
|
+
version_requirements: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - "~>"
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: 1.7.10
|
153
201
|
description: A wrapper for Freshsales API
|
154
202
|
email: jerome@wewanttoknow.com
|
155
203
|
executables: []
|
@@ -159,6 +207,7 @@ files:
|
|
159
207
|
- ".circleci/config.yml"
|
160
208
|
- ".github/ISSUE_TEMPLATE.md"
|
161
209
|
- ".github/PULL_REQUEST_TEMPLATE.md"
|
210
|
+
- ".github_changelog_generator"
|
162
211
|
- ".gitignore"
|
163
212
|
- ".rspec"
|
164
213
|
- ".rubocop.yml"
|
@@ -168,7 +217,6 @@ files:
|
|
168
217
|
- LICENSE
|
169
218
|
- README.md
|
170
219
|
- Rakefile
|
171
|
-
- TODO
|
172
220
|
- appveyor.yml
|
173
221
|
- freshsales.gemspec
|
174
222
|
- lib/freshsales.rb
|