test-rc-sdk 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: f0ed544553943eef59bca4060e254a266591ca821c64e31e9d6b18f70c770aa6
4
+ data.tar.gz: b59c797191c98112301c069ed94850708c2a41868cade83fcafa9ae833b1fc71
5
+ SHA512:
6
+ metadata.gz: e5ea09c8f9b261383ba26ad46987a9ab653e09a550ee81d48bf316119d857060f9031633339b7b3f3b9985f05525912579650ed40ad28b51394f1bbe88493bbe
7
+ data.tar.gz: d5a62a30adfdaa7835007fb6377e4414c9d7630dc9e9ebd5e631a417e2777ee4c7211897cb03387d94f85ebe82f2d97ab0d43591967ace3da6ed4d6ee4106982
data/README.md ADDED
@@ -0,0 +1,190 @@
1
+ # RingCentral SDK for Ruby
2
+
3
+ [![Ruby](https://github.com/ringcentral/ringcentral-ruby/actions/workflows/ruby.yml/badge.svg)](https://github.com/ringcentral/ringcentral-ruby/actions/workflows/ruby.yml)
4
+ [![Reference](https://img.shields.io/badge/rubydoc-reference-blue?logo=ruby)](https://ringcentral.github.io/ringcentral-ruby/)
5
+ [![Twitter](https://img.shields.io/twitter/follow/ringcentraldevs.svg?style=social&label=follow)](https://twitter.com/RingCentralDevs)
6
+
7
+ __[RingCentral Developers](https://developer.ringcentral.com/api-products)__ is a cloud communications platform which can be accessed via more than 70 APIs. The platform's main capabilities include technologies that enable:
8
+ __[Voice](https://developer.ringcentral.com/api-products/voice), [SMS/MMS](https://developer.ringcentral.com/api-products/sms), [Fax](https://developer.ringcentral.com/api-products/fax), [Glip Team Messaging](https://developer.ringcentral.com/api-products/team-messaging), [Data and Configurations](https://developer.ringcentral.com/api-products/configuration)__.
9
+
10
+ ## Additional resources
11
+
12
+ * [RingCentral API Reference](https://developer.ringcentral.com/api-docs/latest/index.html) - an interactive reference for the RingCentral API that allows developers to make API calls with no code.
13
+ * [Document](https://ringcentral.github.io/ringcentral-ruby/) - an interactive reference for the SDK code documentation.
14
+
15
+
16
+ ## Getting help and support
17
+
18
+ If you are having difficulty using this SDK, or working with the RingCentral API, please visit our [developer community forums](https://community.ringcentral.com/spaces/144/) for help and to get quick answers to your questions. If you wish to contact the RingCentral Developer Support team directly, please [submit a help ticket](https://developers.ringcentral.com/support/create-case) from our developer website.
19
+
20
+
21
+ ## Installation
22
+
23
+ ```
24
+ gem install ringcentral-sdk
25
+ ```
26
+
27
+ If for some reason `eventmachine` failed to install, please check [this](https://stackoverflow.com/a/31516586/862862).
28
+
29
+
30
+ ### Name collision with `ringcentral` gem
31
+
32
+ The `ringcentral` gem is using RingCentral's legacy API which was End-of-Lifed in 2018. Everyone is recommended to move to the REST API.
33
+
34
+ If you have both the `ringcentral` and `ringcentral-sdk` gems installed, you will run into a collision error when attempting to initialize the `ringcentral-sdk` RingCentral SDK.
35
+
36
+ The solution is `gem uninstall ringcentral`
37
+
38
+
39
+ ## Documentation
40
+
41
+ https://developer.ringcentral.com/api-docs/latest/index.html
42
+
43
+
44
+ ## Usage
45
+
46
+ ```ruby
47
+ require 'ringcentral'
48
+
49
+ rc = RingCentral.new('clientID', 'clientSecret', 'serverURL')
50
+ rc.authorize(jwt: 'jwt-token')
51
+
52
+ # get
53
+ r = rc.get('/restapi/v1.0/account/~/extension/~')
54
+ expect(r).not_to be_nil
55
+ expect('101').to eq(r.body['extensionNumber'])
56
+ ```
57
+
58
+
59
+ ## How to specify query parameters
60
+
61
+ ### for get & delete
62
+
63
+ ```ruby
64
+ rc.get('/restapi/v1.0/account/~/extension', { hello: 'world' })
65
+ ```
66
+
67
+ ### for post, put & patch
68
+
69
+ ```ruby
70
+ rc.post('/restapi/v1.0/account/~/extension/~/sms', payload: body, params: { hello: 'world' })
71
+ ```
72
+
73
+ ### multi-value query parameter
74
+
75
+ ```ruby
76
+ rc.get('/restapi/v1.0/account/~/extension', { hello: ['world1', 'world2'] })
77
+ ```
78
+
79
+ Above will be translated to `/restapi/v1.0/account/~/extension?hello=world1&hello=world2`.
80
+
81
+
82
+ ### Token Refresh
83
+
84
+ Access token expires. You need to call `rc.refresh()` before it expires.
85
+ If you want the SDK to do auto refresh please `rc.auto_refresh = true` before authorization.
86
+
87
+
88
+ ### Load pre-existing token
89
+
90
+ Let's say you already have a token. Then you can load it like this: `rc.token = your_token_object`.
91
+ The benefit of loading a preexisting token is you don't need to go through any authorization flow.
92
+
93
+ If what you have is a JSON string instead of a Ruby object, you need to convert it first: `JSON.parse(your_token_string)`.
94
+
95
+ If you only have a string for the access token instead of for the whole object, you can set it like this:
96
+
97
+ ```ruby
98
+ rc.token = { access_token: 'the token string' }
99
+ ```
100
+
101
+
102
+ ### Send SMS
103
+
104
+ ```ruby
105
+ r = rc.post('/restapi/v1.0/account/~/extension/~/sms', payload: {
106
+ to: [{phoneNumber: ENV['RINGCENTRAL_RECEIVER']}],
107
+ from: {phoneNumber: ENV['RINGCENTRAL_SENDER']},
108
+ text: 'Hello world'
109
+ })
110
+ ```
111
+
112
+
113
+ ### Send fax
114
+
115
+ ```ruby
116
+ rc.post('/restapi/v1.0/account/~/extension/~/fax',
117
+ payload: { to: [{ phoneNumber: ENV['RINGCENTRAL_RECEIVER'] }] },
118
+ files: [
119
+ ['spec/test.txt', 'text/plain'],
120
+ ['spec/test.png', 'image/png']
121
+ ]
122
+ )
123
+ ```
124
+
125
+
126
+ ### Send MMS
127
+
128
+ ```ruby
129
+ r = rc.post('/restapi/v1.0/account/~/extension/~/sms',
130
+ payload: {
131
+ to: [{ phoneNumber: ENV['RINGCENTRAL_RECEIVER'] }],
132
+ from: { phoneNumber: ENV['RINGCENTRAL_SENDER'] },
133
+ text: 'hello world'
134
+ },
135
+ files: [
136
+ ['spec/test.png', 'image/png']
137
+ ]
138
+ )
139
+ ```
140
+
141
+
142
+ ## Subscriptions
143
+
144
+ ### WebSocket Subscriptions
145
+
146
+ ```ruby
147
+ events = [
148
+ '/restapi/v1.0/account/~/extension/~/message-store',
149
+ ]
150
+ subscription = WS.new(rc, events, lambda { |message|
151
+ puts message
152
+ })
153
+ subscription.subscribe()
154
+ ```
155
+
156
+ #### How to keep a subscription running 24 * 7?
157
+
158
+ There are two main cases that a subscription will be terminated:
159
+
160
+ - Absolute time out. The maximum time for a subscription to run is 24 hours. After that, the websocket connection will be closed by the server.
161
+ - Network issue. It could be your local network issue or the server's network issue. In either case, your websocket connection will be closed
162
+
163
+ In order to keep a subscription running 24 * 7, you need to re-subscribe when the connection is closed.
164
+
165
+ ```ruby
166
+ subscription.on_ws_closed = lambda { |event|
167
+ # make sure that there is no network issue and re-subscribe
168
+ subscription.subscribe()
169
+ }
170
+ ```
171
+
172
+
173
+ ## How to test
174
+
175
+ ```
176
+ bundle install
177
+ ```
178
+
179
+ Rename `.env.sample` to `.env`.
180
+
181
+ Edit `.env` file to specify credentials.
182
+
183
+ `RINGCENTRAL_RECEIVER` is a phone number to receive SMS, Fax..etc.
184
+
185
+ Run `bundle exec rspec`
186
+
187
+
188
+ ## License
189
+
190
+ MIT
@@ -0,0 +1,227 @@
1
+ require 'base64'
2
+ require 'addressable/uri'
3
+ require 'json'
4
+ require 'concurrent'
5
+ require 'faraday'
6
+ require 'faraday/multipart'
7
+
8
+ class RingCentral
9
+ def self.PRODUCTION_SERVER
10
+ 'https://platform.ringcentral.com'
11
+ end
12
+
13
+ attr_reader :client_id, :client_secret, :server, :token
14
+ attr_accessor :auto_refresh, :debug_mode
15
+
16
+ def initialize(client_id, client_secret, server = self.PRODUCTION_SERVER, debug_mode = false)
17
+ @client_id = client_id
18
+ @client_secret = client_secret
19
+ @server = server
20
+ @auto_refresh = false
21
+ @debug_mode = debug_mode
22
+ @token = nil
23
+ @timer = nil
24
+ @faraday = Faraday.new(url: server, request: { params_encoder: Faraday::FlatParamsEncoder }) do |faraday|
25
+ faraday.request :multipart
26
+ faraday.request :url_encoded
27
+ faraday.response :json, content_type: /\bjson$/
28
+ faraday.adapter Faraday.default_adapter
29
+ end
30
+ end
31
+
32
+ def token=(value)
33
+ @token = value
34
+ if @timer != nil
35
+ @timer.shutdown
36
+ @timer = nil
37
+ end
38
+ if @auto_refresh && value != nil
39
+ @timer = Concurrent::TimerTask.new(execution_interval: value['expires_in'] - 120, timeout_interval: 60) { self.refresh }
40
+ @timer.execute
41
+ end
42
+ end
43
+
44
+ def authorize(username: nil, extension: nil, password: nil, auth_code: nil, redirect_uri: nil, jwt: nil, verifier: nil)
45
+ if auth_code != nil
46
+ payload = {
47
+ grant_type: 'authorization_code',
48
+ code: auth_code,
49
+ redirect_uri: redirect_uri,
50
+ }
51
+ if verifier != nil
52
+ payload["code_verifier"] = verifier
53
+ end
54
+ elsif jwt != nil
55
+ payload = {
56
+ grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
57
+ assertion: jwt
58
+ }
59
+ else
60
+ warn('Password auth is deprecated. Use JWT auth or OAuth instead.')
61
+ payload = {
62
+ grant_type: 'password',
63
+ username: username,
64
+ extension: extension,
65
+ password: password,
66
+ }
67
+ end
68
+ self.token = nil
69
+ r = self.post('/restapi/oauth/token', payload: payload)
70
+ self.token = r.body
71
+ end
72
+
73
+ def refresh
74
+ return if @token == nil
75
+ payload = {
76
+ grant_type: 'refresh_token',
77
+ refresh_token: @token['refresh_token']
78
+ }
79
+ self.token = nil
80
+ r = self.post('/restapi/oauth/token', payload: payload)
81
+ self.token = r.body
82
+ end
83
+
84
+ def revoke
85
+ return if @token == nil
86
+ payload = { token: @token['access_token'] }
87
+ self.token = nil
88
+ self.post('/restapi/oauth/revoke', payload: payload)
89
+ end
90
+
91
+ def authorize_uri(redirect_uri, hash = {})
92
+ hash[:response_type] = 'code'
93
+ hash[:redirect_uri] = redirect_uri
94
+ hash[:client_id] = @client_id
95
+ uri = Addressable::URI.parse(@server) + '/restapi/oauth/authorize'
96
+ uri.query_values = hash
97
+ uri.to_s
98
+ end
99
+
100
+ def get(endpoint, params = {})
101
+ r = @faraday.get do |req|
102
+ req.url endpoint
103
+ req.params = params
104
+ req.headers = headers
105
+ end
106
+ if @debug_mode
107
+ puts r.status, r.body
108
+ end
109
+ if r.status >= 400
110
+ raise "HTTP status #{r.status}:
111
+
112
+ headers: #{r.headers}
113
+
114
+ body: #{r.body}"
115
+ end
116
+ return r
117
+ end
118
+
119
+ def post(endpoint, payload: nil, params: {}, files: nil)
120
+ r = @faraday.post do |req|
121
+ req.url endpoint
122
+ req.params = params
123
+ if files != nil && files.size > 0 # send fax or MMS
124
+ io = StringIO.new(payload.to_json)
125
+ payload = {}
126
+ payload[:json] = Faraday::UploadIO.new(io, 'application/json')
127
+ payload[:attachment] = files.map{ |file| Faraday::UploadIO.new(file[0], file[1]) }
128
+ req.headers = headers
129
+ req.body = payload
130
+ elsif payload != nil && @token != nil
131
+ req.headers = headers.merge({ 'Content-Type': 'application/json' })
132
+ req.body = payload.to_json
133
+ else
134
+ req.headers = headers
135
+ req.body = payload
136
+ end
137
+ end
138
+ if @debug_mode
139
+ puts r.status, r.body
140
+ end
141
+ if r.status >= 400
142
+ raise "HTTP status #{r.status}:
143
+
144
+ headers: #{r.headers}
145
+
146
+ body: #{r.body}"
147
+ end
148
+ return r
149
+ end
150
+
151
+ def put(endpoint, payload: nil, params: {}, files: nil)
152
+ r = @faraday.put do |req|
153
+ req.url endpoint
154
+ req.params = params
155
+ req.headers = headers.merge({ 'Content-Type': 'application/json' })
156
+ req.body = payload.to_json
157
+ end
158
+ if @debug_mode
159
+ puts r.status, r.body
160
+ end
161
+ if r.status >= 400
162
+ raise "HTTP status #{r.status}:
163
+
164
+ headers: #{r.headers}
165
+
166
+ body: #{r.body}"
167
+ end
168
+ return r
169
+ end
170
+
171
+ def patch(endpoint, payload: nil, params: {}, files: nil)
172
+ r = @faraday.patch do |req|
173
+ req.url endpoint
174
+ req.params = params
175
+ req.headers = headers.merge({ 'Content-Type': 'application/json' })
176
+ req.body = payload.to_json
177
+ end
178
+ if @debug_mode
179
+ puts r.status, r.body
180
+ end
181
+ if r.status >= 400
182
+ raise "HTTP status #{r.status}:
183
+
184
+ headers: #{r.headers}
185
+
186
+ body: #{r.body}"
187
+ end
188
+ return r
189
+ end
190
+
191
+ def delete(endpoint, params = {})
192
+ r = @faraday.delete do |req|
193
+ req.url endpoint
194
+ req.params = params
195
+ req.headers = headers
196
+ end
197
+ if @debug_mode
198
+ puts r.status, r.body
199
+ end
200
+ if r.status >= 400
201
+ raise "HTTP status #{r.status}:
202
+
203
+ headers: #{r.headers}
204
+
205
+ body: #{r.body}"
206
+ end
207
+ return r
208
+ end
209
+
210
+ private
211
+
212
+ def basic_key
213
+ Base64.encode64("#{@client_id}:#{@client_secret}").gsub(/\s/, '')
214
+ end
215
+
216
+ def autorization_header
217
+ @token != nil ? "Bearer #{@token['access_token']}" : "Basic #{basic_key}"
218
+ end
219
+
220
+ def headers
221
+ user_agent_header = "ringcentral/ringcentral-ruby Ruby #{RUBY_VERSION} #{RUBY_PLATFORM}"
222
+ {
223
+ 'Authorization': autorization_header,
224
+ 'X-User-Agent': user_agent_header,
225
+ }
226
+ end
227
+ end
@@ -0,0 +1,66 @@
1
+ require 'concurrent'
2
+ require 'faye/websocket'
3
+ require 'securerandom'
4
+ require 'eventmachine'
5
+
6
+ class WS
7
+ def initialize(ringcentral, events, callback, debugMode = false)
8
+ @rc = ringcentral
9
+ @events = events
10
+ @callback = callback
11
+ @debugMode = debugMode
12
+ end
13
+
14
+ def on_ws_closed=(callback)
15
+ @on_ws_closed = callback
16
+ end
17
+
18
+ def subscribe
19
+ r = @rc.post('/restapi/oauth/wstoken').body
20
+ @t = Thread.new do
21
+ EM.run {
22
+ @ws = Faye::WebSocket::Client.new(r['uri'] + '?access_token=' + r['ws_access_token'])
23
+ if @debugMode
24
+ class << @ws
25
+ def send(message)
26
+ puts "Sending...\n" + message
27
+ super(message)
28
+ end
29
+ end
30
+ end
31
+ @ws.on :open do
32
+ @ws.send([
33
+ { type: 'ClientRequest', method: 'POST', path: '/restapi/v1.0/subscription', messageId: SecureRandom.uuid },
34
+ { deliveryMode: { transportType: 'WebSocket' }, eventFilters: @events }
35
+ ].to_json())
36
+
37
+ # send a heartbeat every 10 minutes
38
+ @task = Concurrent::TimerTask.new(execution_interval: 600) do
39
+ @ws.send([
40
+ { type: 'Heartbeat', messageId: SecureRandom.uuid },
41
+ ].to_json())
42
+ end
43
+ @task.execute
44
+ end
45
+ @ws.on :message do |event|
46
+ if @debugMode
47
+ puts "Receiving...\n" + event.data
48
+ end
49
+ header, body = JSON.parse(event.data)
50
+ if header['type'] == 'ServerNotification'
51
+ @callback.call(body)
52
+ end
53
+ end
54
+ @ws.on :close do |event|
55
+ if @on_ws_closed
56
+ @on_ws_closed.call(event)
57
+ end
58
+ end
59
+ }
60
+ end
61
+ end
62
+
63
+ def revoke
64
+ @t.kill
65
+ end
66
+ end
data/spec/fax_spec.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'dotenv'
2
+ require 'ringcentral'
3
+ require "simplecov"
4
+ SimpleCov.start
5
+
6
+ RSpec.describe 'Fax' do
7
+ describe 'send fax' do
8
+ it 'should send a fax' do
9
+ Dotenv.load
10
+ rc = RingCentral.new(ENV['RINGCENTRAL_CLIENT_ID'], ENV['RINGCENTRAL_CLIENT_SECRET'], ENV['RINGCENTRAL_SERVER_URL'])
11
+ rc.authorize(jwt: ENV['RINGCENTRAL_JWT_TOKEN'])
12
+ r = rc.post('/restapi/v1.0/account/~/extension/~/fax',
13
+ payload: { to: [{ phoneNumber: ENV['RINGCENTRAL_RECEIVER'] }] },
14
+ files: [
15
+ ['spec/test.txt', 'text/plain'],
16
+ ['spec/test.png', 'image/png']
17
+ ]
18
+ )
19
+ expect(r).not_to be_nil
20
+ message = r.body
21
+ expect('Fax').to eq(message['type'])
22
+
23
+ rc.revoke()
24
+ end
25
+ end
26
+ end
data/spec/mms_spec.rb ADDED
@@ -0,0 +1,30 @@
1
+ require 'dotenv'
2
+ require 'ringcentral'
3
+ require "simplecov"
4
+ SimpleCov.start
5
+
6
+ RSpec.describe 'MMS' do
7
+ describe 'send MMS' do
8
+ it 'should send an MMS' do
9
+ Dotenv.load
10
+ rc = RingCentral.new(ENV['RINGCENTRAL_CLIENT_ID'], ENV['RINGCENTRAL_CLIENT_SECRET'], ENV['RINGCENTRAL_SERVER_URL'])
11
+ rc.authorize(jwt: ENV['RINGCENTRAL_JWT_TOKEN'])
12
+
13
+ r = rc.post('/restapi/v1.0/account/~/extension/~/sms',
14
+ payload: {
15
+ to: [{ phoneNumber: ENV['RINGCENTRAL_RECEIVER'] }],
16
+ from: { phoneNumber: ENV['RINGCENTRAL_SENDER'] },
17
+ text: 'hello world'
18
+ },
19
+ files: [
20
+ ['spec/test.png', 'image/png']
21
+ ]
22
+ )
23
+ expect(r).not_to be_nil
24
+ message = r.body
25
+ expect('SMS').to eq(message['type'])
26
+
27
+ rc.revoke()
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ require 'dotenv'
2
+ require 'ringcentral'
3
+ require "simplecov"
4
+ SimpleCov.start
5
+
6
+ RSpec.describe 'query params' do
7
+ describe 'single' do
8
+ it 'contain single query param' do
9
+ Dotenv.load
10
+ rc = RingCentral.new(ENV['RINGCENTRAL_CLIENT_ID'], ENV['RINGCENTRAL_CLIENT_SECRET'], ENV['RINGCENTRAL_SERVER_URL'])
11
+ rc.authorize(jwt: ENV['RINGCENTRAL_JWT_TOKEN'])
12
+ r = rc.get('/restapi/v1.0/account/~/extension/~/address-book/contact', { phoneNumber: '666' })
13
+ expect(r).not_to be_nil
14
+ message = r.body
15
+ expect(message['uri']).to include('phoneNumber=666')
16
+
17
+ r = rc.get('/restapi/v1.0/account/~/extension/~/address-book/contact', { phoneNumber: ['666', '888'] })
18
+ expect(r).not_to be_nil
19
+ message = r.body
20
+ expect(message['uri']).to include('phoneNumber=666&phoneNumber=888')
21
+
22
+ rc.revoke()
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,86 @@
1
+ require 'ringcentral'
2
+ require "simplecov"
3
+ SimpleCov.start
4
+
5
+ RSpec.describe 'RingCentral' do
6
+ describe 'ringcentral' do
7
+ it 'test_class_variables' do
8
+ expect('https://platform.ringcentral.com').to eq(RingCentral.PRODUCTION_SERVER)
9
+ end
10
+
11
+ it 'test_initializer' do
12
+ rc = RingCentral.new('client_id', 'client_secret', RingCentral.PRODUCTION_SERVER)
13
+ expect('client_id').to eq(rc.client_id)
14
+ expect('client_secret').to eq(rc.client_secret)
15
+ expect('https://platform.ringcentral.com').to eq(rc.server)
16
+ expect(false).to eq(rc.auto_refresh)
17
+ end
18
+
19
+ it 'test_authorize_uri' do
20
+ rc = RingCentral.new('client_id', 'client_secret', RingCentral.PRODUCTION_SERVER)
21
+ expect(RingCentral.PRODUCTION_SERVER + '/restapi/oauth/authorize?client_id=client_id&redirect_uri=https%3A%2F%2Fexample.com&response_type=code&state=mystate').to eq(rc.authorize_uri('https://example.com', {state: 'mystate'}))
22
+ end
23
+
24
+ it 'test_jwt_flow' do
25
+ Dotenv.load
26
+ rc = RingCentral.new(ENV['RINGCENTRAL_CLIENT_ID'], ENV['RINGCENTRAL_CLIENT_SECRET'], ENV['RINGCENTRAL_SERVER_URL'])
27
+ expect(rc.token).to be_nil
28
+
29
+ # create token
30
+ rc.authorize(jwt: ENV['RINGCENTRAL_JWT_TOKEN'])
31
+ expect(rc.token).not_to be_nil
32
+
33
+ # refresh token
34
+ rc.refresh
35
+ expect(rc.token).not_to be_nil
36
+
37
+ # revoke token
38
+ rc.revoke
39
+ expect(rc.token).to be_nil
40
+ end
41
+
42
+ it 'test_http_methods' do
43
+ Dotenv.load
44
+ rc = RingCentral.new(ENV['RINGCENTRAL_CLIENT_ID'], ENV['RINGCENTRAL_CLIENT_SECRET'], ENV['RINGCENTRAL_SERVER_URL'])
45
+ rc.authorize(jwt: ENV['RINGCENTRAL_JWT_TOKEN'])
46
+
47
+ # get
48
+ r = rc.get('/restapi/v1.0/account/~/extension/~')
49
+ expect(r).not_to be_nil
50
+ expect(r.body['extensionNumber']).not_to be_nil
51
+
52
+ # post
53
+ r = rc.post('/restapi/v1.0/account/~/extension/~/company-pager', payload: {
54
+ to: [{extensionId: rc.token['owner_id']}],
55
+ from: {extensionId: rc.token['owner_id']},
56
+ text: 'Hello world'
57
+ })
58
+ expect(r).not_to be_nil
59
+ message = r.body
60
+ expect('Pager').to eq(message['type'])
61
+ messageUrl = "/restapi/v1.0/account/~/extension/~/message-store/#{message['id']}"
62
+
63
+ # put
64
+ r = rc.put(messageUrl, payload: { readStatus: 'Unread' })
65
+ expect(r).not_to be_nil
66
+ message = r.body
67
+ expect('Unread').to eq(message['readStatus'])
68
+ r = rc.put(messageUrl, payload: { readStatus: 'Read' })
69
+ expect(r).not_to be_nil
70
+ message = r.body
71
+ expect('Read').to eq(message['readStatus'])
72
+
73
+ # todo: test patch
74
+
75
+ # delete
76
+ r = rc.delete(messageUrl)
77
+ expect(r).not_to be_nil
78
+ r = rc.get(messageUrl)
79
+ expect(r).not_to be_nil
80
+ message = r.body
81
+ expect('Deleted').to eq(message['availability'])
82
+
83
+ rc.revoke()
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,76 @@
1
+ require 'ringcentral'
2
+ require 'subscription'
3
+ require 'dotenv'
4
+ require 'rspec'
5
+ require "simplecov"
6
+ SimpleCov.start
7
+
8
+ Dotenv.load
9
+ $rc = RingCentral.new(ENV['RINGCENTRAL_CLIENT_ID'], ENV['RINGCENTRAL_CLIENT_SECRET'], ENV['RINGCENTRAL_SERVER_URL'])
10
+
11
+ RSpec.describe 'WebSocket Subscription' do
12
+ def createSubscription(callback)
13
+ events = [
14
+ '/restapi/v1.0/account/~/extension/~/message-store?type=Pager',
15
+ ]
16
+ subscription = WS.new($rc, events, lambda { |message|
17
+ callback.call(message)
18
+ })
19
+ subscription.subscribe()
20
+ # subscription.on_ws_closed = lambda { |event|
21
+ # puts 'WebSocket closed'
22
+ # }
23
+ return subscription
24
+ end
25
+
26
+ describe 'WebSocket Subscription' do
27
+ it 'receives message notification' do
28
+ $rc.authorize(jwt: ENV['RINGCENTRAL_JWT_TOKEN'])
29
+ count = 0
30
+ sub = createSubscription(lambda { |message|
31
+ count += 1
32
+ })
33
+
34
+ $rc.post('/restapi/v1.0/account/~/extension/~/company-pager', payload: {
35
+ to: [{extensionId: $rc.token['owner_id']}],
36
+ from: {extensionId: $rc.token['owner_id']},
37
+ text: 'Hello world'
38
+ })
39
+ sleep(10)
40
+ expect(count).to be > 0
41
+
42
+ # sleep for some time and see if the websocket is still alive
43
+ sleep(20)
44
+ $rc.post('/restapi/v1.0/account/~/extension/~/company-pager', payload: {
45
+ to: [{extensionId: $rc.token['owner_id']}],
46
+ from: {extensionId: $rc.token['owner_id']},
47
+ text: 'Hello world'
48
+ })
49
+ sleep(10)
50
+ expect(count).to be > 1
51
+
52
+ sub.revoke()
53
+ $rc.revoke()
54
+ end
55
+
56
+ it 'revoke' do
57
+ $rc.authorize(jwt: ENV['RINGCENTRAL_JWT_TOKEN'])
58
+ count = 0
59
+ subscription = createSubscription(lambda { |message|
60
+ count += 1
61
+ })
62
+
63
+ subscription.revoke()
64
+
65
+ $rc.post('/restapi/v1.0/account/~/extension/~/company-pager', payload: {
66
+ to: [{extensionId: $rc.token['owner_id']}],
67
+ from: {extensionId: $rc.token['owner_id']},
68
+ text: 'Hello world'
69
+ })
70
+ sleep(10)
71
+
72
+ expect(count).to eq(0)
73
+ $rc.revoke()
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,21 @@
1
+ Gem::Specification.new do |gem|
2
+ gem.name = 'test-rc-sdk'
3
+ gem.version = '1.0.0'
4
+ gem.authors = ['Sushil Mall']
5
+ gem.email = ['sushil.mall@ringcentral.com']
6
+ gem.description = 'Ruby SDK for you to access RingCentral platform API.'
7
+ gem.summary = 'RingCentral Ruby SDK.'
8
+ gem.homepage = 'https://github.com/SushilMallRC/ringcentral-ruby'
9
+ gem.license = 'MIT'
10
+
11
+ gem.require_paths = ['lib']
12
+ gem.files = %w(README.md test-rc-sdk.gemspec)
13
+ gem.files += Dir['lib/**/*.rb']
14
+ gem.test_files = Dir['spec/**/*.rb']
15
+
16
+ gem.add_dependency('addressable', '~> 2.8', '>= 2.8.6')
17
+ gem.add_dependency('concurrent-ruby', '~> 1.2', '>= 1.2.3')
18
+ gem.add_dependency('faraday', '~> 2.9', '>= 2.9.0')
19
+ gem.add_dependency('faraday-multipart', '~> 1.0', '>= 1.0.4')
20
+ gem.add_dependency('faye-websocket', '~> 0.11', '>= 0.11.3')
21
+ end
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: test-rc-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Sushil Mall
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-05-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: addressable
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.8'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.8.6
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.8'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.8.6
33
+ - !ruby/object:Gem::Dependency
34
+ name: concurrent-ruby
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.2'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.2.3
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.2'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.2.3
53
+ - !ruby/object:Gem::Dependency
54
+ name: faraday
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '2.9'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 2.9.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '2.9'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 2.9.0
73
+ - !ruby/object:Gem::Dependency
74
+ name: faraday-multipart
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '1.0'
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 1.0.4
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.0'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 1.0.4
93
+ - !ruby/object:Gem::Dependency
94
+ name: faye-websocket
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '0.11'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 0.11.3
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '0.11'
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 0.11.3
113
+ description: Ruby SDK for you to access RingCentral platform API.
114
+ email:
115
+ - sushil.mall@ringcentral.com
116
+ executables: []
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - README.md
121
+ - lib/ringcentral.rb
122
+ - lib/subscription.rb
123
+ - spec/fax_spec.rb
124
+ - spec/mms_spec.rb
125
+ - spec/query_params_spec.rb
126
+ - spec/ringcentral_spec.rb
127
+ - spec/websocket_subscription_spec.rb
128
+ - test-rc-sdk.gemspec
129
+ homepage: https://github.com/SushilMallRC/ringcentral-ruby
130
+ licenses:
131
+ - MIT
132
+ metadata: {}
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubygems_version: 3.4.19
149
+ signing_key:
150
+ specification_version: 4
151
+ summary: RingCentral Ruby SDK.
152
+ test_files:
153
+ - spec/fax_spec.rb
154
+ - spec/mms_spec.rb
155
+ - spec/query_params_spec.rb
156
+ - spec/ringcentral_spec.rb
157
+ - spec/websocket_subscription_spec.rb