gitlab-customer-support-operations_calendly 1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 50a88e913a2facddb2e5812af8ba37d18d776ddfeb2c2aae1ae6d167ac4c9a1e
4
+ data.tar.gz: 623303e804f2939c5684e034d123c269a0631aa54fb69aaa94ffeee7d4c1c2ca
5
+ SHA512:
6
+ metadata.gz: 42dad4e2bb5b17c11985f9f2802123e923fa63399207ed4e3a700d9e13a76416c0acb5dca1457f9ef7f177dad2a90d93c367ef9b4fe21a6834435431ffcf9f7d
7
+ data.tar.gz: 9fd7e013fb412ef6e5559f996731da75c61d9ac6c0d2387081141761200d93edb7ed4b8f6e6d83d91d4040abcf371ba5e2c2e7b1f767333243f7f1c0e655fc7b
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Defines the module SupportOps.
4
+ module SupportOps
5
+ # Defines the module Calendly
6
+ module Calendly
7
+ ##
8
+ # Defines the class Base within the module {SupportOps::Calendly}.
9
+ #
10
+ # @author Jason Colyer
11
+ # @since 1.0.0
12
+ class Base
13
+ class << self
14
+ def client
15
+ Configuration.config.client
16
+ end
17
+
18
+ def configure
19
+ yield Configuration.config
20
+ end
21
+
22
+ def define_attributes(*attrs)
23
+ @attributes = attrs
24
+ attrs.each do |attr|
25
+ attr_accessor attr
26
+ end
27
+ end
28
+
29
+ def attributes
30
+ @attributes || []
31
+ end
32
+
33
+ def readonly_attributes(*attrs)
34
+ return @readonly_attributes || [] if attrs.empty?
35
+
36
+ @readonly_attributes = attrs
37
+ end
38
+ end
39
+
40
+ def initialize(attributes = {}, client = nil)
41
+ @client = client
42
+ @original_attributes = {}
43
+ set_attributes(attributes)
44
+ store_original_attributes
45
+ end
46
+
47
+ def store_original_attributes
48
+ @original_attributes = {}
49
+ self.class.attributes.each do |attr|
50
+ @original_attributes[attr] = instance_variable_get("@#{attr}")
51
+ end
52
+ end
53
+
54
+ def uuid
55
+ uuid_record
56
+ end
57
+
58
+ def members
59
+ ensure_client_present!
60
+ members_record
61
+ end
62
+
63
+ def find
64
+ ensure_client_present!
65
+ set_attributes(get_record)
66
+ store_original_attributes
67
+ self
68
+ end
69
+
70
+ def find!
71
+ ensure_client_present!
72
+ attrs = get_record
73
+ if attrs == nil
74
+ raise "Unable to locate #{self.class.name.demodulize.singularize.downcase} '#{self.uri}'"
75
+ end
76
+ set_attributes(attrs)
77
+ store_original_attributes
78
+ self
79
+ end
80
+
81
+ def save!
82
+ ensure_client_present!
83
+ new_data = if id.nil?
84
+ create_record
85
+ else
86
+ update_record
87
+ end
88
+ new_data.each do |key, value|
89
+ self.instance_variable_set("@#{key}", value) if self.respond_to?("#{key}=")
90
+ end
91
+ store_original_attributes
92
+ self
93
+ end
94
+
95
+ def delete!
96
+ ensure_client_present!
97
+ delete_record
98
+ end
99
+
100
+ def client=(new_client)
101
+ @client = new_client
102
+ end
103
+
104
+ protected
105
+
106
+ attr_reader :attributes, :original_attributes
107
+
108
+ def set_attributes(attributes)
109
+ return unless attributes
110
+
111
+ attrs = attributes.transform_keys(&:to_sym)
112
+
113
+ self.class.attributes.each do |attr|
114
+ instance_variable_set("@#{attr}", attrs[attr])
115
+ end
116
+ end
117
+
118
+ def attributes_for_save
119
+ if send(:url) == nil
120
+ self.class.attributes
121
+ .reject { |attr| self.class.readonly_attributes.include?(attr) }
122
+ .each_with_object({}) do |attr, hash|
123
+ hash[attr] = send(attr)
124
+ end
125
+ else
126
+ self.class.attributes
127
+ .reject { |attr| self.class.readonly_attributes.include?(attr) }
128
+ .each_with_object({}) do |attr, hash|
129
+ current_value = send(attr)
130
+ original_value = @original_attributes[attr]
131
+
132
+ hash[attr] = current_value if attr == :url
133
+ if original_value != current_value
134
+ hash[attr] = current_value
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ def client
141
+ @client ||= self.class.client
142
+ end
143
+
144
+ def ensure_client_present!
145
+ raise 'No client configured. Use SupportOps::Calendly.configure to set up the client.' unless client
146
+ end
147
+
148
+ def uuid_record
149
+ raise NotImplementedError
150
+ end
151
+
152
+ def get_record(**args)
153
+ raise NotImplementedError
154
+ end
155
+
156
+ def create_record
157
+ raise NotImplementedError
158
+ end
159
+
160
+ def update_record
161
+ raise NotImplementedError
162
+ end
163
+
164
+ def members_record
165
+ raise NotImplementedError
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Defines the module SupportOps.
4
+ module SupportOps
5
+ # Defines the module Calendly
6
+ module Calendly
7
+ ##
8
+ # Defines the class Client within the module {SupportOps::Calendly}.
9
+ #
10
+ # @author Jason Colyer
11
+ # @since 1.0.0
12
+ class Client
13
+ class Error < StandardError; end
14
+ class RequestError < Error; end
15
+ class ResourceNotFound < Error; end
16
+
17
+ attr_reader :connection
18
+
19
+ def initialize(config = SupportOps::Calendly::Configuration.new)
20
+ if config[:token].nil?
21
+ raise 'No authentication token provided'
22
+ end
23
+ @connection = generate_connection(config)
24
+ end
25
+
26
+ def retry_options(config)
27
+ {
28
+ max: config[:retry_max],
29
+ interval: config[:retry_interval],
30
+ interval_randomness: config[:retry_randomness],
31
+ backoff_factor: config[:retry_backoff],
32
+ exceptions: config[:retry_exceptions]
33
+ }
34
+ end
35
+
36
+ def generate_connection(config)
37
+ Faraday.new('https://api.calendly.com') do |c|
38
+ c.request :retry, retry_options(config)
39
+ c.adapter Faraday.default_adapter
40
+ c.headers['Content-Type'] = 'application/json'
41
+ c.headers['Authorization'] = "Bearer #{config[:token]}"
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Defines the module SupportOps.
4
+ module SupportOps
5
+ # Defines the module Calendly
6
+ module Calendly
7
+ ##
8
+ # Defines the module Configuration within the module {SupportOps::Calendly}.
9
+ #
10
+ # @author Jason Colyer
11
+ # @since 1.0.0
12
+ module Configuration
13
+ ##
14
+ # Setup a Calendly client configuration
15
+ #
16
+ # @author Jason Colyer
17
+ # @since 1.0.0
18
+ # @overload configure(key: value)
19
+ # @param retry_backoff [Integer] See {Config#retry_backoff}
20
+ # @param retry_exceptions [Array] See {Config#retry_exceptions}
21
+ # @param retry_interval [Integer] See {Config#retry_interval}
22
+ # @param retry_max [Integer] See {Config#retry_max}
23
+ # @param retry_randomness [Integer] See {Config#retry_randomness}
24
+ # @param token [String] See {Config#token}
25
+ # @example
26
+ # require 'support_ops_calendly'
27
+ #
28
+ # SupportOps::Calendly::Configuration.configure do |config|
29
+ # config.token = 'abc123'
30
+ # end
31
+ def self.configure
32
+ yield config
33
+ end
34
+
35
+ def self.config
36
+ @config ||= Config.new
37
+ end
38
+
39
+ def self.reset!
40
+ @config = Config.new
41
+ end
42
+
43
+ ##
44
+ # Defined the class Config within the module {SupportOps::Calendly::Configuration}
45
+ #
46
+ # @author Jason Colyer
47
+ # @since 1.0.0
48
+ # @attr [Integer] retry_backoff multiplier applied to the retry_interval after each retry attempt, causing exponential backoff. Defaults to 2
49
+ # @attr [Array] retry_exceptions Specifies which types of exceptions or errors should trigger the retry mechanism.
50
+ # @attr [Integer] retry_interval The base time interval (typically in seconds or milliseconds) between retry attempts. Defaults to 1
51
+ # @attr [Integer] retry_max The maximum number of retry attempts that will be made when an operation fails. Defaults to 5
52
+ # @attr [Float] retry_randomness Adds a random element to the retry interval to prevent "thundering herd" problems where many systems retry simultaneously. Defaults to 0.5
53
+ # @attr [String] token The token to use for authentication
54
+ class Config
55
+ attr_accessor :token, :retry_max, :retry_interval, :retry_randomness,
56
+ :retry_backoff, :retry_exceptions,
57
+
58
+ def initialize
59
+ @retry_backoff = 2
60
+ @retry_exceptions = Faraday::Retry::Middleware::DEFAULT_EXCEPTIONS + [Faraday::ConnectionFailed]
61
+ @retry_interval = 1
62
+ @retry_max = 5
63
+ @retry_randomness = 0.5
64
+ end
65
+
66
+ def client
67
+ @client ||= Client.new(
68
+ retry_max: retry_max,
69
+ retry_interval: retry_interval,
70
+ retry_randomness: retry_randomness,
71
+ retry_backoff: retry_backoff,
72
+ retry_exceptions: retry_exceptions,
73
+ token: token
74
+ )
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Defines the module SupportOps.
4
+ module SupportOps
5
+ # Defines the module Calendly
6
+ module Calendly
7
+ ##
8
+ # Defines the module Groups within the module {SupportOps::Calendly}.
9
+ #
10
+ # @author Jason Colyer
11
+ # @since 1.0.0
12
+ # @attr [String] created_at The moment when the Group record was created
13
+ # @attr [Integer] member_count The number of members in a group
14
+ # @attr [String] name The Group name (in human-readable format)
15
+ # @attr [String] organization A unique reference to the associated Organization object
16
+ # @attr [String] updated_at The moment when the Group record was last updated
17
+ # @attr [String] uri Canonical reference (unique identifier) for the Group resource
18
+ class Groups < SupportOps::Calendly::Base
19
+ # @!parse
20
+ # # Returns the UUID of a group
21
+ # #
22
+ # # @author Jason Colyer
23
+ # # @since 1.0.0
24
+ # # @return [String] The UUID
25
+ # # @note This is inherited from {SupportOps::Calendly::Base#uuid}
26
+ # # @example
27
+ # # require 'support_ops_calendly'
28
+ # #
29
+ # # SupportOps::Calendly::Configuration.configure do |config|
30
+ # # config.token = 'abc123'
31
+ # # end
32
+ # #
33
+ # # group = SupportOps::Calendly::Groups.get!('EEEEEEEEEEEEEEEE')
34
+ # # pp group.uuid
35
+ # # #=> "BBBBBBBBBBBBBBBB"
36
+ # def uuid; end
37
+ define_attributes :created_at, :member_count, :name, :organization,
38
+ :updated_at, :uri
39
+ readonly_attributes :created_at, :member_count, :name, :organization,
40
+ :updated_at, :uri
41
+
42
+ ##
43
+ # Returns a list of groups
44
+ #
45
+ # @author Jason Colyer
46
+ # @since 1.0.0
47
+ # @overload list(key: value)
48
+ # @param organization [String required] The given organization URI that
49
+ # owns the subscriptions being returned
50
+ # @see
51
+ # https://developer.calendly.com/api-docs/6rb6dtdln74sy-list-groups
52
+ # Calendly API > Groups > List Groups
53
+ # @example
54
+ # require 'support_ops_calendly'
55
+ #
56
+ # SupportOps::Calendly::Configuration.configure do |config|
57
+ # config.token = 'abc123'
58
+ # end
59
+ #
60
+ # groups = SupportOps::Calendly::Groups.list(
61
+ # organization: 'https://api.calendly.com/organizations/BBBBBBBBBBBBBBBB',
62
+ # )
63
+ # pp groups.first.uri
64
+ # #=> "https://api.calendly.com/webhook_subscriptions/FFFFFFFFFFFFFFFF"
65
+ # pp groups.count
66
+ # #=> 2
67
+ def self.list(**args)
68
+ args[:organization] = nil unless args[:organization]
69
+ raise 'You must provide an organization URI' if args[:organization].nil?
70
+
71
+ array = []
72
+ data = {
73
+ count: 100,
74
+ organization: args[:organization]
75
+ }
76
+ loop do
77
+ response = client.connection.get('groups', data)
78
+ body = Oj.load(response.body)
79
+ array += body['collection'].map { |g| Groups.new(g) }
80
+ break if body['pagination']['next_page_token'].nil?
81
+
82
+ data['page_token'] = body['pagination']['next_page_token']
83
+ end
84
+ array
85
+ end
86
+
87
+ ##
88
+ # Get a specified Webhook Subscription
89
+ #
90
+ # @author Jason Colyer
91
+ # @since 1.0.0
92
+ # @see
93
+ # https://developer.calendly.com/api-docs/4d800dc2cb119-get-webhook-subscription
94
+ # Calendly API > Groups > Get Group
95
+ # @example
96
+ # require 'support_ops_calendly'
97
+ #
98
+ # SupportOps::Calendly::Configuration.configure do |config|
99
+ # config.token = 'abc123'
100
+ # end
101
+ #
102
+ # groups = SupportOps::Calendly::Groups.get('FFFFFFFFFFFFFFFF')
103
+ # pp group.uri
104
+ # #=> "https://api.calendly.com/webhook_subscriptions/FFFFFFFFFFFFFFFF"
105
+ def self.get(object)
106
+ if object.is_a? Groups
107
+ Groups.new(uri: uri).find
108
+ else
109
+ Groups.new(uri: object).find
110
+ end
111
+ end
112
+
113
+ ##
114
+ # Get a specified Webhook Subscription
115
+ #
116
+ # @author Jason Colyer
117
+ # @since 1.0.0
118
+ # @see
119
+ # https://developer.calendly.com/api-docs/4d800dc2cb119-get-webhook-subscription
120
+ # Calendly API > Groups > Get Group
121
+ # @example
122
+ # require 'support_ops_calendly'
123
+ #
124
+ # SupportOps::Calendly::Configuration.configure do |config|
125
+ # config.token = 'abc123'
126
+ # end
127
+ #
128
+ # groups = SupportOps::Calendly::Groups.get!('FFFFFFFFFFFFFFFF')
129
+ # pp group.uri
130
+ # #=> "https://api.calendly.com/webhook_subscriptions/FFFFFFFFFFFFFFFF"
131
+ def self.get!(object)
132
+ if object.is_a? Groups
133
+ Groups.new(uri: uri).find!
134
+ else
135
+ Groups.new(uri: object).find!
136
+ end
137
+ end
138
+
139
+ private
140
+
141
+ ##
142
+ # @private
143
+ def get_record
144
+ response = self.client.connection.get("groups/#{self.uuid}")
145
+ return nil if response.status != 200
146
+
147
+ Oj.load(response.body)['resource']
148
+ end
149
+
150
+ ##
151
+ # @private
152
+ def uuid_record
153
+ (uri =~ /^https/ ? uri.split('/').last : uri)
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,216 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Defines the module SupportOps.
4
+ module SupportOps
5
+ # Defines the module Calendly
6
+ module Calendly
7
+ ##
8
+ # Defines the module Organizations within the module {SupportOps::Calendly}.
9
+ #
10
+ # @author Jason Colyer
11
+ # @since 1.0.0
12
+ # @attr [String] created_at The moment when the membership record was created (e.g. "2020-01-02T03:04:05.678123Z")
13
+ # @attr [String] organization A unique reference to the organization
14
+ # @attr [String] role The user's role in the organization
15
+ # @attr [String] updated_at The moment when the membership record was last updated (e.g. "2020-01-02T03:04:05.678123Z")
16
+ # @attr [String] uri Canonical reference (unique identifier) for the membership
17
+ # @attr [Object] user An instance of {SupportOps::Calendly::Users}
18
+ class OrganizationMemberships < SupportOps::Calendly::Base
19
+ # @!parse
20
+ # # Removes a membership from an organization
21
+ # #
22
+ # # @author Jason Colyer
23
+ # # @since 1.0.0
24
+ # # @see
25
+ # # https://developer.calendly.com/api-docs/269e89d9f559f-remove-user-from-organization
26
+ # # Calendly API > Organizations > Remove User from Organization
27
+ # # @note This is inherited from {SupportOps::Calendly::Base#delete!}
28
+ # # @example
29
+ # # require 'support_ops_calendly'
30
+ # #
31
+ # # SupportOps::Calendly::Configuration.configure do |config|
32
+ # # config.token = 'abc123'
33
+ # # end
34
+ # #
35
+ # # org = SupportOps::Calendly::Organizations.current
36
+ # # members = SupportOps::Calendly::OrganizationMemberships.list('BBBBBBBBBBBBBBBB')
37
+ # # pp members.last.delete!
38
+ # # #=> "CCCCCCCCCCCCCCCC"
39
+ # def delete!; end
40
+ # @!parse
41
+ # # Returns the UUID of an organization membership
42
+ # #
43
+ # # @author Jason Colyer
44
+ # # @since 1.0.0
45
+ # # @return [String] The UUID
46
+ # # @note This is inherited from {SupportOps::Calendly::Base#uuid}
47
+ # # @example
48
+ # # require 'support_ops_calendly'
49
+ # #
50
+ # # SupportOps::Calendly::Configuration.configure do |config|
51
+ # # config.token = 'abc123'
52
+ # # end
53
+ # #
54
+ # # org = SupportOps::Calendly::Organizations.current
55
+ # # members = SupportOps::Calendly::OrganizationMemberships.list('BBBBBBBBBBBBBBBB')
56
+ # # pp members.first.uuid
57
+ # # #=> "CCCCCCCCCCCCCCCC"
58
+ # def uuid; end
59
+ define_attributes :created_at, :organization, :role, :updated_at, :uri,
60
+ :user
61
+ readonly_attributes :created_at, :organization, :role, :updated_at, :uri,
62
+ :user
63
+
64
+ ##
65
+ # Returns a list of Organization Memberships for a specified Organization
66
+ #
67
+ # @author Jason Colyer
68
+ # @since 1.0.0
69
+ # @see
70
+ # https://developer.calendly.com/api-docs/eaed2e61a6bc3-list-organization-memberships
71
+ # Calendly API > Organizations > List ORganization Memberships
72
+ # @example
73
+ # require 'support_ops_calendly'
74
+ #
75
+ # SupportOps::Calendly::Configuration.configure do |config|
76
+ # config.token = 'abc123'
77
+ # end
78
+ #
79
+ # org = SupportOps::Calendly::Organizations.get!('BBBBBBBBBBBBBBBB')
80
+ # members = SupportOps::Calendly::OrganizationMemberships(org)
81
+ # pp members.count
82
+ # # => 27
83
+ # pp members.first.user.uuid
84
+ # # => "AAAAAAAAAAAAAAAA"
85
+ # @example
86
+ # require 'support_ops_calendly'
87
+ #
88
+ # SupportOps::Calendly::Configuration.configure do |config|
89
+ # config.token = 'abc123'
90
+ # end
91
+ #
92
+ # members = SupportOps::Calendly::OrganizationMemberships('https://api.calendly.com/organizations/BBBBBBBBBBBBBBBB')
93
+ # pp members.count
94
+ # # => 27
95
+ # pp members.first.user.uuid
96
+ # # => "AAAAAAAAAAAAAAAA"
97
+ # @example
98
+ # require 'support_ops_calendly'
99
+ #
100
+ # SupportOps::Calendly::Configuration.configure do |config|
101
+ # config.token = 'abc123'
102
+ # end
103
+ #
104
+ # members = SupportOps::Calendly::OrganizationMemberships('BBBBBBBBBBBBBBBB')
105
+ # pp members.count
106
+ # # => 27
107
+ # pp members.first.user.uuid
108
+ # # => "AAAAAAAAAAAAAAAA"
109
+ def self.list(object)
110
+ id = if object.is_a? Organizations
111
+ object.uri
112
+ elsif object =~ /^https/
113
+ object
114
+ else
115
+ "https://api.calendly.com/organizations/#{object}"
116
+ end
117
+ data = { organization: id, count: 100 }
118
+ array = []
119
+ loop do
120
+ response = client.connection.get('organization_memberships', data)
121
+ body = Oj.load(response.body)
122
+ body['collection'].each_with_index do |member, index|
123
+ body['collection'][index]['user'] = Users.new(member['user'])
124
+ end
125
+ array += body['collection'].map { |c| OrganizationMemberships.new(c) }
126
+ break if body['pagination']['next_page_token'].nil?
127
+
128
+ data = { organization: id, count: 100, page_token: body['pagination']['next_page_token'] }
129
+ end
130
+ array
131
+ end
132
+
133
+ ##
134
+ # Returns information about a specified Organization Membership
135
+ #
136
+ # @author Jason Colyer
137
+ # @since 1.0.0
138
+ # @see
139
+ # https://developer.calendly.com/api-docs/8c3baa79a5883-get-organization-membership
140
+ # Calendly API > Organizations > Get Organization Membership
141
+ # @example
142
+ # require 'support_ops_calendly'
143
+ #
144
+ # SupportOps::Calendly::Configuration.configure do |config|
145
+ # config.token = 'abc123'
146
+ # end
147
+ #
148
+ # member = SupportOps::Calendly::OrganizationMemberships.get('CCCCCCCCCCCCCCCC')
149
+ # pp member.user.uuid
150
+ # # => "AAAAAAAAAAAAAAAA"
151
+ def self.get(object)
152
+ if object.is_a? OrganizationMemberships
153
+ OrganizationMemberships.new(uri: uri).find
154
+ else
155
+ OrganizationMemberships.new(uri: object).find
156
+ end
157
+ end
158
+
159
+ ##
160
+ # Returns information about a specified Organization Membership
161
+ #
162
+ # @author Jason Colyer
163
+ # @since 1.0.0
164
+ # @see
165
+ # https://developer.calendly.com/api-docs/8c3baa79a5883-get-organization-membership
166
+ # Calendly API > Organizations > Get Organization Membership
167
+ # @example
168
+ # require 'support_ops_calendly'
169
+ #
170
+ # SupportOps::Calendly::Configuration.configure do |config|
171
+ # config.token = 'abc123'
172
+ # end
173
+ #
174
+ # member = SupportOps::Calendly::OrganizationMemberships.get!('CCCCCCCCCCCCCCCC')
175
+ # pp member.user.uuid
176
+ # # => "AAAAAAAAAAAAAAAA"
177
+ def self.get!(object)
178
+ if object.is_a? OrganizationMemberships
179
+ OrganizationMemberships.new(uri: uri).find!
180
+ else
181
+ OrganizationMemberships.new(uri: object).find!
182
+ end
183
+ end
184
+
185
+ private
186
+
187
+ ##
188
+ # @private
189
+ def uuid_record
190
+ (uri =~ /^https/ ? uri.split('/').last : uri)
191
+ end
192
+
193
+ ##
194
+ # @private
195
+ def get_record
196
+ response = self.client.connection.get("organization_memberships/#{uuid}")
197
+ return nil if response.status != 200
198
+
199
+ body = Oj.load(response.body)['resource']
200
+ body['user'] = Users.new(body['user'])
201
+ body
202
+ end
203
+
204
+ ##
205
+ # @private
206
+ def delete_record
207
+ response = self.client.connection.delete("organization_memberships/#{self.uuid}")
208
+ body = Oj.load(response.body)
209
+ raise "Failed to remove user #{self.user.email} => #{body}" unless response.status == 204
210
+
211
+ true
212
+ end
213
+ end
214
+ end
215
+ end
216
+