ringcentral-avatars 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +164 -0
- data/NEWS.md +278 -0
- data/README.md +32 -2
- data/lib/ringcentral-avatars.rb +1 -1
- data/lib/ringcentral-avatars/creator.rb +44 -19
- metadata +11 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36141cadb78befc9afe2c8383721e8645d9e320a
|
4
|
+
data.tar.gz: 55e6cc5ed25ab49f57391a51c65e92450c813f13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff2d64ea6868369971ebb40ce485118416c8ef7052c9b0421bda7d1c98e41e48147b6a501bfc1f1494e07d8e13fe696528de97cffc5fe50fa572d684ff5ce36c
|
7
|
+
data.tar.gz: 9734754fe66688298036dd7c5fd08ec67ec564f4e9732c27462475c230bcaf7364e054023d8cb04a0b92dcba7ee80e1b3d379053ff490b43c541b01e95ab56d1
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
CHANGELOG
|
2
2
|
---------
|
3
|
+
- **2016-12-28**: 0.5.0
|
4
|
+
- Add auto-retry for `429` and `503` errors.
|
5
|
+
- Add test script to try PNG, JPG, and GIF filetypes
|
6
|
+
- Add article `NEWS.md`
|
7
|
+
- **2016-11-19**: 0.4.1
|
8
|
+
- Fix RubyDoc.info documentation rendering
|
3
9
|
- **2016-11-19**: 0.4.0
|
4
10
|
- Add PNG metadata support
|
5
11
|
- Add demo scripts in `./scripts` directory
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ringcentral-avatars (0.5.0)
|
5
|
+
avatarly (~> 1.5, >= 1.5.0)
|
6
|
+
chunky_png (~> 1.3, >= 1.3.8)
|
7
|
+
faraday (~> 0.9, >= 0.9)
|
8
|
+
mime-types (~> 3.0, >= 3.1)
|
9
|
+
ringcentral_sdk (~> 2, >= 2.0.2)
|
10
|
+
ruby_identicon (~> 0, >= 0.0.5)
|
11
|
+
|
12
|
+
GEM
|
13
|
+
remote: https://rubygems.org/
|
14
|
+
specs:
|
15
|
+
avatarly (1.5.0)
|
16
|
+
rfc822
|
17
|
+
rmagick
|
18
|
+
unicode_utils
|
19
|
+
celluloid (0.17.3)
|
20
|
+
celluloid-essentials
|
21
|
+
celluloid-extras
|
22
|
+
celluloid-fsm
|
23
|
+
celluloid-pool
|
24
|
+
celluloid-supervision
|
25
|
+
timers (>= 4.1.1)
|
26
|
+
celluloid-essentials (0.20.5)
|
27
|
+
timers (>= 4.1.1)
|
28
|
+
celluloid-extras (0.20.5)
|
29
|
+
timers (>= 4.1.1)
|
30
|
+
celluloid-fsm (0.20.5)
|
31
|
+
timers (>= 4.1.1)
|
32
|
+
celluloid-pool (0.20.5)
|
33
|
+
timers (>= 4.1.1)
|
34
|
+
celluloid-supervision (0.20.6)
|
35
|
+
timers (>= 4.1.1)
|
36
|
+
chunky_png (1.3.8)
|
37
|
+
concurrent-ruby (1.0.3)
|
38
|
+
coveralls (0.8.17)
|
39
|
+
json (>= 1.8, < 3)
|
40
|
+
simplecov (~> 0.12.0)
|
41
|
+
term-ansicolor (~> 1.3)
|
42
|
+
thor (~> 0.19.1)
|
43
|
+
tins (~> 1.6)
|
44
|
+
docile (1.1.5)
|
45
|
+
dotenv (2.1.1)
|
46
|
+
dry-configurable (0.5.0)
|
47
|
+
concurrent-ruby (~> 1.0)
|
48
|
+
dry-container (0.6.0)
|
49
|
+
concurrent-ruby (~> 1.0)
|
50
|
+
dry-configurable (~> 0.1, >= 0.1.3)
|
51
|
+
dry-core (0.2.1)
|
52
|
+
concurrent-ruby (~> 1.0)
|
53
|
+
dry-equalizer (0.2.0)
|
54
|
+
dry-logic (0.4.0)
|
55
|
+
dry-container (~> 0.2, >= 0.2.6)
|
56
|
+
dry-core (~> 0.1)
|
57
|
+
dry-equalizer (~> 0.2)
|
58
|
+
dry-types (0.9.3)
|
59
|
+
concurrent-ruby (~> 1.0)
|
60
|
+
dry-configurable (~> 0.1)
|
61
|
+
dry-container (~> 0.3)
|
62
|
+
dry-core (~> 0.2, >= 0.2.1)
|
63
|
+
dry-equalizer (~> 0.2)
|
64
|
+
dry-logic (~> 0.4, >= 0.4.0)
|
65
|
+
inflecto (~> 0.0.0, >= 0.0.2)
|
66
|
+
dry-validation (0.10.4)
|
67
|
+
concurrent-ruby (~> 1.0)
|
68
|
+
dry-configurable (~> 0.1, >= 0.1.3)
|
69
|
+
dry-container (~> 0.2, >= 0.2.8)
|
70
|
+
dry-core (~> 0.2, >= 0.2.1)
|
71
|
+
dry-equalizer (~> 0.2)
|
72
|
+
dry-logic (~> 0.4, >= 0.4.0)
|
73
|
+
dry-types (~> 0.9, >= 0.9.0)
|
74
|
+
faraday (0.9.2)
|
75
|
+
multipart-post (>= 1.2, < 3)
|
76
|
+
faraday_middleware (0.10.1)
|
77
|
+
faraday (>= 0.7.4, < 1.0)
|
78
|
+
faraday_middleware-oauth2_refresh (0.0.3)
|
79
|
+
faraday (~> 0.9, >= 0.9)
|
80
|
+
faraday_middleware (~> 0, >= 0)
|
81
|
+
faraday_middleware-request-retry (0.2.0)
|
82
|
+
faraday (~> 0, >= 0)
|
83
|
+
faraday_middleware (~> 0, >= 0)
|
84
|
+
hitimes (1.2.4)
|
85
|
+
httpclient (2.8.3)
|
86
|
+
inflecto (0.0.2)
|
87
|
+
json (2.0.2)
|
88
|
+
jsondoc (0.1.3)
|
89
|
+
jwt (1.5.6)
|
90
|
+
logger (1.2.8)
|
91
|
+
metaclass (0.0.4)
|
92
|
+
mime (0.4.3)
|
93
|
+
mime-types (3.1)
|
94
|
+
mime-types-data (~> 3.2015)
|
95
|
+
mime-types-data (3.2016.0521)
|
96
|
+
mime_builder (0.0.4)
|
97
|
+
mime (~> 0.4, >= 0.4.3)
|
98
|
+
mime-types (~> 3.1)
|
99
|
+
multi_json (~> 1, >= 1.12.1)
|
100
|
+
mocha (1.2.1)
|
101
|
+
metaclass (~> 0.0.1)
|
102
|
+
multi_json (1.12.1)
|
103
|
+
multi_xml (0.6.0)
|
104
|
+
multipart-post (2.0.0)
|
105
|
+
oauth2 (1.2.0)
|
106
|
+
faraday (>= 0.8, < 0.10)
|
107
|
+
jwt (~> 1.0)
|
108
|
+
multi_json (~> 1.3)
|
109
|
+
multi_xml (~> 0.5)
|
110
|
+
rack (>= 1.2, < 3)
|
111
|
+
power_assert (0.4.1)
|
112
|
+
pubnub (4.0.17)
|
113
|
+
celluloid (~> 0.17)
|
114
|
+
dry-validation (~> 0.10)
|
115
|
+
httpclient (~> 2.8)
|
116
|
+
json (>= 1.8, < 3)
|
117
|
+
rack (2.0.1)
|
118
|
+
rake (11.3.0)
|
119
|
+
rfc822 (0.1.5)
|
120
|
+
ringcentral_sdk (2.0.3)
|
121
|
+
dotenv (~> 2.1, >= 2.1.0)
|
122
|
+
faraday (~> 0, >= 0)
|
123
|
+
faraday_middleware (~> 0, >= 0)
|
124
|
+
faraday_middleware-oauth2_refresh (~> 0)
|
125
|
+
faraday_middleware-request-retry (~> 0.1, >= 0.1.0)
|
126
|
+
jsondoc (~> 0.1, >= 0.1.0)
|
127
|
+
logger (~> 1)
|
128
|
+
mime (~> 0.4, >= 0.4.3)
|
129
|
+
mime-types (~> 3.1)
|
130
|
+
mime_builder (~> 0, >= 0.0.4)
|
131
|
+
multi_json (~> 1.3)
|
132
|
+
oauth2 (~> 1.0, >= 1.0.0)
|
133
|
+
pubnub (~> 4.0)
|
134
|
+
rmagick (2.16.0)
|
135
|
+
ruby_identicon (0.0.5)
|
136
|
+
chunky_png (~> 1.3.5)
|
137
|
+
simplecov (0.12.0)
|
138
|
+
docile (~> 1.1.0)
|
139
|
+
json (>= 1.8, < 3)
|
140
|
+
simplecov-html (~> 0.10.0)
|
141
|
+
simplecov-html (0.10.0)
|
142
|
+
term-ansicolor (1.4.0)
|
143
|
+
tins (~> 1.0)
|
144
|
+
test-unit (3.2.3)
|
145
|
+
power_assert
|
146
|
+
thor (0.19.4)
|
147
|
+
timers (4.1.2)
|
148
|
+
hitimes
|
149
|
+
tins (1.13.0)
|
150
|
+
unicode_utils (1.4.0)
|
151
|
+
|
152
|
+
PLATFORMS
|
153
|
+
ruby
|
154
|
+
|
155
|
+
DEPENDENCIES
|
156
|
+
coveralls (~> 0)
|
157
|
+
mocha (~> 1)
|
158
|
+
rake (~> 11)
|
159
|
+
ringcentral-avatars!
|
160
|
+
simplecov (~> 0)
|
161
|
+
test-unit (~> 3)
|
162
|
+
|
163
|
+
BUNDLED WITH
|
164
|
+
1.13.6
|
data/NEWS.md
ADDED
@@ -0,0 +1,278 @@
|
|
1
|
+
Using The Profile Image API and Default Images
|
2
|
+
==============================================
|
3
|
+
|
4
|
+
The RingCentral Profile Image API is a powerful API that can be used to upload images that are used in the corporate address book both individually and administratively across users. Some popular use cases include:
|
5
|
+
|
6
|
+
1. Syncing images from Active Directory or Okta
|
7
|
+
2. Uploading images from mobile apps
|
8
|
+
3. Setting default images for users
|
9
|
+
|
10
|
+
For this article, we'll cover API basics and then discuss how to set default images using either user initials like Gmail/Office 365 or Identicons. The initials will look like the following in the RingCentral for Desktop softphone. The avatars will update in the softphone in real-time as they are changed on the backend:
|
11
|
+
|
12
|
+
![](https://raw.githubusercontent.com/ringcentral-ruby/ringcentral-avatars-ruby/master/docs/images/ringcentral-avatars-softphone.png)
|
13
|
+
|
14
|
+
We will cover:
|
15
|
+
|
16
|
+
1. API basics
|
17
|
+
1. User profile image information
|
18
|
+
1. Example user object
|
19
|
+
2. Update user profile image
|
20
|
+
1. Example request
|
21
|
+
3. Subscribing for avatar updates
|
22
|
+
1. Example request
|
23
|
+
2. Example response
|
24
|
+
3. Retrieving the user image
|
25
|
+
2. Default images recipe
|
26
|
+
1. Getting a list of extensions without avatars
|
27
|
+
2. Creating the default image
|
28
|
+
3. Identifying auto-generated default images
|
29
|
+
4. Wrapping it up
|
30
|
+
1. Notes
|
31
|
+
2. Throttling
|
32
|
+
|
33
|
+
This article uses the Ruby language and leverages the community [`ringcentral_sdk`](https://rubygems.org/gems/ringcentral_sdk) SDK gem. It presents code which is implemented in a similar way in the [`ringcentral-avatars`](https://rubygems.org/gems/ringcentral-avatars) Ruby gem for discussion purposes. If you just want to use the functionality, you can use the Ruby gem directly.
|
34
|
+
|
35
|
+
## API basics
|
36
|
+
|
37
|
+
When working with the Profile API, there are a few basic APIs to use:
|
38
|
+
|
39
|
+
| method | endpoint | notes |
|
40
|
+
|--------|----------|-------|
|
41
|
+
| `GET` | `account/~/extension/~` | Get your own extension info with profile image information. |
|
42
|
+
| `GET` | `account/~/extension` | Get a list of extension with profile image information. |
|
43
|
+
| `PUT` | `account/~/extension/~/profile-image` | Update the user's profile image with a binary image file. |
|
44
|
+
| n/a | `account/~/extension` | Event filter for webhook and PubNub-based subscriptions |
|
45
|
+
|
46
|
+
### User profile image information
|
47
|
+
|
48
|
+
To retrieve the extension `profileImage` information for a user, retrieve the user's `account/~/extension/~` endpoint.
|
49
|
+
|
50
|
+
#### Example user object
|
51
|
+
|
52
|
+
```json
|
53
|
+
{
|
54
|
+
"uri": "https://platform.devtest.ringcentral.com/restapi/v1.0/account/11111111/extension/22222222",
|
55
|
+
"id": 22222222,
|
56
|
+
"extensionNumber": "102",
|
57
|
+
"contact": {
|
58
|
+
"firstName": "Alice"
|
59
|
+
"businessPhone": "+6505550102"
|
60
|
+
},
|
61
|
+
"name": "Alice",
|
62
|
+
"type": "User",
|
63
|
+
"status": "Enabled",
|
64
|
+
"permissions": {
|
65
|
+
"admin": {
|
66
|
+
"enabled": false
|
67
|
+
},
|
68
|
+
"internationalCalling": {
|
69
|
+
"enabled": false
|
70
|
+
}
|
71
|
+
},
|
72
|
+
"profileImage": {
|
73
|
+
"uri": "https://media.devtest.ringcentral.com/restapi/v1.0/account/11111111/extension/22222222/profile-image",
|
74
|
+
"etag": "0123456789abcdef0123456789abcdef",
|
75
|
+
"contentType": "image/png",
|
76
|
+
"lastModified": "2016-11-01T00:00:00.000Z",
|
77
|
+
"scales": [
|
78
|
+
{
|
79
|
+
"uri": "https://media.devtest.ringcentral.com/restapi/v1.0/account/11111111/extension/22222222/profile-image/90x90"
|
80
|
+
},
|
81
|
+
{
|
82
|
+
"uri": "https://media.devtest.ringcentral.com/restapi/v1.0/account/11111111/extension/22222222/profile-image/195x195"
|
83
|
+
},
|
84
|
+
{
|
85
|
+
"uri": "https://media.devtest.ringcentral.com/restapi/v1.0/account/11111111/extension/22222222/profile-image/584x584"
|
86
|
+
}
|
87
|
+
]
|
88
|
+
}
|
89
|
+
}
|
90
|
+
```
|
91
|
+
|
92
|
+
### Update user profile image
|
93
|
+
|
94
|
+
To update an image make a `PUT` request to the user's `account/~/extension/~/profile-image` endpoint using `multipart/formdata` and the `image` attribute.
|
95
|
+
|
96
|
+
#### Example request
|
97
|
+
|
98
|
+
Using the Ruby SDK, you can do the following:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
url = 'account/~/extension/~/profile-image'
|
102
|
+
file = Faraday::UploadIO.new '/path/to/myimage.png', 'image/png'
|
103
|
+
|
104
|
+
client.http.put url, image: file
|
105
|
+
```
|
106
|
+
|
107
|
+
### Subscribing for avatar updates
|
108
|
+
|
109
|
+
Client applications can subscribe for updates by using the Subscription API using either webhooks or PubNub using the `account/~/extension` event filter. The app will be notified of changes in real time and can retrieve the relevant images. This type of client-side update is implemented in the RingCentral for Desktop softphone app.
|
110
|
+
|
111
|
+
#### Example request
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
# Create an observable subscription and add your observer
|
115
|
+
sub = client.create_subscription()
|
116
|
+
sub.subscribe([ "/restapi/v1.0/account/~/extension" ])
|
117
|
+
sub.add_observer MyObserver.new()
|
118
|
+
```
|
119
|
+
|
120
|
+
#### Example event
|
121
|
+
|
122
|
+
When a user's extension has changed for any reason, including, profile image updates, an event is fired that matches `account/~/extension` filter mentioned above with the following example format. Once you have the `extensionId` you can retrieve the user extension if to see if the `etag` has changed. If so, you can retrieve and update the image in your app.
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
{
|
126
|
+
"uuid":"11112222-0000-0000-0000-333344445555",
|
127
|
+
"event":"/restapi/v1.0/account/11111111/extension",
|
128
|
+
"timestamp":"2016-11-23T16:42:08.482Z",
|
129
|
+
"subscriptionId":"11112222-1111-1111-1111-333344445555",
|
130
|
+
"body": {
|
131
|
+
"extensions":[
|
132
|
+
{"extensionId":"22222222","eventType":"Update"}
|
133
|
+
]
|
134
|
+
}
|
135
|
+
}
|
136
|
+
```
|
137
|
+
|
138
|
+
## Default images recipe
|
139
|
+
|
140
|
+
To create default images we want to do a few things:
|
141
|
+
|
142
|
+
1. Get a list of all extensions which do not have avatars
|
143
|
+
2. Create and upload default images for extensions
|
144
|
+
|
145
|
+
### Getting a list of extensions without avatars
|
146
|
+
|
147
|
+
To get a list of extensions without avatars, we need to get a list of all extensions and then filter for users without avatars. Since we do not have a way to do this server-side, we will retrieve all extensions and then filter client-side.
|
148
|
+
|
149
|
+
For the client-side filter, we will look for the `profileImage.etag` property. The `etag` property will not exist if there is no avatar which is an easy way to identify users that need a default avatar.
|
150
|
+
|
151
|
+
For example:
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
require 'ringcentral_sdk'
|
155
|
+
|
156
|
+
client = RingCentralSdk.new ...
|
157
|
+
client.authorize ...
|
158
|
+
|
159
|
+
# Retrieve up to 1000 extensions
|
160
|
+
res = client.http.get do |req|
|
161
|
+
req.url 'account/~/extension'
|
162
|
+
req.params['perPage'] = 1000
|
163
|
+
end
|
164
|
+
|
165
|
+
# Filter for users without avatars
|
166
|
+
res.body['records'].each do |ext|
|
167
|
+
next unless ext['profileImage'].key? 'etag'
|
168
|
+
end
|
169
|
+
```
|
170
|
+
|
171
|
+
The above will work with up to 1000 users. For over 1000 users, you will need to either follow the `navigation.nextPage` property yourself or use the `RingCentralSdk::REST::Cache::Extensions` gem. `RingCentral::Avatars` uses the extension cache similar to the following:
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
# Load the cache
|
175
|
+
cache = RingCentralSdk::REST::Cache::Extensions.new client
|
176
|
+
cache.retrieve_all
|
177
|
+
|
178
|
+
# Cycle through the users
|
179
|
+
cache.extensions_hash.each do |ext_id, ext|
|
180
|
+
next unless ext['profileImage'].key? 'etag'
|
181
|
+
end
|
182
|
+
```
|
183
|
+
|
184
|
+
### Creating the default image
|
185
|
+
|
186
|
+
The default image can be created in one of several ways that including:
|
187
|
+
|
188
|
+
1. User initials, like Gmail, Office 365, etc.
|
189
|
+
2. Identicons, like GitHub, Stack Overflow, Wordpress, etc.
|
190
|
+
|
191
|
+
Both of these are supported directly within `ringcentral-avatars` using `avatarly` and `ruby_identicon` to generate default images. They also both generate blobs:
|
192
|
+
|
193
|
+
```ruby
|
194
|
+
# Using Initials
|
195
|
+
require 'avatarly'
|
196
|
+
blob = Avatarly.generate_avatar 'AZ'
|
197
|
+
|
198
|
+
# Using Identicons
|
199
|
+
require 'ruby_identicon'
|
200
|
+
blob = RubyIdenticon.create 'AZ'
|
201
|
+
```
|
202
|
+
|
203
|
+
More information can be found for these particular libraries:
|
204
|
+
|
205
|
+
* [`avatarly`](https://rubygems.org/gems/avatarly)
|
206
|
+
* [`ruby_identicon`](https://rubygems.org/gems/ruby_identicon)
|
207
|
+
|
208
|
+
### Identifying auto-generated default images
|
209
|
+
|
210
|
+
Sometimes there may be a need to identify and overwrite only auto-generated images. The code above will not do this because auto-generated images will have an `etag` like user submitted images.
|
211
|
+
|
212
|
+
To resolve this, you can add a tag to the image itself which means each image will need to be retrieved and inspected. `ringcentral-avatars` supports setting PNG metadata attributes that can be used to identify default avatars. This can be done using [`chunky_png`](https://rubygems.org/gems/chunky_png):
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
require 'chunky_png'
|
216
|
+
|
217
|
+
img = ChunkyPNG::Image.from_blob blob
|
218
|
+
img.metadata = { 'Description' => 'My Default Avatar' }
|
219
|
+
blob = img.to_blob
|
220
|
+
```
|
221
|
+
|
222
|
+
For JPEG, Exif can be implemented and is left as a future exercise.
|
223
|
+
|
224
|
+
### Wrapping it up
|
225
|
+
|
226
|
+
Much of this code has been implemented in the [`ringcentral-avatars`](https://rubygems.org/gems/ringcentral-avatars) gem and can be inspected in the gem's source code on GitHub. To use the gem to update your avatar, you can simply use the following commands:
|
227
|
+
|
228
|
+
```ruby
|
229
|
+
require 'ringcentral-avatars'
|
230
|
+
require 'ringcentral_sdk'
|
231
|
+
|
232
|
+
client = RingCentralSdk.new [...]
|
233
|
+
|
234
|
+
avatars = RingCentral::Avatars.new client # Default options
|
235
|
+
avatars = RingCentral::Avatars.new client, avatar_opts: {font_size: 275} # Avatarly options
|
236
|
+
|
237
|
+
avatars.create_defaults # create default avatars only
|
238
|
+
avatars.create_all # create all avatars, overwriting existing avatars
|
239
|
+
|
240
|
+
avatars.create_mine # does not overwrite existing user avatar
|
241
|
+
avatars.create_mine overwrite: true # overwrite existing user avatar
|
242
|
+
|
243
|
+
avatars.create_avatar ext # create a default for an extension hash
|
244
|
+
avatars.create_avatar ext, overwrite: true # overwrite existing for an extension hash
|
245
|
+
```
|
246
|
+
|
247
|
+
## Notes
|
248
|
+
|
249
|
+
### Throttling
|
250
|
+
|
251
|
+
When retrieving and uploading many images, your application can be throttled if it is making API requests above the rate specified in your usage plan. To resolve this, you can make calls one at a time and examine the response status and headers. For example:
|
252
|
+
|
253
|
+
1. A `429` status will indicate your app is being throttled. It should wait the specified amount of seconds specified in the `Retry-After` header and then retry the request.
|
254
|
+
2. A `X-Rate-Limit-Remaining` of `0` will indicate that the app has used up its allotment of API calls for the window and should wait the amount of seconds specified in the `X-Rate-Limit-Window` header.
|
255
|
+
|
256
|
+
Pseudo code for this is:
|
257
|
+
|
258
|
+
```ruby
|
259
|
+
if res.status == 429
|
260
|
+
// Wait for the specified time
|
261
|
+
sleep res.headers['Retry-After'].to_i
|
262
|
+
// Retry the request
|
263
|
+
client.http.get ...
|
264
|
+
elsif res.headers['X-Rate-Limit-Remaining'].to_i == 0
|
265
|
+
sleep res.headers['X-Rate-Limit-Window'].to_i
|
266
|
+
end
|
267
|
+
```
|
268
|
+
|
269
|
+
In a future release, this type of throttling should be automatically built into the Ruby SDK.
|
270
|
+
|
271
|
+
## Summary
|
272
|
+
|
273
|
+
The RingCentral Profile Image API is a useful way to upload corporate address book images individually and administratively. It can be used for exciting use cases like directory sync, upload from mobile phones and setting default images.
|
274
|
+
|
275
|
+
If you have questions on this API or this gem, please feel free to ask on the following sites:
|
276
|
+
|
277
|
+
* [Stack Overflow](http://stackoverflow.com/questions/tagged/ringcentral)
|
278
|
+
* [GitHub](https://github.com/ringcentral-ruby/ringcentral-avatars-ruby/issues)
|
data/README.md
CHANGED
@@ -4,6 +4,7 @@ RingCentral Avatars
|
|
4
4
|
[![Gem Version][gem-version-svg]][gem-version-link]
|
5
5
|
[![Build Status][build-status-svg]][build-status-link]
|
6
6
|
[![Dependency Status][dependency-status-svg]][dependency-status-link]
|
7
|
+
[![Codacy Badge][codacy-svg]][codacy-link]
|
7
8
|
[![Code Climate][codeclimate-status-svg]][codeclimate-status-link]
|
8
9
|
[![Scrutinizer Code Quality][scrutinizer-status-svg]][scrutinizer-status-link]
|
9
10
|
[![Downloads][downloads-svg]][downloads-link]
|
@@ -49,7 +50,7 @@ $ gem install ringcentral-avatars
|
|
49
50
|
require 'ringcentral-avatars'
|
50
51
|
require 'ringcentral_sdk'
|
51
52
|
|
52
|
-
client = RingCentralSdk.new [...]
|
53
|
+
client = RingCentralSdk::REST::Client.new [...]
|
53
54
|
|
54
55
|
avatars = RingCentral::Avatars.new client # Default options
|
55
56
|
avatars = RingCentral::Avatars.new client, avatar_opts: {font_size: 275} # Avatarly options
|
@@ -64,7 +65,8 @@ avatars.create_avatar ext # create a default for an extension h
|
|
64
65
|
avatars.create_avatar ext, overwrite: true # overwrite existing for an extension hash
|
65
66
|
```
|
66
67
|
|
67
|
-
|
68
|
+
* For batch operations, consider using [RingCentral SDK's] `config.retry = true` option for automatic handling of rate limiting using 429 headers.
|
69
|
+
* For avatar customization, see [Avatarly](https://github.com/lucek/avatarly) options. The default avatar size is `600`.
|
68
70
|
|
69
71
|
### Adding PNG Metadata
|
70
72
|
|
@@ -103,10 +105,36 @@ $ ruby get_avatar.rb
|
|
103
105
|
$ ruby avatar_info.rb
|
104
106
|
```
|
105
107
|
|
108
|
+
## Test Uploads
|
109
|
+
|
110
|
+
The `scripts` directory contains test images for `png`, `jpg`, and `gif` file types: `test_filetype_png.png`, `test_filetype_jpg.jpg`, and `test_filetype_gif.gif`.
|
111
|
+
|
112
|
+
### Test Upload Script
|
113
|
+
|
114
|
+
This repo also includes test scripts to upload PNG, JPG, and GIF format images.
|
115
|
+
|
116
|
+
```bash
|
117
|
+
$ cd ringcentral-avatars-ruby/scripts
|
118
|
+
$ vi .env
|
119
|
+
$ ruby test_filetype.rb --filetype=png
|
120
|
+
$ ruby test_filetype.rb --filetype=jpg
|
121
|
+
$ ruby test_filetype.rb --filetype=gif
|
122
|
+
```
|
123
|
+
|
124
|
+
### Test cURL Command
|
125
|
+
|
126
|
+
```bash
|
127
|
+
$ curl -v -H 'Authorization: Bearer <MY_ACCESS_TOKEN>' -F image=@test_filetype_gif.gif 'https://platform.devtest.ringcentral.com/restapi/v1.0/account/~/extension/~/profile-image'
|
128
|
+
```
|
129
|
+
|
106
130
|
### Change Log
|
107
131
|
|
108
132
|
See [CHANGELOG.md](CHANGELOG.md)
|
109
133
|
|
134
|
+
## Credits
|
135
|
+
|
136
|
+
Test icons files are adapted from freeware [Filetype Icons](http://www.iconarchive.com/show/filetype-icons-by-graphicloads.html) by [GraphicLoads](http://www.iconarchive.com/artist/graphicloads.html).
|
137
|
+
|
110
138
|
## Links
|
111
139
|
|
112
140
|
Project Repo
|
@@ -145,6 +173,8 @@ RingCentral Avatars © 2016 by John Wang
|
|
145
173
|
[downloads-link]: https://rubygems.org/gems/ringcentral-avatars
|
146
174
|
[build-status-svg]: https://api.travis-ci.org/ringcentral-ruby/ringcentral-avatars-ruby.svg?branch=master
|
147
175
|
[build-status-link]: https://travis-ci.org/ringcentral-ruby/ringcentral-avatars-ruby
|
176
|
+
[codacy-svg]: https://api.codacy.com/project/badge/Grade/e82eac58a42d4463885627f78098bbb0
|
177
|
+
[codacy-link]: https://www.codacy.com/app/johncwang/ringcentral-avatars-ruby
|
148
178
|
[coverage-status-svg]: https://coveralls.io/repos/ringcentral-ruby/ringcentral-avatars-ruby/badge.svg?branch=master
|
149
179
|
[coverage-status-link]: https://coveralls.io/r/ringcentral-ruby/ringcentral-avatars-ruby?branch=master
|
150
180
|
[dependency-status-svg]: https://gemnasium.com/ringcentral-ruby/ringcentral-avatars-ruby.svg
|
data/lib/ringcentral-avatars.rb
CHANGED
@@ -3,6 +3,8 @@ require 'chunky_png'
|
|
3
3
|
require 'ruby_identicon'
|
4
4
|
|
5
5
|
require 'faraday'
|
6
|
+
require 'faraday_middleware-request-retry'
|
7
|
+
require 'logger'
|
6
8
|
require 'mime/types'
|
7
9
|
require 'ringcentral_sdk'
|
8
10
|
require 'tempfile'
|
@@ -11,16 +13,17 @@ module RingCentral
|
|
11
13
|
module Avatars
|
12
14
|
class Creator
|
13
15
|
DEFAULT_SIZE = 600
|
14
|
-
DEFAULT_FORMAT = 'png'
|
16
|
+
DEFAULT_FORMAT = 'png'.freeze
|
15
17
|
PNG_DEFAULT_METADATA = {
|
16
18
|
'Description' => 'RingCentral Default Avatar'
|
17
|
-
}
|
19
|
+
}.freeze
|
18
20
|
|
19
21
|
attr_accessor :avatar_opts
|
20
22
|
attr_accessor :avatars
|
21
23
|
attr_accessor :client
|
22
24
|
attr_accessor :extensions
|
23
25
|
attr_accessor :png_metadata
|
26
|
+
attr_accessor :retry
|
24
27
|
|
25
28
|
##
|
26
29
|
# Requires RingCentralSdk instance
|
@@ -30,12 +33,16 @@ module RingCentral
|
|
30
33
|
if !opts.key?(:initials_opts) && opts.key?(:avatar_opts)
|
31
34
|
opts[:initials_opts] = opts[:avatar_opts]
|
32
35
|
end
|
33
|
-
if opts.key
|
36
|
+
if opts.key? :png_metadata
|
34
37
|
opts[:png_metadata] = PNG_DEFAULT_METADATA.merge(opts[:png_metadata])
|
35
38
|
else
|
36
39
|
opts[:png_metadata] = PNG_DEFAULT_METADATA
|
37
40
|
end
|
41
|
+
opts[:logger] = @client.config.logger
|
42
|
+
@retry = opts.key?(:retry) && opts[:retry] ? true : false
|
43
|
+
opts[:retry] = @retry
|
38
44
|
@avatars = RingCentral::Avatars::MultiAvatar.new opts
|
45
|
+
@retry_util = FaradayMiddleware::Request::RetryUtil.new logger: client.config.logger
|
39
46
|
load_extensions
|
40
47
|
end
|
41
48
|
|
@@ -52,7 +59,7 @@ module RingCentral
|
|
52
59
|
# Defaults to overwriting existing avatar
|
53
60
|
def create_all(opts = {})
|
54
61
|
opts[:overwrite] = true unless opts.key?(:overwrite)
|
55
|
-
@extensions.extensions_hash.each do |
|
62
|
+
@extensions.extensions_hash.each do |_ext_id, ext|
|
56
63
|
create_avatar ext, opts
|
57
64
|
end
|
58
65
|
load_extensions
|
@@ -62,10 +69,13 @@ module RingCentral
|
|
62
69
|
# Convenience method for creating avatar for authorized extension
|
63
70
|
# Defaults to not overwriting existing avatar
|
64
71
|
def create_mine(opts = {})
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
72
|
+
try_req = true
|
73
|
+
while try_req
|
74
|
+
res_ext = @client.http.get 'account/~/extension/~'
|
75
|
+
try_req = retry_status res_ext
|
76
|
+
end
|
77
|
+
res_avt = create_avatar res_ext.body, opts
|
78
|
+
res_avt
|
69
79
|
end
|
70
80
|
|
71
81
|
##
|
@@ -73,16 +83,29 @@ module RingCentral
|
|
73
83
|
# Defaults to not overwriting existing avatar
|
74
84
|
def create_avatar(ext, opts = {})
|
75
85
|
opts[:overwrite] = false unless opts.key?(:overwrite)
|
76
|
-
|
86
|
+
if avatar?(ext) && !opts[:overwrite]
|
87
|
+
return nil
|
88
|
+
end
|
77
89
|
url = "account/~/extension/#{ext['id']}/profile-image"
|
78
|
-
|
79
|
-
|
90
|
+
res_avt = nil
|
91
|
+
try_req = true
|
92
|
+
while try_req
|
93
|
+
image = @avatars.avatar_faraday_uploadio ext['name']
|
94
|
+
res_avt = @client.http.put url, image: image
|
95
|
+
try_req = retry_status res_avt
|
96
|
+
end
|
97
|
+
res_avt
|
98
|
+
end
|
99
|
+
|
100
|
+
def retry_status(res)
|
101
|
+
return false unless @retry
|
102
|
+
@retry_util.retry_status(res.status, res.headers['Retry-After'])
|
80
103
|
end
|
81
104
|
|
82
105
|
##
|
83
106
|
# Determines if extension has an existing avatar
|
84
107
|
# Checks by looking for the presence of the `etag` property
|
85
|
-
def
|
108
|
+
def avatar?(ext)
|
86
109
|
ext['profileImage'].key?('etag') ? true : false
|
87
110
|
end
|
88
111
|
|
@@ -124,23 +147,24 @@ end
|
|
124
147
|
module RingCentral
|
125
148
|
module Avatars
|
126
149
|
class MultiAvatar
|
127
|
-
DEFAULT_STYLE = 'initials'
|
150
|
+
DEFAULT_STYLE = 'initials'.freeze
|
128
151
|
AVATARLY_DEFAULTS = {
|
129
152
|
size: 600,
|
130
153
|
format: 'png'
|
131
|
-
}
|
154
|
+
}.freeze
|
132
155
|
IDENTICON_DEFAULTS = {
|
133
156
|
grid_size: 5,
|
134
157
|
square_size: 70,
|
135
158
|
background_color: 0xffffffff
|
136
|
-
}
|
137
|
-
IDENTICON_DEFAULT_FORMAT = 'png'
|
159
|
+
}.freeze
|
160
|
+
IDENTICON_DEFAULT_FORMAT = 'png'.freeze
|
138
161
|
|
139
162
|
def initialize(opts = {})
|
140
163
|
@avatarly_opts = inflate_avatarly_opts opts[:initials_opts]
|
141
164
|
@identicon_opts = inflate_identicon_opts opts[:identicon_opts]
|
142
165
|
@style = opts.key?(:style) ? opts[:style] : DEFAULT_STYLE
|
143
166
|
@png_metadata = opts.key?(:png_metadata) ? opts[:png_metadata] : {}
|
167
|
+
@logger = opts.key?(:logger) ? opts[:logger] : Logger.new(STDOUT)
|
144
168
|
end
|
145
169
|
|
146
170
|
def inflate_avatarly_opts(avatarly_opts = {})
|
@@ -155,7 +179,7 @@ module RingCentral
|
|
155
179
|
|
156
180
|
def avatar_blob(text, style = nil)
|
157
181
|
style = @style if style.nil?
|
158
|
-
blob =
|
182
|
+
blob = style == 'initials' \
|
159
183
|
? Avatarly.generate_avatar(text, @avatarly_opts) \
|
160
184
|
: RubyIdenticon.create(text, @identicon_opts)
|
161
185
|
inflate_avatar_blob_png blob
|
@@ -179,7 +203,8 @@ module RingCentral
|
|
179
203
|
|
180
204
|
def avatar_faraday_uploadio(text, style = nil)
|
181
205
|
file = avatar_temp_file text, style
|
182
|
-
|
206
|
+
@logger.debug "Building Avatar Temp File: #{file.path}"
|
207
|
+
Faraday::UploadIO.new file.path, avatar_mime_type
|
183
208
|
end
|
184
209
|
|
185
210
|
def avatar_format
|
@@ -188,7 +213,7 @@ module RingCentral
|
|
188
213
|
|
189
214
|
def avatar_mime_type
|
190
215
|
types = MIME::Types.type_for avatar_format
|
191
|
-
if types.
|
216
|
+
if types.empty?
|
192
217
|
raise "Unknown avatar format: #{avatar_format}"
|
193
218
|
end
|
194
219
|
types[0].to_s
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ringcentral-avatars
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Wang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: avatarly
|
@@ -96,20 +96,20 @@ dependencies:
|
|
96
96
|
requirements:
|
97
97
|
- - "~>"
|
98
98
|
- !ruby/object:Gem::Version
|
99
|
-
version: '
|
99
|
+
version: '2'
|
100
100
|
- - ">="
|
101
101
|
- !ruby/object:Gem::Version
|
102
|
-
version:
|
102
|
+
version: 2.0.2
|
103
103
|
type: :runtime
|
104
104
|
prerelease: false
|
105
105
|
version_requirements: !ruby/object:Gem::Requirement
|
106
106
|
requirements:
|
107
107
|
- - "~>"
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: '
|
109
|
+
version: '2'
|
110
110
|
- - ">="
|
111
111
|
- !ruby/object:Gem::Version
|
112
|
-
version:
|
112
|
+
version: 2.0.2
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: ruby_identicon
|
115
115
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,14 +164,14 @@ dependencies:
|
|
164
164
|
requirements:
|
165
165
|
- - "~>"
|
166
166
|
- !ruby/object:Gem::Version
|
167
|
-
version: '
|
167
|
+
version: '12'
|
168
168
|
type: :development
|
169
169
|
prerelease: false
|
170
170
|
version_requirements: !ruby/object:Gem::Requirement
|
171
171
|
requirements:
|
172
172
|
- - "~>"
|
173
173
|
- !ruby/object:Gem::Version
|
174
|
-
version: '
|
174
|
+
version: '12'
|
175
175
|
- !ruby/object:Gem::Dependency
|
176
176
|
name: simplecov
|
177
177
|
requirement: !ruby/object:Gem::Requirement
|
@@ -208,7 +208,9 @@ extra_rdoc_files: []
|
|
208
208
|
files:
|
209
209
|
- CHANGELOG.md
|
210
210
|
- Gemfile
|
211
|
+
- Gemfile.lock
|
211
212
|
- LICENSE.md
|
213
|
+
- NEWS.md
|
212
214
|
- README.md
|
213
215
|
- Rakefile
|
214
216
|
- lib/ringcentral-avatars.rb
|
@@ -233,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
233
235
|
version: '0'
|
234
236
|
requirements: []
|
235
237
|
rubyforge_project:
|
236
|
-
rubygems_version: 2.
|
238
|
+
rubygems_version: 2.5.2
|
237
239
|
signing_key:
|
238
240
|
specification_version: 4
|
239
241
|
summary: RingCentral library for auto-generating Gmail style avatars
|