cirro-ruby-client 1.6.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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