cirro-ruby-client 1.6.0 → 2.0.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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +77 -5
  3. data/.gitignore +5 -0
  4. data/.rubocop.yml +28 -11
  5. data/CODE_OF_CONDUCT.md +1 -1
  6. data/Gemfile.lock +16 -15
  7. data/README.md +353 -0
  8. data/bin/console +1 -0
  9. data/cirro-ruby-client.gemspec +1 -0
  10. data/lib/cirro_io/client/base.rb +20 -0
  11. data/lib/cirro_io/client/gig.rb +0 -2
  12. data/lib/cirro_io/client/gig_invitation.rb +1 -0
  13. data/lib/cirro_io/client/gig_task.rb +1 -0
  14. data/lib/cirro_io/client/gig_time_activity.rb +1 -0
  15. data/lib/cirro_io/client/version.rb +1 -1
  16. data/lib/cirro_io_v2/client.rb +106 -0
  17. data/lib/cirro_io_v2/errors/http_error.rb +17 -0
  18. data/lib/cirro_io_v2/errors/response_not_json_error.rb +17 -0
  19. data/lib/cirro_io_v2/request_clients/base.rb +21 -0
  20. data/lib/cirro_io_v2/request_clients/jwt.rb +41 -0
  21. data/lib/cirro_io_v2/resources/base.rb +21 -0
  22. data/lib/cirro_io_v2/resources/gig.rb +10 -0
  23. data/lib/cirro_io_v2/resources/gig_ivitation.rb +18 -0
  24. data/lib/cirro_io_v2/resources/notification_broadcast.rb +13 -0
  25. data/lib/cirro_io_v2/resources/notification_configuration.rb +13 -0
  26. data/lib/cirro_io_v2/resources/notification_layout.rb +27 -0
  27. data/lib/cirro_io_v2/resources/notification_layout_template.rb +18 -0
  28. data/lib/cirro_io_v2/resources/notification_locale.rb +18 -0
  29. data/lib/cirro_io_v2/resources/notification_template.rb +25 -0
  30. data/lib/cirro_io_v2/resources/notification_topic.rb +17 -0
  31. data/lib/cirro_io_v2/resources/notification_topic_preference.rb +17 -0
  32. data/lib/cirro_io_v2/resources/user.rb +15 -0
  33. data/lib/cirro_io_v2/responses/base.rb +32 -0
  34. data/lib/cirro_io_v2/responses/responses.rb +101 -0
  35. metadata +36 -3
@@ -8,7 +8,6 @@ module CirroIO
8
8
  has_many :gig_results
9
9
  has_many :gig_time_activities
10
10
 
11
- # rubocop:disable Metrics/AbcSize
12
11
  def bulk_create_with(worker_filter, gig_tasks)
13
12
  payload = { data: { attributes: attributes, relationships: {} } }
14
13
  payload[:data][:relationships][:gig_tasks] = gig_tasks.map(&:attributes)
@@ -35,7 +34,6 @@ module CirroIO
35
34
 
36
35
  self.class.parser.parse(self.class, response).first
37
36
  end
38
- # rubocop:enable Metrics/AbcSize
39
37
  end
40
38
  end
41
39
  end
@@ -4,6 +4,7 @@ module CirroIO
4
4
  include CirroIO::Client::BulkActionHelper
5
5
 
6
6
  has_one :gig
7
+ has_one :app_worker
7
8
 
8
9
  def bulk_create_with(worker_filter, auto_accept: false)
9
10
  payload = { data: { attributes: attributes.merge(worker_filter: worker_filter.attributes, auto_accept: auto_accept) } }
@@ -1,6 +1,7 @@
1
1
  module CirroIO
2
2
  module Client
3
3
  class GigTask < Base
4
+ has_one :gig
4
5
  end
5
6
  end
6
7
  end
@@ -1,6 +1,7 @@
1
1
  module CirroIO
2
2
  module Client
3
3
  class GigTimeActivity < Base
4
+ has_one :gig
4
5
  has_one :app_worker
5
6
  end
6
7
  end
@@ -1,7 +1,7 @@
1
1
  # rubocop:disable Style/MutableConstant
2
2
  module CirroIO
3
3
  module Client
4
- VERSION = '1.6.0'
4
+ VERSION = '2.0.0'
5
5
  end
6
6
  end
7
7
  # rubocop:enable Style/MutableConstant
@@ -0,0 +1,106 @@
1
+ require 'cirro_io/client/version'
2
+ require 'cirro_io_v2/errors/http_error'
3
+ require 'cirro_io_v2/errors/response_not_json_error'
4
+
5
+ require 'cirro_io_v2/request_clients/base'
6
+ require 'cirro_io_v2/request_clients/jwt'
7
+
8
+ require 'cirro_io_v2/resources/base'
9
+ require 'cirro_io_v2/resources/gig'
10
+ require 'cirro_io_v2/resources/gig_ivitation'
11
+ require 'cirro_io_v2/resources/user'
12
+
13
+ require 'cirro_io_v2/responses/base'
14
+ require 'cirro_io_v2/responses/responses'
15
+
16
+ require 'cirro_io_v2/resources/notification_broadcast'
17
+ require 'cirro_io_v2/resources/notification_topic_preference'
18
+ require 'cirro_io_v2/resources/notification_topic'
19
+ require 'cirro_io_v2/resources/notification_configuration'
20
+ require 'cirro_io_v2/resources/notification_layout_template'
21
+ require 'cirro_io_v2/resources/notification_layout'
22
+ require 'cirro_io_v2/resources/notification_locale'
23
+ require 'cirro_io_v2/resources/notification_template'
24
+
25
+ module CirroIOV2
26
+ class Client
27
+ attr_accessor :request_client
28
+ attr_reader :options
29
+
30
+ DEFAULT_OPTIONS = {
31
+ site: 'https://api.cirro.io',
32
+ api_version: 'v2',
33
+ auth_type: :jwt,
34
+ }.freeze
35
+
36
+ DEFINED_OPTIONS = (DEFAULT_OPTIONS.keys + [:private_key, :private_key_path, :client_id]).freeze
37
+
38
+ def initialize(options = {})
39
+ @options = DEFAULT_OPTIONS.merge(options)
40
+
41
+ unknown_options = @options.keys.reject { |o| DEFINED_OPTIONS.include?(o) }
42
+ raise ArgumentError, "Unknown option(s) given: #{unknown_options}" unless unknown_options.empty?
43
+
44
+ # TODO: for now we only have jwt
45
+ case @options[:auth_type]
46
+ when :jwt
47
+ private_key = OpenSSL::PKey::RSA.new(@options[:private_key]) if @options[:private_key]
48
+ private_key = OpenSSL::PKey::RSA.new(File.read(@options[:private_key_path])) if @options[:private_key_path]
49
+ @request_client = RequestClients::Jwt.new(base_url: "#{@options[:site]}/#{@options[:api_version]}",
50
+ client_id: @options[:client_id],
51
+ private_key: private_key)
52
+ else
53
+ raise ArgumentError, 'Options: ":auth_type" must be ":jwt"'
54
+ end
55
+ end
56
+
57
+ # resources
58
+ # rubocop:disable Naming/MethodName
59
+
60
+ def User
61
+ Resources::User.new(self)
62
+ end
63
+
64
+ def GigInvitation
65
+ Resources::GigInvitation.new(self)
66
+ end
67
+
68
+ def Gig
69
+ Resources::Gig.new(self)
70
+ end
71
+
72
+ def NotificationBroadcast
73
+ Resources::NotificationBroadcast.new(self)
74
+ end
75
+
76
+ def NotificationChannelPreference
77
+ Resources::NotificationChannelPreference.new(self)
78
+ end
79
+
80
+ def NotificationChannel
81
+ Resources::NotificationChannel.new(self)
82
+ end
83
+
84
+ def NotificationConfiguration
85
+ Resources::NotificationConfiguration.new(self)
86
+ end
87
+
88
+ def NotificationLayoutTemplate
89
+ Resources::NotificationLayoutTemplate.new(self)
90
+ end
91
+
92
+ def NotificationLayout
93
+ Resources::NotificationLayout.new(self)
94
+ end
95
+
96
+ def NotificationLocale
97
+ Resources::NotificationLocale.new(self)
98
+ end
99
+
100
+ def NotificationTemplate
101
+ Resources::NotificationTemplate.new(self)
102
+ end
103
+
104
+ # rubocop:enable Naming/MethodName
105
+ end
106
+ end
@@ -0,0 +1,17 @@
1
+ require 'forwardable'
2
+
3
+ module CirroIOV2
4
+ module Errors
5
+ class HTTPError < StandardError
6
+ extend Forwardable
7
+
8
+ def_instance_delegators :@response, :code
9
+ attr_reader :response, :message
10
+
11
+ def initialize(response)
12
+ @response = response
13
+ @message = response.try(:message).presence || response.try(:body)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ require 'forwardable'
2
+
3
+ module CirroIOV2
4
+ module Errors
5
+ class ResponseNotJsonError < StandardError
6
+ extend Forwardable
7
+
8
+ def_instance_delegators :@faraday_error, :message, :full_message, :response
9
+
10
+ attr_reader :faraday_error
11
+
12
+ def initialize(faraday_error)
13
+ @faraday_error = faraday_error
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module CirroIOV2
2
+ module RequestClients
3
+ class Base
4
+ # Interface of all request clients. It returns the response if the request was successful (HTTP::2xx) and
5
+ # raises a CirroIOV2::HTTPError together with the response if the request was not successful
6
+
7
+ def request(*args, **named_args)
8
+ response = make_request(*args, **named_args)
9
+ raise Errors::HTTPError, response unless response.success?
10
+
11
+ response
12
+ rescue Faraday::ParsingError => e
13
+ raise Errors::ResponseNotJsonError, e
14
+ end
15
+
16
+ def make_request(*args)
17
+ raise NotImplementedError
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,41 @@
1
+ require 'jwt'
2
+ require 'openssl'
3
+
4
+ module CirroIOV2
5
+ module RequestClients
6
+ class Jwt < Base
7
+ attr_reader :base_url, :private_key, :client_id, :connection
8
+
9
+ def initialize(base_url:, private_key:, client_id:)
10
+ @base_url = base_url
11
+ @private_key = private_key
12
+ @client_id = client_id
13
+
14
+ @connection = Faraday.new(url: base_url) do |conn|
15
+ conn.request :json
16
+ conn.response :json
17
+ conn.adapter Faraday.default_adapter # testIO App is on older version of faraday and needs this line
18
+ end
19
+ end
20
+
21
+ def make_request(http_method, url, body: nil, params: nil, _headers: {})
22
+ @connection.send(http_method, url) do |request|
23
+ request.params = params if params
24
+ request.body = body.to_json if body
25
+ request.headers['Authorization'] = bearer_token
26
+ end
27
+ end
28
+
29
+ def bearer_token
30
+ payload = {
31
+ exp: Time.now.to_i + (10 * 60),
32
+ sub: client_id,
33
+ }
34
+
35
+ token = JWT.encode(payload, private_key, 'RS256')
36
+
37
+ "Bearer #{token}"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+
3
+ module CirroIOV2
4
+ module Resources
5
+ class Base
6
+ attr_reader :client
7
+
8
+ def initialize(client)
9
+ @client = client
10
+ end
11
+
12
+ def resource_root
13
+ self.class.name.demodulize.underscore.pluralize
14
+ end
15
+
16
+ def params_allowed?(params, allowed)
17
+ raise 'ParamNotAllowed' if (params.keys - allowed).any?
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ module CirroIOV2
2
+ module Resources
3
+ class Gig < Base
4
+ def create(params)
5
+ response = client.request_client.request(:post, resource_root, body: params)
6
+ Responses::GigResponse.new(response.body)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,18 @@
1
+ module CirroIOV2
2
+ module Resources
3
+ class GigInvitation < Base
4
+ ALLOWED_PARAMS = [:user_id, :gig_id, :limit, :before, :after, :status].freeze
5
+
6
+ def list(params = nil)
7
+ params_allowed?(params, ALLOWED_PARAMS) if params
8
+ response = client.request_client.request(:get, resource_root, params: params)
9
+ Responses::GigInvitationListResponse.new(response.body)
10
+ end
11
+
12
+ def accept(id)
13
+ response = client.request_client.request(:post, "#{resource_root}/#{id}/accept")
14
+ Responses::GigInvitationResponse.new(response.body)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ module CirroIOV2
2
+ module Resources
3
+ class NotificationBroadcast < Base
4
+ ALLOWED_PARAMS = [:payload, :recipients, :notification_channel_id].freeze
5
+
6
+ def create(params)
7
+ params_allowed?(params, ALLOWED_PARAMS)
8
+ response = client.request_client.request(:post, resource_root, body: params)
9
+ Responses::NotificationBroadcastResponse.new(response.body)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module CirroIOV2
2
+ module Resources
3
+ class NotificationConfiguration < Base
4
+ ALLOWED_PARAMS = [:locale, :limit, :before, :after].freeze
5
+
6
+ def list(params = nil)
7
+ params_allowed?(params, ALLOWED_PARAMS) if params
8
+ response = client.request_client.request(:get, resource_root, params: params)
9
+ Responses::NotificationConfigurationListResponse.new(response.body)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ module CirroIOV2
2
+ module Resources
3
+ class NotificationLayout < Base
4
+ CREATE_ALLOWED_PARAMS = [:name, :templates].freeze
5
+ UPDATE_ALLOWED_PARAMS = [:name].freeze
6
+ CREATE_TEMPLATE_ALLOWED_PARAMS = [:notification_configuration_id, :body].freeze
7
+
8
+ def create(params)
9
+ params_allowed?(params, CREATE_ALLOWED_PARAMS)
10
+ response = client.request_client.request(:post, resource_root, body: params)
11
+ Responses::NotificationLayoutResponse.new(response.body)
12
+ end
13
+
14
+ def update(id, params)
15
+ params_allowed?(params, UPDATE_ALLOWED_PARAMS)
16
+ response = client.request_client.request(:post, "#{resource_root}/#{id}", body: params)
17
+ Responses::NotificationLayoutResponse.new(response.body)
18
+ end
19
+
20
+ def create_template(id, params)
21
+ params_allowed?(params, CREATE_TEMPLATE_ALLOWED_PARAMS)
22
+ response = client.request_client.request(:post, "#{resource_root}/#{id}/notification_layout_templates", body: params)
23
+ Responses::NotificationLayoutTemplateResponse.new(response.body)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ module CirroIOV2
2
+ module Resources
3
+ class NotificationLayoutTemplate < Base
4
+ UPDATE_ALLOWED_PARAMS = [:notification_configuration_id, :body].freeze
5
+
6
+ def update(id, params)
7
+ params_allowed?(params, UPDATE_ALLOWED_PARAMS)
8
+ response = client.request_client.request(:post, "#{resource_root}/#{id}", body: params)
9
+ Responses::NotificationLayoutTemplateResponse.new(response.body)
10
+ end
11
+
12
+ def delete(id)
13
+ response = client.request_client.request(:delete, "#{resource_root}/#{id}")
14
+ Responses::NotificationLayoutTemplateDeleteResponse.new(response.body)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module CirroIOV2
2
+ module Resources
3
+ class NotificationLocale < Base
4
+ ALLOWED_PARAMS = [:locale].freeze
5
+
6
+ def create(params)
7
+ params_allowed?(params, ALLOWED_PARAMS)
8
+ response = client.request_client.request(:post, resource_root, body: params)
9
+ Responses::NotificationLocaleResponse.new(response.body)
10
+ end
11
+
12
+ def list
13
+ response = client.request_client.request(:get, resource_root)
14
+ Responses::NotificationLocaleListResponse.new(response.body)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ module CirroIOV2
2
+ module Resources
3
+ class NotificationTemplate < Base
4
+ LIST_ALLOWED_PARAMS = [:notification_configuration_id, :notification_channel_id, :limit, :before, :after].freeze
5
+ UPDATE_ALLOWED_PARAMS = [:subject, :body].freeze
6
+
7
+ def list(params = nil)
8
+ params_allowed?(params, LIST_ALLOWED_PARAMS) if params
9
+ response = client.request_client.request(:get, resource_root, params: params)
10
+ Responses::NotificationTemplateListResponse.new(response.body)
11
+ end
12
+
13
+ def update(id, params)
14
+ params_allowed?(params, UPDATE_ALLOWED_PARAMS)
15
+ response = client.request_client.request(:post, "#{resource_root}/#{id}", body: params)
16
+ Responses::NotificationTemplateResponse.new(response.body)
17
+ end
18
+
19
+ def delete(id)
20
+ response = client.request_client.request(:delete, "#{resource_root}/#{id}")
21
+ Responses::NotificationTemplateDeleteResponse.new(response.body)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,17 @@
1
+ module CirroIOV2
2
+ module Resources
3
+ class NotificationTopic < Base
4
+ ALLOWED_PARAMS = [:name, :notification_layout_id, :preferences, :templates].freeze
5
+
6
+ def resource_root
7
+ 'notification_channels'
8
+ end
9
+
10
+ def create(params)
11
+ params_allowed?(params, ALLOWED_PARAMS)
12
+ response = client.request_client.request(:post, resource_root, body: params)
13
+ Responses::NotificationChannelResponse.new(response.body)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module CirroIOV2
2
+ module Resources
3
+ class NotificationTopicPreference < Base
4
+ ALLOWED_PARAMS = [:user_id, :notification_channel_id, :limit, :before, :after].freeze
5
+
6
+ def resource_root
7
+ 'notification_channel_preferences'
8
+ end
9
+
10
+ def list(params = nil)
11
+ params_allowed?(params, ALLOWED_PARAMS) if params
12
+ response = client.request_client.request(:get, resource_root, params: params)
13
+ Responses::NotificationChannelPreferenceListResponse.new(response.body)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ module CirroIOV2
2
+ module Resources
3
+ class User < Base
4
+ def find(id)
5
+ response = client.request_client.request(:get, "#{resource_root}/#{id}")
6
+ CirroIOV2::Responses::UserResponse.new(response.body)
7
+ end
8
+
9
+ def notification_preferences(id, params)
10
+ response = client.request_client.request(:post, "#{resource_root}/#{id}/notification_preferences", body: params)
11
+ CirroIOV2::Responses::UserNotificationPreferenceResponse.new(response.body)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,32 @@
1
+ module CirroIOV2
2
+ module Responses
3
+ module Base
4
+ def initialize(body)
5
+ body = body.deep_symbolize_keys
6
+ if body[:object] == 'list'
7
+ list_item_class = self.class.name.gsub('List', '').constantize
8
+ values_hash = body.slice(*members.excluding(:data)).merge(
9
+ data: body[:data].map { |list_item| list_item_class.new(list_item) },
10
+ )
11
+ super(*members.map { |attr| values_hash[attr] })
12
+ elsif list_attribute(body)
13
+ values_hash = body.slice(*members.excluding(list_attribute(body))).merge(
14
+ list_attribute(body) => create_sub_resource(list_attribute(body), body[list_attribute(body)]),
15
+ )
16
+ super(*body.slice(*members).keys.map { |attr| values_hash[attr] })
17
+ else
18
+ super(*body.slice(*members).values)
19
+ end
20
+ end
21
+
22
+ def list_attribute(data)
23
+ data.keys.find { |key| data[key].is_a?(Hash) && data[key][:object] == 'list' }
24
+ end
25
+
26
+ def create_sub_resource(resource_name, body)
27
+ sub_resource_class = "CirroIOV2::Responses::#{self.class::NESTED_RESPONSES[resource_name]}".constantize
28
+ sub_resource_class.new(body)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,101 @@
1
+ module CirroIOV2
2
+ module Responses
3
+ LIST_RESPONSES = [
4
+ :GigTaskListResponse,
5
+ :GigInvitationListResponse,
6
+ :NotificationChannelPreferenceListResponse,
7
+ :NotificationLocaleListResponse,
8
+ :NotificationConfigurationListResponse,
9
+ :NotificationLayoutTemplateListResponse,
10
+ :NotificationChannelListResponse,
11
+ :NotificationTemplateListResponse,
12
+ ].freeze
13
+
14
+ UserResponse = Struct.new(:id, :object, :first_name, :last_name, :time_zone, :screen_name, :country_code, :epam, :worker) do
15
+ include Base
16
+ end
17
+
18
+ UserNotificationPreferenceResponse = Struct.new(:id, :object, :locale, :channels) do
19
+ self::NESTED_RESPONSES = { channels: :NotificationChannelListResponse }.freeze
20
+ include Base
21
+ end
22
+
23
+ GigResponse = Struct.new(:id,
24
+ :object,
25
+ :title,
26
+ :description,
27
+ :url,
28
+ :start_at,
29
+ :end_at,
30
+ :total_seats,
31
+ :invitation_mode,
32
+ :filter_query,
33
+ :tasks,
34
+ :notification_payload,
35
+ :epam_options) do
36
+ self::NESTED_RESPONSES = { tasks: :GigTaskListResponse }.freeze
37
+ include Base
38
+ end
39
+
40
+ GigTaskResponse = Struct.new(:id, :object, :title, :base_price) do
41
+ include Base
42
+ end
43
+
44
+ GigInvitationResponse = Struct.new(:id, :object, :status, :gig_id, :user_id) do
45
+ include Base
46
+ end
47
+
48
+ NotificationChannelPreferenceResponse = Struct.new(:id, :object, :preferences, :notification_channel_id, :user_id) do
49
+ self::NESTED_RESPONSES = { preferences: :NotificationChannelPreferenceListResponse }.freeze
50
+ include Base
51
+ end
52
+
53
+ NotificationLocaleResponse = Struct.new(:id, :object, :locale, :default, :configurations) do
54
+ self::NESTED_RESPONSES = { configurations: :NotificationConfigurationListResponse }.freeze
55
+ include Base
56
+ end
57
+
58
+ NotificationConfigurationResponse = Struct.new(:id, :object, :deliver_by, :format, :kind, :locale) do
59
+ include Base
60
+ end
61
+
62
+ NotificationLayoutResponse = Struct.new(:id, :object, :name, :templates) do
63
+ self::NESTED_RESPONSES = { templates: :NotificationLayoutTemplateListResponse }.freeze
64
+ include Base
65
+ end
66
+
67
+ NotificationLayoutTemplateResponse = Struct.new(:id, :notification_configuration_id, :notification_layout_id, :body) do
68
+ include Base
69
+ end
70
+
71
+ NotificationLayoutTemplateDeleteResponse = Struct.new(:id, :object, :deleted) do
72
+ include Base
73
+ end
74
+
75
+ NotificationChannelResponse = Struct.new(:id, :object, :name, :notification_layout_id, :preferences, :templates) do
76
+ self::NESTED_RESPONSES = { templates: :NotificationTemplateListResponse }.freeze
77
+ include Base
78
+ end
79
+
80
+ NotificationTemplateResponse = Struct.new(:id, :object, :notification_configuration_id, :notification_channel_id, :subject, :body) do
81
+ include Base
82
+ end
83
+
84
+ NotificationTemplateDeleteResponse = Struct.new(:id, :object, :deleted) do
85
+ include Base
86
+ end
87
+
88
+ NotificationBroadcastResponse = Struct.new(:id, :object, :payload, :recipients, :notification_channel_id) do
89
+ include Base
90
+ end
91
+
92
+ # cover the list responses
93
+ def self.const_missing(name)
94
+ return const_get(name) if const_defined? name
95
+ return unless LIST_RESPONSES.include? name
96
+
97
+ klass = Class.new(Struct.new(:object, :url, :has_more, :data)) { include Base }
98
+ const_set(name, klass)
99
+ end
100
+ end
101
+ end