close 0.1.0 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9aa1bc5d8124785414823311b95736c9ddde2ca4c5f2746e6308443f313ace7a
4
- data.tar.gz: e3eac1f1c53b1da521845eb66bd3a8ec6cd342c608cf216b2cef62e7b0cea410
3
+ metadata.gz: 4ae57ff51e41efeb5bcf5464bca8b5e23a6388806e71fc73378d389be7d652a1
4
+ data.tar.gz: 61eec10200545f071801b978090b9c43e8608e2dc3230207ecbe07bb903106ce
5
5
  SHA512:
6
- metadata.gz: 0a5b9a3e0ee10bced5cccad33bc838c8b156fad65c821f332f548a94d0a6eff47847a340b946b5e91b12c0503bc36c0af883347cca12aa95887ad4d62e3d3144
7
- data.tar.gz: 991f361451aedaf253e9d602f3f8975deb3495202fb2f294c058b32b4ba83ecd20a9d262e7ab2d23aff1ba0d64dea314cfe9c0c05c8773beac094dfdcc218e64
6
+ metadata.gz: 84e59c4ef43627a67343d39f93ef6cf888aa5c038dfa54ee65d23ee3d38d54422788ce44ea6b8b9410e57a0a4bcb7527671d3ef20a5723232895127c177b8509
7
+ data.tar.gz: 776e2d4bedb0051203e458e200ee6e45b016904dbb3d1b6cdaf180988bd3c482ff43408eb981c678389cc1db1cdefd8f2d9dd1cb25a16f8e724a64484bd06a34
data/Gemfile CHANGED
@@ -12,3 +12,7 @@ gem "rspec", "~> 3.0"
12
12
  gem "rubocop", "~> 1.21"
13
13
 
14
14
  gem "faraday"
15
+
16
+ gem "webmock"
17
+
18
+ gem "sinatra"
data/Gemfile.lock CHANGED
@@ -1,24 +1,35 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- close (0.1.0)
4
+ close (0.1.1)
5
5
  faraday
6
6
  ostruct
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
+ addressable (2.8.1)
12
+ public_suffix (>= 2.0.2, < 6.0)
11
13
  ast (2.4.2)
14
+ crack (0.4.5)
15
+ rexml
12
16
  diff-lcs (1.5.0)
13
17
  faraday (2.6.0)
14
18
  faraday-net_http (>= 2.0, < 3.1)
15
19
  ruby2_keywords (>= 0.0.4)
16
20
  faraday-net_http (3.0.1)
21
+ hashdiff (1.0.1)
17
22
  json (2.6.2)
23
+ mustermann (3.0.0)
24
+ ruby2_keywords (~> 0.0.1)
18
25
  ostruct (0.5.5)
19
26
  parallel (1.22.1)
20
27
  parser (3.1.2.1)
21
28
  ast (~> 2.4.1)
29
+ public_suffix (5.0.0)
30
+ rack (2.2.4)
31
+ rack-protection (3.0.2)
32
+ rack
22
33
  rainbow (3.1.1)
23
34
  rake (13.0.6)
24
35
  regexp_parser (2.6.0)
@@ -50,10 +61,21 @@ GEM
50
61
  parser (>= 3.1.1.0)
51
62
  ruby-progressbar (1.11.0)
52
63
  ruby2_keywords (0.0.5)
64
+ sinatra (3.0.2)
65
+ mustermann (~> 3.0)
66
+ rack (~> 2.2, >= 2.2.4)
67
+ rack-protection (= 3.0.2)
68
+ tilt (~> 2.0)
69
+ tilt (2.0.11)
53
70
  unicode-display_width (2.3.0)
71
+ webmock (3.18.1)
72
+ addressable (>= 2.8.0)
73
+ crack (>= 0.3.2)
74
+ hashdiff (>= 0.4.0, < 2.0.0)
54
75
 
55
76
  PLATFORMS
56
77
  arm64-darwin-21
78
+ ruby
57
79
 
58
80
  DEPENDENCIES
59
81
  close!
@@ -61,6 +83,8 @@ DEPENDENCIES
61
83
  rake (~> 13.0)
62
84
  rspec (~> 3.0)
63
85
  rubocop (~> 1.21)
86
+ sinatra
87
+ webmock
64
88
 
65
89
  BUNDLED WITH
66
90
  2.3.7
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Close
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/close.svg)](https://badge.fury.io/rb/close) [![Test Coverage](https://api.codeclimate.com/v1/badges/d83380e81bfb459ea027/test_coverage)](https://codeclimate.com/github/joynerd/close/test_coverage)
4
+
3
5
  This a ruby gem that provides a robust way to interact with the Close
4
6
  CRM API.
5
7
 
@@ -59,17 +61,39 @@ leads = Close::Lead.list
59
61
  # Get a single lead
60
62
  lead = Close::Lead.retrieve('lead_id')
61
63
 
62
- # Update the name
64
+ # Update the name (and other attributes) of a lead. These are not persisted to the API until you call save.
63
65
  lead.name = 'New Name'
64
66
 
65
67
  # Save the changes
66
68
  lead.save
67
69
 
68
-
69
70
  ```
70
71
 
71
72
  ## Supported Resources
72
73
 
74
+ ### Advanced Filters
75
+ [Close API Docs](https://developer.close.com/resources/leads/)
76
+
77
+ Advanced Filters are a clever way to open up search to the API, with the caveat that they are very dense and appear to be written in search DSL (Elastic, Solr, etc).
78
+
79
+ I have tried to encapsulate the complexity of the DSL into a simple interface that is easy to use. This is mostly by defining queries before
80
+ they are run and then running them with parameters when they are needed.
81
+
82
+ An example of an advanced filter query:
83
+
84
+ ```ruby
85
+ # Run a prebuilt query
86
+ Close::AdvancedFilter.run('find_leads_by_email', {email: 'buster.bluth@gmail.com'})
87
+
88
+ # Add a new query
89
+ Close::AdvancedFilter.add('find_leads_by_phone_number', {phone_number: '%PHONE_NUMBER%'})
90
+
91
+ # Run the new query
92
+ Close::AdvancedFilter.run('find_leads_by_phone_number', {phone_number: '555-555-5555'})
93
+ ```
94
+
95
+ If you think you have a common query or one that would be useful to others, please open an issue with a new query and I will add it to the gem. Or you can submit a PR with the JSON for the query added to the repo.
96
+
73
97
  ### Leads
74
98
  [Close API Docs](https://developer.close.com/resources/leads/)
75
99
 
data/close-0.1.0.gem ADDED
Binary file
data/close-0.1.1.gem ADDED
Binary file
@@ -0,0 +1,60 @@
1
+ {
2
+ "limit": null,
3
+ "query": {
4
+ "negate": false,
5
+ "queries": [
6
+ {
7
+ "negate": false,
8
+ "object_type": "lead",
9
+ "type": "object_type"
10
+ },
11
+ {
12
+ "negate": false,
13
+ "queries": [
14
+ {
15
+ "negate": false,
16
+ "related_object_type": "contact",
17
+ "related_query": {
18
+ "negate": false,
19
+ "queries": [
20
+ {
21
+ "negate": false,
22
+ "related_object_type": "contact_email",
23
+ "related_query": {
24
+ "negate": false,
25
+ "queries": [
26
+ {
27
+ "condition": {
28
+ "mode": "full_words",
29
+ "type": "text",
30
+ "value": "%EMAIL%"
31
+ },
32
+ "field": {
33
+ "field_name": "email",
34
+ "object_type": "contact_email",
35
+ "type": "regular_field"
36
+ },
37
+ "negate": false,
38
+ "type": "field_condition"
39
+ }
40
+ ],
41
+ "type": "and"
42
+ },
43
+ "this_object_type": "contact",
44
+ "type": "has_related"
45
+ }
46
+ ],
47
+ "type": "and"
48
+ },
49
+ "this_object_type": "lead",
50
+ "type": "has_related"
51
+ }
52
+ ],
53
+ "type": "and"
54
+ }
55
+ ],
56
+ "type": "and"
57
+ },
58
+ "results_limit": null,
59
+ "sort": []
60
+ }
data/lib/close/errors.rb CHANGED
@@ -3,4 +3,6 @@ module Close
3
3
  class InvalidRequestError < StandardError; end
4
4
  class AuthenticationError < StandardError; end
5
5
  class APIError < StandardError; end
6
+ class QueryNotFoundError < StandardError; end
7
+ class MissingParameterError < StandardError; end
6
8
  end
@@ -0,0 +1,99 @@
1
+ # This class attempts to abstract away the Advanced Filter API.
2
+ # It is very powerful and fast, but building the queries is very tedious.
3
+ # It allows to store preset queries as JSON for common queries that
4
+ # can be commited to the repo and validated. It also lets you
5
+ # define queries on the fly which can then be reused across the
6
+ # codebase without having to copy and paste the query all the time.
7
+ module Close
8
+ class Filter
9
+ extend APIOperations
10
+
11
+ @@queries = {}
12
+
13
+ # Executes a raw query against the Close API.
14
+ # @param [Hash] query The query to execute.
15
+ # @return [Array] An array of results.
16
+ def self.execute(query = {})
17
+ response = request(:post, 'api/v1/data/search/', query)
18
+ response['data']
19
+ end
20
+
21
+ # Executes a query by name.
22
+ # @param [String] name The name of the query to execute.
23
+ # @param [Hash] params The parameters to pass to the query.
24
+ # @return [Array] An array of results.
25
+ def self.run(name, params = {})
26
+ query_string = load_query_from_file(name)
27
+ expected_params = find_params(query_string)
28
+ preflight_params(params, expected_params)
29
+ parameterized_query = apply_params(query_string, params)
30
+ execute(parameterized_query)
31
+ end
32
+
33
+ # Loads a query from a file or from memory.
34
+ # @param [String] name The name of the query.
35
+ # @return [String] A stringified JSON query.
36
+ def self.load_query(name)
37
+ if @@queries[name.to_s]
38
+ @@queries[name.to_s]
39
+ else
40
+ load_query_from_file(name)
41
+ end
42
+ end
43
+
44
+ # This method is used to defined a query at run time.
45
+ # If a name collision occurs, the query will be overwritten.
46
+ # @param [String] name The name of the query.
47
+ # @param [Hash] query_body A hash with placeholders in keys.
48
+ # @return [Void]
49
+ def self.add_query(name, query_body)
50
+ @@queries[name.to_s] = query_body.to_json
51
+ end
52
+
53
+ # Applies the params to the query string.
54
+ # @param [String] query_string The stringified JSON query.
55
+ # @param [Hash] params The parameters to apply.
56
+ # @return [String] The stringified JSON query with the parameters applied.
57
+ def self.apply_params(query_string, params)
58
+ qs = query_string.dup
59
+ params.each do |key, value|
60
+ qs.gsub!(/%#{key.upcase}%/, value)
61
+ end
62
+ qs
63
+ end
64
+
65
+ # Check that all of the params are present in expected_params.
66
+ # @param [Hash] params The parameters to check.
67
+ # @param [Array] expected_params The expected parameters.
68
+ # @return [Void]
69
+ # @raise [Close::MissingParameterError] if a parameter is missing.
70
+ def self.preflight_params(params, expected_params)
71
+ expected_params.each do |param|
72
+ if !params.transform_keys(&:to_s).has_key?(param.to_s)
73
+ raise Close::MissingParameterError, "Missing parameter: #{param}"
74
+ end
75
+ end
76
+ end
77
+
78
+ # Loads a predefined query from a file.
79
+ # @param [String] name The name of the query.
80
+ # @return [String] A stringified JSON query.
81
+ # @raise [Close::QueryNotFoundError] if the file does not exist.
82
+ def self.load_query_from_file(name)
83
+ begin
84
+ file = File.read("lib/close/data/filters/#{name}.json")
85
+ rescue Errno::ENOENT
86
+ raise Close::QueryNotFoundError.new("Query #{name} not found.")
87
+ end
88
+ end
89
+
90
+ # Scans a string a returns the parameters it will expect
91
+ # when executed.
92
+ # @param [String] str The string to scan.
93
+ # @return [Array] An array of parameters.
94
+ def self.find_params(str)
95
+ str.scan(/%[A-Z]+(?:_[A-Z]+)*%/).map{ |x| x[1..-2].downcase }.uniq
96
+ end
97
+
98
+ end
99
+ end
data/lib/close/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Close
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
data/lib/close.rb CHANGED
@@ -5,6 +5,7 @@ require "faraday"
5
5
  require_relative "close/close_object"
6
6
  require_relative "close/api_operations"
7
7
  require_relative "close/api_resource"
8
+ require_relative "close/filter"
8
9
  require_relative "close/resources"
9
10
  require_relative "close/errors"
10
11
  require_relative "close/version"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: close
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - JoyNerd LLC
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-18 00:00:00.000000000 Z
11
+ date: 2022-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ostruct
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 2.0.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 2.0.0
41
41
  description: A ruby wrapper for the close.com API that offers caching.
42
42
  email:
43
43
  - developers@joynerd.io
@@ -54,11 +54,15 @@ files:
54
54
  - LICENSE.txt
55
55
  - README.md
56
56
  - Rakefile
57
+ - close-0.1.0.gem
58
+ - close-0.1.1.gem
57
59
  - lib/close.rb
58
60
  - lib/close/api_operations.rb
59
61
  - lib/close/api_resource.rb
60
62
  - lib/close/close_object.rb
63
+ - lib/close/data/filters/find_lead_by_contact_email.json
61
64
  - lib/close/errors.rb
65
+ - lib/close/filter.rb
62
66
  - lib/close/resource/contact.rb
63
67
  - lib/close/resource/custom_activity_type.rb
64
68
  - lib/close/resource/lead.rb
@@ -89,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
93
  - !ruby/object:Gem::Version
90
94
  version: '0'
91
95
  requirements: []
92
- rubygems_version: 3.2.3
96
+ rubygems_version: 3.0.9
93
97
  signing_key:
94
98
  specification_version: 4
95
99
  summary: A ruby wrapper for the close.com API