frederick_api 0.4.4 → 0.9

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
- SHA1:
3
- metadata.gz: 711d8e8257f97e7ad18803cca7b24e8e87a9f43e
4
- data.tar.gz: baf134c2da2e7da52cfeb7a75ccd5b90a18a2200
2
+ SHA256:
3
+ metadata.gz: af582661b851880a278f82844f06ec98910f639cf0292ec1249f1ed1127b0a27
4
+ data.tar.gz: 5740b928ced7a2d9f4964388dbd5e543cbb0827c571f562899ab3a651a030f43
5
5
  SHA512:
6
- metadata.gz: 294478020b031f49b7f5ae1a636977ff5301befb4892f44b9526ddec5037c2b2f4f6461a391e7661ed70db4cdf05177f696bb08c63f158c0d6f1ee4ba7855dff
7
- data.tar.gz: fbce1720a78066c1caeeb2e1da9dbf688f250eacea4fa407307a838d492ef898ff8791cbdd83c7cfe1d38462b5f456f1643acc8772063ca7163c5d8effb1df45
6
+ metadata.gz: dd740314950b62480828dc4878a603582edd4bf00c6bddc7e7a6b694707b90da52fd2e31ccdf226b86afeff09aeccd0a12d94b900f322a1e153a3e5a48ce9515
7
+ data.tar.gz: e535fb7f7655cbf975424497a333292d1dae97c9c8cb3f0621fac118f6e694d360dd355250f1ab91427144038c6a009392c37a0c47a64b4a9536b34a223a6582
data/README.md CHANGED
@@ -88,6 +88,21 @@ FrederickAPI::V2::Location.with_access_token(access_token) do
88
88
  end
89
89
  ```
90
90
 
91
+ ### Using Headers
92
+
93
+ `Resource.with_access_token` is extended to take headers in the method `Resource.with_access_token_and_headers`. This is useful when we need to pass the universal customer to services that accept it.
94
+
95
+ ```ruby
96
+ access_token = '9jsdo320fjfkfdksls30dfdcd919bcaa1b7804dbbebda0'
97
+ headers = { 'X-Universal-Customer': '{"source_platform":"mindbody","source_location_id":"1","source_customer_id":"77"}' }
98
+
99
+ FrederickAPI::V2::CommunicationTemplate.with_access_token_and_headers(access_token, headers) do
100
+ template = FrederickAPI::V2::CommunicationTemplate.create(template_attributes)
101
+
102
+ template.name
103
+ # => 'Name from Attrs'
104
+ end
105
+ ```
91
106
  ### Nested Resources
92
107
 
93
108
  Nested resources must be accessed using `where` to scope the request:
@@ -101,3 +116,14 @@ FrederickAPI::V2::Location.with_access_token(access_token) do
101
116
  # => [...]
102
117
  end
103
118
  ```
119
+ ### Background Jobs
120
+
121
+ FrederickAPI Gem handles asynchronous responses as suggested in
122
+ [JSONApi Recommendations](https://jsonapi.org/recommendations/#asynchronous-processing)
123
+ [Asynchronous Processing](https://jsonapi.org/recommendations/#asynchronous-processing).
124
+ Polling until the job is complete, fetching and returning the completed resource.
125
+
126
+ * A FrederickAPI::V2::Errors::BackgroundJobFailure exception is raised if the API returns
127
+ an error on an asyncronous job.
128
+ * A BackgroundJob Resource will be returned from the client in the case that a successful
129
+ job does not return a resource.
data/lib/frederick_api.rb CHANGED
@@ -12,17 +12,20 @@ require 'frederick_api/v2/helpers/has_many'
12
12
  require 'frederick_api/v2/helpers/paginator'
13
13
  require 'frederick_api/v2/helpers/query_builder'
14
14
  require 'frederick_api/v2/helpers/requestor'
15
+ require 'frederick_api/v2/helpers/backgroundable_parser'
15
16
  require 'frederick_api/v2/resource'
16
17
  require 'frederick_api/v2/public_resource'
17
18
 
18
19
  require 'frederick_api/v2/user'
19
20
  require 'frederick_api/v2/location'
21
+ require 'frederick_api/v2/background_job'
20
22
 
21
23
  # Public resources
22
24
  require 'frederick_api/v2/business_category'
23
25
 
24
26
  # Core resources
25
27
  require 'frederick_api/v2/automation'
28
+ require 'frederick_api/v2/automation_step'
26
29
  require 'frederick_api/v2/communication_content'
27
30
  require 'frederick_api/v2/contact'
28
31
  require 'frederick_api/v2/contact_property'
@@ -30,6 +33,9 @@ require 'frederick_api/v2/contact_list'
30
33
  require 'frederick_api/v2/contact_type'
31
34
  require 'frederick_api/v2/interaction'
32
35
  require 'frederick_api/v2/role'
36
+ require 'frederick_api/v2/campaign'
37
+ require 'frederick_api/v2/email_document'
38
+ require 'frederick_api/v2/communication_template'
33
39
 
34
40
  # Namespace for all Frederick API client methods/classes
35
41
  module FrederickAPI
@@ -5,6 +5,8 @@ module FrederickAPI
5
5
  # /v2/locations/:location_id/automations
6
6
  class Automation < Resource
7
7
  belongs_to :location
8
+ has_many :automation_steps
9
+
8
10
  self.read_only_attributes += [:location_id]
9
11
  end
10
12
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrederickAPI
4
+ module V2
5
+ # Resource for automation step
6
+ class AutomationStep < Resource
7
+ belongs_to :location
8
+ has_one :automation
9
+ has_one :previous_automation_step, class_name: 'FrederickAPI::V2::AutomationStep'
10
+
11
+ self.read_only_attributes += %i[location_id]
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrederickAPI
4
+ module V2
5
+ # V2 Frederick API async background job class for parsing
6
+ # background job responses coming from API.
7
+ class BackgroundJob < Resource
8
+ attr_accessor :response
9
+
10
+ def has_errors?
11
+ @attributes['status'] == 'error'
12
+ end
13
+
14
+ def retry_after
15
+ try_time = @response[:headers]['retry-after'].to_i
16
+ @retry_after ||= try_time > 1 ? try_time : 1
17
+ end
18
+
19
+ def response_code
20
+ @response_code ||= @response[:status]
21
+ end
22
+
23
+ def status
24
+ @attributes['status']
25
+ end
26
+
27
+ def errors
28
+ @attributes['messages']
29
+ end
30
+
31
+ def id
32
+ @attributes['id']
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrederickAPI
4
+ module V2
5
+ # V2 Campaign Resource
6
+ class Campaign < Resource
7
+ belongs_to :location
8
+
9
+ self.read_only_attributes += [:location_id]
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrederickAPI
4
+ module V2
5
+ # V2 CommunicationTemplate Resource
6
+ class CommunicationTemplate < Resource; end
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrederickAPI
4
+ module V2
5
+ # V2 Email Document Resource
6
+ class EmailDocument < Resource
7
+ belongs_to :location
8
+
9
+ self.read_only_attributes += [:location_id]
10
+ end
11
+ end
12
+ end
@@ -23,6 +23,10 @@ module FrederickAPI
23
23
  class BadRequest < Error; end
24
24
  class UnprocessableEntity < Error; end
25
25
 
26
+ # an exception class for when the server reports that a
27
+ # long running job has failed.
28
+ class BackgroundJobFailure < Error; end
29
+
26
30
  ERROR_CODES = {
27
31
  '400' => BadRequest,
28
32
  '422' => UnprocessableEntity
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrederickAPI
4
+ module V2
5
+ module Helpers
6
+ # Custom Parser for parsing BackgroundJob resources for FrederickAPI V2
7
+ class BackgroundableParser < ::JsonApiClient::Parsers::Parser
8
+ def self.parse(klass, response)
9
+ result_set = super(klass, response)
10
+ return result_set unless result_set&.first&.type == 'background_jobs'
11
+ result_set = super(::FrederickAPI::V2::BackgroundJob, response)
12
+ result_set&.first&.response = { headers: response.headers, status: response.status }
13
+ result_set
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -20,7 +20,7 @@ module FrederickAPI
20
20
  def query_builder(url)
21
21
  association_class.query_builder.new(
22
22
  association_class,
23
- association_class.requestor_class.new(association_class, url)
23
+ requestor: association_class.requestor_class.new(association_class, url)
24
24
  )
25
25
  end
26
26
 
@@ -9,9 +9,9 @@ module FrederickAPI
9
9
  class QueryBuilder < JsonApiClient::Query::Builder
10
10
  attr_reader :requestor
11
11
 
12
- def initialize(klass, requestor = nil)
13
- super(klass)
14
- @requestor = requestor || klass.requestor
12
+ def initialize(klass, opts = {})
13
+ super(klass, opts)
14
+ @requestor = opts[:requestor] || klass.requestor
15
15
  end
16
16
 
17
17
  def params
@@ -23,17 +23,6 @@ module FrederickAPI
23
23
  .merge(additional_params)
24
24
  end
25
25
 
26
- def find(args = {})
27
- case args
28
- when Hash
29
- where(args)
30
- else
31
- @primary_key = args
32
- end
33
-
34
- requestor.get(params)
35
- end
36
-
37
26
  def filter_params
38
27
  super_filter_params = super
39
28
 
@@ -65,6 +54,27 @@ module FrederickAPI
65
54
  { prefix => object }
66
55
  end
67
56
  end
57
+
58
+ protected
59
+
60
+ def _fetch
61
+ (requestor || klass.requestor).get(params)
62
+ end
63
+
64
+ private
65
+
66
+ def _new_scope(opts = {})
67
+ self.class.new(@klass,
68
+ requestor: requestor,
69
+ primary_key: opts.fetch(:primary_key, @primary_key),
70
+ pagination_params: @pagination_params.merge(opts.fetch(:pagination_params, {})),
71
+ path_params: @path_params.merge(opts.fetch(:path_params, {})),
72
+ additional_params: @additional_params.merge(opts.fetch(:additional_params, {})),
73
+ filters: @filters.merge(opts.fetch(:filters, {})),
74
+ includes: @includes + opts.fetch(:includes, []),
75
+ orders: @orders + opts.fetch(:orders, []),
76
+ fields: @fields + opts.fetch(:fields, []))
77
+ end
68
78
  end
69
79
  end
70
80
  end
@@ -7,6 +7,24 @@ module FrederickAPI
7
7
  class Requestor < JsonApiClient::Query::Requestor
8
8
  attr_reader :path
9
9
 
10
+ # For backward compatibility, preserve these JSON API client errors instead of raising
11
+ # FrederickAPI::Errors::Error
12
+ JSON_API_CLIENT_PASSTHROUGH_ERRORS = [
13
+ JsonApiClient::Errors::NotAuthorized,
14
+ JsonApiClient::Errors::AccessDenied,
15
+ JsonApiClient::Errors::NotFound,
16
+ JsonApiClient::Errors::Conflict,
17
+ JsonApiClient::Errors::ServerError,
18
+ JsonApiClient::Errors::UnexpectedStatus
19
+ ].freeze
20
+
21
+ # Paths that may have an unbounded query param length so we should always use a POST
22
+ # instead of a GET to get around AWS Cloudfront limitations
23
+ GET_VIA_POST_PATHS = [
24
+ %r{^.*locations\/[^\/]+\/contacts$},
25
+ %r{^.*locations\/[^\/]+\/interactions$}
26
+ ].map(&:freeze).freeze
27
+
10
28
  def initialize(klass, path = nil)
11
29
  @klass = klass
12
30
  @path = path
@@ -21,15 +39,49 @@ module FrederickAPI
21
39
  end
22
40
  end
23
41
 
42
+ def get(params = {})
43
+ path = resource_path(params)
44
+
45
+ params.delete(klass.primary_key)
46
+ if get_via_post_path?(path)
47
+ return request(:post, path, body: params.to_json, additional_headers: { 'X-Request-Method' => 'GET' })
48
+ end
49
+
50
+ request(:get, path, params: params)
51
+ end
52
+
53
+ def linked(path)
54
+ uri = URI.parse(path)
55
+ return super unless get_via_post_path?(uri.path)
56
+
57
+ path_without_params = "#{uri.scheme}://#{uri.host}#{uri.path}"
58
+ params = uri.query ? CGI.parse(uri.query).each_with_object({}) { |(k, v), h| h[k] = v[0] } : {}
59
+ request(:post, path_without_params, body: params.to_json, additional_headers: { 'X-Request-Method' => 'GET' })
60
+ end
61
+
24
62
  # Retry once on unhandled server errors
25
- def request(type, path, params)
26
- handle_errors(super)
27
- rescue JsonApiClient::Errors::ConnectionError, JsonApiClient::Errors::ServerError => ex
28
- raise ex if ex.is_a?(JsonApiClient::Errors::NotFound) || ex.is_a?(JsonApiClient::Errors::Conflict)
29
- handle_errors(super)
63
+ def request(type, path, params: nil, body: nil, additional_headers: {})
64
+ headers = klass.custom_headers.merge(additional_headers)
65
+ make_request = proc do
66
+ handle_background(handle_errors(make_request(type, path, params: params, body: body, headers: headers)))
67
+ end
68
+
69
+ begin
70
+ make_request.call
71
+ rescue JsonApiClient::Errors::ConnectionError, JsonApiClient::Errors::ServerError => ex
72
+ raise ex if ex.is_a?(JsonApiClient::Errors::NotFound) || ex.is_a?(JsonApiClient::Errors::Conflict)
73
+ make_request.call
74
+ end
30
75
  end
31
76
 
32
77
  private
78
+ def handle_background(response)
79
+ return response unless
80
+ (job = response&.first).is_a?(::FrederickAPI::V2::BackgroundJob) && job.status != 'complete'
81
+ raise FrederickAPI::V2::Errors::BackgroundJobFailure, job if job.has_errors?
82
+ sleep job.retry_after
83
+ linked(job.links.attributes['self'])
84
+ end
33
85
 
34
86
  def handle_errors(result)
35
87
  return result unless result.has_errors?
@@ -37,6 +89,25 @@ module FrederickAPI
37
89
  FrederickAPI::V2::Errors::Error
38
90
  raise error_klass, result
39
91
  end
92
+
93
+ def make_request(type, path, params:, body:, headers:)
94
+ faraday_response = connection.run(type, path, params: params, body: body, headers: headers)
95
+ return klass.parser.parse(klass, faraday_response) unless faraday_response.status == 303
96
+
97
+ linked(faraday_response.headers['location'])
98
+ rescue JsonApiClient::Errors::ClientError => e
99
+ handle_json_api_client_error(e)
100
+ end
101
+
102
+ def get_via_post_path?(path)
103
+ GET_VIA_POST_PATHS.any? { |r| r.match(path) }
104
+ end
105
+
106
+ def handle_json_api_client_error(error)
107
+ raise error if JSON_API_CLIENT_PASSTHROUGH_ERRORS.include?(error.class)
108
+
109
+ klass.parser.parse(klass, error.env.response)
110
+ end
40
111
  end
41
112
  end
42
113
  end
@@ -10,6 +10,7 @@ module FrederickAPI
10
10
  self.query_builder = FrederickAPI::V2::Helpers::QueryBuilder
11
11
  self.paginator = FrederickAPI::V2::Helpers::Paginator
12
12
  self.requestor_class = FrederickAPI::V2::Helpers::Requestor
13
+ self.parser = ::FrederickAPI::V2::Helpers::BackgroundableParser
13
14
 
14
15
  attr_accessor :custom_headers
15
16
 
@@ -35,7 +36,16 @@ module FrederickAPI
35
36
  end
36
37
 
37
38
  def self.with_access_token(token)
38
- with_headers(authorization: "Bearer #{token}") do
39
+ with_access_token_and_headers(token) do
40
+ yield
41
+ end
42
+ end
43
+
44
+ def self.with_access_token_and_headers(token, headers = {})
45
+ with_headers(
46
+ authorization: "Bearer #{token}",
47
+ **headers
48
+ ) do
39
49
  yield
40
50
  end
41
51
  end
@@ -5,6 +5,7 @@ module FrederickAPI
5
5
  # /v2/users
6
6
  class User < Resource
7
7
  has_many :roles, class_name: 'FrederickAPI::V2::Role'
8
+ has_many :permitted_locations, class_name: 'FrederickAPI::V2::Location'
8
9
  end
9
10
  end
10
11
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module FrederickAPI
4
4
  # Current gem version
5
- VERSION = '0.4.4'
5
+ VERSION = '0.9'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: frederick_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: '0.9'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Frederick Engineering
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-11 00:00:00.000000000 Z
11
+ date: 2021-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json_api_client
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.5.3
19
+ version: 1.17.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.5.3
26
+ version: 1.17.1
27
27
  description: Ruby client for the Frederick API
28
28
  email:
29
29
  - tech@hirefrederick.com
@@ -36,13 +36,19 @@ files:
36
36
  - lib/frederick_api.rb
37
37
  - lib/frederick_api/configuration.rb
38
38
  - lib/frederick_api/v2/automation.rb
39
+ - lib/frederick_api/v2/automation_step.rb
40
+ - lib/frederick_api/v2/background_job.rb
39
41
  - lib/frederick_api/v2/business_category.rb
42
+ - lib/frederick_api/v2/campaign.rb
40
43
  - lib/frederick_api/v2/communication_content.rb
44
+ - lib/frederick_api/v2/communication_template.rb
41
45
  - lib/frederick_api/v2/contact.rb
42
46
  - lib/frederick_api/v2/contact_list.rb
43
47
  - lib/frederick_api/v2/contact_property.rb
44
48
  - lib/frederick_api/v2/contact_type.rb
49
+ - lib/frederick_api/v2/email_document.rb
45
50
  - lib/frederick_api/v2/errors/errors.rb
51
+ - lib/frederick_api/v2/helpers/backgroundable_parser.rb
46
52
  - lib/frederick_api/v2/helpers/has_many.rb
47
53
  - lib/frederick_api/v2/helpers/paginator.rb
48
54
  - lib/frederick_api/v2/helpers/query_builder.rb
@@ -58,7 +64,7 @@ homepage: https://github.com/HireFrederick/frederick_api_gem
58
64
  licenses:
59
65
  - MIT
60
66
  metadata: {}
61
- post_install_message:
67
+ post_install_message:
62
68
  rdoc_options: []
63
69
  require_paths:
64
70
  - lib
@@ -73,9 +79,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
79
  - !ruby/object:Gem::Version
74
80
  version: '0'
75
81
  requirements: []
76
- rubyforge_project:
77
- rubygems_version: 2.6.14
78
- signing_key:
82
+ rubygems_version: 3.0.8
83
+ signing_key:
79
84
  specification_version: 4
80
85
  summary: Frederick API Client
81
86
  test_files: []