@webex/internal-plugin-user 2.59.2 → 2.59.3-next.1

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.
package/src/user.js CHANGED
@@ -1,466 +1,466 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- import {isArray} from 'lodash';
6
- import {deprecated, oneFlight, patterns, tap} from '@webex/common';
7
- import {persist, WebexPlugin, waitForValue} from '@webex/webex-core';
8
-
9
- import UserUUIDBatcher from './user-uuid-batcher';
10
- import UserUUIDStore from './user-uuid-store';
11
-
12
- /**
13
- * @class
14
- */
15
- const User = WebexPlugin.extend({
16
- namespace: 'User',
17
-
18
- children: {
19
- batcher: UserUUIDBatcher,
20
- },
21
-
22
- props: {
23
- /**
24
- * Indicates if the current user is known to have a password.
25
- * @instance
26
- * @memberof User
27
- * @type {boolean}
28
- */
29
- hasPassword: {
30
- default: false,
31
- type: 'boolean',
32
- },
33
- },
34
-
35
- session: {
36
- store: {
37
- default() {
38
- return new UserUUIDStore();
39
- },
40
- type: 'any',
41
- },
42
- },
43
-
44
- @waitForValue('@')
45
- /**
46
- * Activates a Webex user account and exchanges for user token.
47
- * @instance
48
- * @memberof User
49
- * @param {Object} options
50
- * @param {Object} options.confirmationCode (required -- optional if verification token is provided)
51
- * @param {Object} options.id (required -- optional if verification token is provided)
52
- * @param {Object} options.verificationToken (required -- optional if uuid and verification token provided)
53
- * @param {Object} options.email (required with verificationToken for Federation/global user)
54
- * @returns {Promise} Resolves with a userSession
55
- */
56
- activate(options = {}) {
57
- if (!(options.verificationToken || (options.confirmationCode && options.id))) {
58
- return Promise.reject(
59
- new Error(
60
- 'either options.verificationToken is required or both options.confirmationCode and options.id are required'
61
- )
62
- );
63
- }
64
-
65
- options.scope = this.webex.config.credentials.scope;
66
-
67
- // if we have options.email and options.verificationToken
68
- // and Federation flag is enabled, flag that we need to
69
- // lookup user's CI.
70
- const activateOptions = {...options};
71
-
72
- delete activateOptions.email;
73
-
74
- return this.request({
75
- uri: this.webex.config.credentials.activationUrl,
76
- method: 'POST',
77
- body: activateOptions,
78
- auth: {
79
- user: this.webex.config.credentials.client_id,
80
- pass: this.webex.config.credentials.client_secret,
81
- sendImmediately: true,
82
- },
83
- }).then((res) => {
84
- this.webex.credentials.set({supertoken: res.body.tokenData});
85
-
86
- return res.body;
87
- });
88
- },
89
-
90
- /**
91
- * Converts a user-identifying object to a uuid, perhaps by doing a network
92
- * lookup
93
- * @param {string|Object} user
94
- * @param {Object} options
95
- * @param {boolean} options.create if true, ensures the return UUID refers to
96
- * an existing user (rather than creating one deterministically based on email
97
- * address), even if that user must be created
98
- * @returns {Promise<string>}
99
- */
100
- asUUID(user, options) {
101
- if (!user) {
102
- return Promise.reject(new Error('`user` is required'));
103
- }
104
-
105
- if (isArray(user)) {
106
- return Promise.all(user.map((u) => this.asUUID(u, options)));
107
- }
108
-
109
- const id = this._extractUUID(user);
110
-
111
- if (!(options && options.force) && patterns.uuid.test(id)) {
112
- return Promise.resolve(id);
113
- }
114
-
115
- const email = this._extractEmailAddress(user);
116
-
117
- if (!patterns.email.test(email)) {
118
- return Promise.reject(new Error('Provided user object does not appear to identify a user'));
119
- }
120
-
121
- return this.getUUID(email, options);
122
- },
123
-
124
- /**
125
- * Requests a uuid from the api
126
- * @param {string} email
127
- * @param {Object} options
128
- * @param {boolean} options.create
129
- * @returns {Promise<string>}
130
- */
131
- fetchUUID(email, options) {
132
- return this.batcher
133
- .request({
134
- email,
135
- create: options && options.create,
136
- })
137
- .then((user) => this.recordUUID({emailAddress: email, ...user}).then(() => user.id));
138
- },
139
- /**
140
- * Generates One Time Password.
141
- * @instance
142
- * @param {Object} options
143
- * @param {string} options.email
144
- * @param {string} options.id
145
- * @returns {Promise}
146
- */
147
- generateOTP(options = {}) {
148
- if (!(options.email || options.id)) {
149
- return Promise.reject(new Error('One of `options.email` or `options.id` is required'));
150
- }
151
-
152
- return this.request({
153
- uri: this.webex.config.credentials.generateOtpUrl,
154
- method: 'POST',
155
- body: options,
156
- auth: {
157
- user: this.webex.config.credentials.client_id,
158
- pass: this.webex.config.credentials.client_secret,
159
- },
160
- }).then((res) => res.body);
161
- },
162
-
163
- /**
164
- * Fetches details about the current user
165
- * @returns {Promise<Object>}
166
- */
167
- get() {
168
- return this.request({
169
- service: 'conversation',
170
- resource: 'users',
171
- })
172
- .then((res) => res.body)
173
- .then(
174
- tap((user) =>
175
- this.recordUUID({
176
- id: user.id,
177
- // CI endpoints don't use the same user format as actors, so, email may
178
- // be in one of a few fields
179
- emailAddress: user.email || user.emailAddress,
180
- })
181
- )
182
- );
183
- },
184
-
185
- /**
186
- * Converts an email address to a uuid, perhaps by doing a network lookup
187
- * @param {string} email
188
- * @param {Object} options
189
- * @param {boolean} options.create
190
- * @returns {Promise<string>}
191
- */
192
- @oneFlight({keyFactory: (email, options) => email + String(options && options.create)})
193
- getUUID(email, options) {
194
- return this.store
195
- .getByEmail(email)
196
- .then((user) => {
197
- if (options && options.create && !user.userExists) {
198
- return Promise.reject(new Error('User for specified email cannot be confirmed to exist'));
199
- }
200
-
201
- if (!user.id) {
202
- return Promise.reject(new Error('No id recorded for specified user'));
203
- }
204
-
205
- return user.id;
206
- })
207
- .catch(() => this.fetchUUID(email, options));
208
- },
209
-
210
- @persist('@')
211
- initialize(...args) {
212
- return Reflect.apply(WebexPlugin.prototype.initialize, this, args);
213
- },
214
-
215
- /**
216
- * Caches the uuid for the specified email address
217
- * @param {Object} user
218
- * @param {string} user.id
219
- * @param {string} user.emailAddress
220
- * @returns {Promise}
221
- */
222
- recordUUID(user) {
223
- if (!user) {
224
- return Promise.reject(new Error('`user` is required'));
225
- }
226
-
227
- if (!user.id) {
228
- return Promise.reject(new Error('`user.id` is required'));
229
- }
230
-
231
- if (!patterns.uuid.test(user.id)) {
232
- return Promise.reject(new Error('`user.id` must be a uuid'));
233
- }
234
-
235
- if (!user.emailAddress) {
236
- return Promise.reject(new Error('`user.emailAddress` is required'));
237
- }
238
-
239
- if (!patterns.email.test(user.emailAddress)) {
240
- return Promise.reject(new Error('`user.emailAddress` must be an email address'));
241
- }
242
-
243
- return this.store.add(user);
244
- },
245
-
246
- @deprecated('Use User#verify()')
247
- register(...args) {
248
- return this.verify(...args);
249
- },
250
-
251
- /**
252
- * Updates a user with webex.
253
- * @param {Object} body
254
- * @private
255
- * @returns {Promise} Resolves with a response from PATCH request
256
- */
257
- _setUser(body) {
258
- return this.webex.credentials.getUserToken().then((token) =>
259
- this.request({
260
- uri: `${this.webex.config.credentials.setPasswordUrl}/${this.webex.internal.device.userId}`,
261
- method: 'PATCH',
262
- headers: {
263
- authorization: token.toString(),
264
- },
265
- body,
266
- })
267
- );
268
- },
269
-
270
- /**
271
- * Updates a user's password with webex.
272
- * @instance
273
- * @memberof User
274
- * @param {Object} options
275
- * @param {string} options.password (required)
276
- * @param {string} options.email (required when federation enabled)
277
- * @returns {Promise} Resolves with complete user object containing new password
278
- */
279
- setPassword(options) {
280
- options = options || {};
281
- if (!options.password) {
282
- return Promise.reject(new Error('`options.password` is required'));
283
- }
284
-
285
- return this._setUser({
286
- schemas: ['urn:scim:schemas:core:1.0', 'urn:scim:schemas:extension:cisco:commonidentity:1.0'],
287
- password: options.password,
288
- }).then((res) => {
289
- this.hasPassword = true;
290
-
291
- return res.body;
292
- });
293
- },
294
-
295
- /**
296
- * Updates a user's name with webex.
297
- * @instance
298
- * @memberof User
299
- * @param {string} givenName
300
- * @param {string} familyName
301
- * @param {string} displayName
302
- * @returns {Promise<Object>}
303
- */
304
- updateName({givenName, familyName, displayName} = {}) {
305
- if (!(givenName || familyName || displayName)) {
306
- return Promise.reject(
307
- new Error('One of `givenName` and `familyName` or `displayName` is required')
308
- );
309
- }
310
-
311
- return this._setUser({
312
- schemas: ['urn:scim:schemas:core:1.0', 'urn:scim:schemas:extension:cisco:commonidentity:1.0'],
313
- name: {givenName, familyName},
314
- displayName,
315
- }).then((res) => res.body);
316
- },
317
-
318
- /**
319
- * Updates the current user's display name
320
- * @param {Object} options
321
- * @param {string} options.displayName
322
- * @returns {Promise<Object>}
323
- */
324
- update(options) {
325
- options = options || {};
326
- if (!options.displayName) {
327
- return Promise.reject(new Error('`options.displayName` is required'));
328
- }
329
-
330
- return this.request({
331
- method: 'PATCH',
332
- service: 'conversation',
333
- resource: 'users/user',
334
- body: options,
335
- }).then((res) => res.body);
336
- },
337
-
338
- /**
339
- * Validated One Time Password.
340
- * @instance
341
- * @param {Object} options
342
- * @param {string} options.email
343
- * @param {string} options.id
344
- * @param {string} options.oneTimePassword
345
- * @returns {Promise}
346
- */
347
- validateOTP(options = {}) {
348
- if (!(options.email || options.id) || !options.oneTimePassword) {
349
- return Promise.reject(
350
- new Error(
351
- 'One of `options.email` or `options.id` and `options.oneTimePassword` are required'
352
- )
353
- );
354
- }
355
-
356
- options.scope = this.webex.config.credentials.scope;
357
-
358
- return this.request({
359
- uri: this.webex.config.credentials.validateOtpUrl,
360
- method: 'POST',
361
- body: options,
362
- auth: {
363
- user: this.webex.config.credentials.client_id,
364
- pass: this.webex.config.credentials.client_secret,
365
- },
366
- }).then((res) => {
367
- this.webex.credentials.set({supertoken: res.body.tokenData});
368
-
369
- return res.body;
370
- });
371
- },
372
-
373
- /**
374
- * Determines if the specified user needs to signup or can signin.
375
- * Triggers activation email if client credentials are used
376
- * @param {Object} options
377
- * @param {string} options.email (required)
378
- * @param {string} options.reqId required if need to check email status
379
- * @param {string} options.preloginId
380
- * @returns {Promise<Object>}
381
- */
382
- verify(options) {
383
- options = {...this.config.verifyDefaults, ...options};
384
- const {email} = options;
385
-
386
- if (!email) {
387
- return Promise.reject(new Error('`options.email` is required'));
388
- }
389
-
390
- return this.webex.internal.services
391
- .collectPreauthCatalog({email})
392
- .then(() => this.webex.credentials.getUserToken())
393
- .catch(() => this.webex.credentials.getClientToken())
394
- .then((token) =>
395
- this.request({
396
- service: 'atlas',
397
- resource: 'users/activations',
398
- method: 'POST',
399
- headers: {
400
- authorization: token.toString(),
401
- 'x-prelogin-userid': options.preloginId,
402
- },
403
- body: options,
404
- shouldRefreshAccessToken: false,
405
- })
406
- )
407
- .then((res) => {
408
- if (res.body.hasPassword || res.body.sso) {
409
- this.hasPassword = true;
410
- }
411
-
412
- return res.body;
413
- });
414
- },
415
-
416
- /**
417
- * If the passed-in lookupCI is true, retrieve the user's
418
- * CI from Atlas and return the URL's via a Promise.
419
- * Otherwise, return current CI in config via a Promise.
420
- * Useful in a Promise chain to retrieve the CI based on
421
- * conditions like Federation enabled, and suppresses sending
422
- * an additional email to the user, since this is just a
423
- * look-up.
424
- * @param {string} email (required)
425
- * @param {boolean} lookupCI (required)
426
- * @returns {Promise<Object>}
427
- */
428
- getUserCI(email, lookupCI) {
429
- if (lookupCI) {
430
- // call verify first to get the user's CI, but suppress sending another email
431
- const verifyOptions = {
432
- email,
433
- suppressEmail: true,
434
- };
435
-
436
- return this.verify(verifyOptions).then((res) => Promise.resolve(res.userEntities));
437
- }
438
-
439
- return Promise.resolve({
440
- idBrokerUrl: this.webex.config.credentials.idbroker.url,
441
- identityUrl: this.webex.config.credentials.identity.url,
442
- });
443
- },
444
-
445
- /**
446
- * Extracts the uuid from a user identifying object
447
- * @param {string|Object} user
448
- * @private
449
- * @returns {string}
450
- */
451
- _extractUUID(user) {
452
- return user.entryUUID || user.id || user;
453
- },
454
-
455
- /**
456
- * Extracts the email address from a user identifying object
457
- * @param {string|Object} user
458
- * @private
459
- * @returns {string}
460
- */
461
- _extractEmailAddress(user) {
462
- return user.email || user.emailAddress || user.entryEmail || user;
463
- },
464
- });
465
-
466
- export default User;
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {isArray} from 'lodash';
6
+ import {deprecated, oneFlight, patterns, tap} from '@webex/common';
7
+ import {persist, WebexPlugin, waitForValue} from '@webex/webex-core';
8
+
9
+ import UserUUIDBatcher from './user-uuid-batcher';
10
+ import UserUUIDStore from './user-uuid-store';
11
+
12
+ /**
13
+ * @class
14
+ */
15
+ const User = WebexPlugin.extend({
16
+ namespace: 'User',
17
+
18
+ children: {
19
+ batcher: UserUUIDBatcher,
20
+ },
21
+
22
+ props: {
23
+ /**
24
+ * Indicates if the current user is known to have a password.
25
+ * @instance
26
+ * @memberof User
27
+ * @type {boolean}
28
+ */
29
+ hasPassword: {
30
+ default: false,
31
+ type: 'boolean',
32
+ },
33
+ },
34
+
35
+ session: {
36
+ store: {
37
+ default() {
38
+ return new UserUUIDStore();
39
+ },
40
+ type: 'any',
41
+ },
42
+ },
43
+
44
+ @waitForValue('@')
45
+ /**
46
+ * Activates a Webex user account and exchanges for user token.
47
+ * @instance
48
+ * @memberof User
49
+ * @param {Object} options
50
+ * @param {Object} options.confirmationCode (required -- optional if verification token is provided)
51
+ * @param {Object} options.id (required -- optional if verification token is provided)
52
+ * @param {Object} options.verificationToken (required -- optional if uuid and verification token provided)
53
+ * @param {Object} options.email (required with verificationToken for Federation/global user)
54
+ * @returns {Promise} Resolves with a userSession
55
+ */
56
+ activate(options = {}) {
57
+ if (!(options.verificationToken || (options.confirmationCode && options.id))) {
58
+ return Promise.reject(
59
+ new Error(
60
+ 'either options.verificationToken is required or both options.confirmationCode and options.id are required'
61
+ )
62
+ );
63
+ }
64
+
65
+ options.scope = this.webex.config.credentials.scope;
66
+
67
+ // if we have options.email and options.verificationToken
68
+ // and Federation flag is enabled, flag that we need to
69
+ // lookup user's CI.
70
+ const activateOptions = {...options};
71
+
72
+ delete activateOptions.email;
73
+
74
+ return this.request({
75
+ uri: this.webex.config.credentials.activationUrl,
76
+ method: 'POST',
77
+ body: activateOptions,
78
+ auth: {
79
+ user: this.webex.config.credentials.client_id,
80
+ pass: this.webex.config.credentials.client_secret,
81
+ sendImmediately: true,
82
+ },
83
+ }).then((res) => {
84
+ this.webex.credentials.set({supertoken: res.body.tokenData});
85
+
86
+ return res.body;
87
+ });
88
+ },
89
+
90
+ /**
91
+ * Converts a user-identifying object to a uuid, perhaps by doing a network
92
+ * lookup
93
+ * @param {string|Object} user
94
+ * @param {Object} options
95
+ * @param {boolean} options.create if true, ensures the return UUID refers to
96
+ * an existing user (rather than creating one deterministically based on email
97
+ * address), even if that user must be created
98
+ * @returns {Promise<string>}
99
+ */
100
+ asUUID(user, options) {
101
+ if (!user) {
102
+ return Promise.reject(new Error('`user` is required'));
103
+ }
104
+
105
+ if (isArray(user)) {
106
+ return Promise.all(user.map((u) => this.asUUID(u, options)));
107
+ }
108
+
109
+ const id = this._extractUUID(user);
110
+
111
+ if (!(options && options.force) && patterns.uuid.test(id)) {
112
+ return Promise.resolve(id);
113
+ }
114
+
115
+ const email = this._extractEmailAddress(user);
116
+
117
+ if (!patterns.email.test(email)) {
118
+ return Promise.reject(new Error('Provided user object does not appear to identify a user'));
119
+ }
120
+
121
+ return this.getUUID(email, options);
122
+ },
123
+
124
+ /**
125
+ * Requests a uuid from the api
126
+ * @param {string} email
127
+ * @param {Object} options
128
+ * @param {boolean} options.create
129
+ * @returns {Promise<string>}
130
+ */
131
+ fetchUUID(email, options) {
132
+ return this.batcher
133
+ .request({
134
+ email,
135
+ create: options && options.create,
136
+ })
137
+ .then((user) => this.recordUUID({emailAddress: email, ...user}).then(() => user.id));
138
+ },
139
+ /**
140
+ * Generates One Time Password.
141
+ * @instance
142
+ * @param {Object} options
143
+ * @param {string} options.email
144
+ * @param {string} options.id
145
+ * @returns {Promise}
146
+ */
147
+ generateOTP(options = {}) {
148
+ if (!(options.email || options.id)) {
149
+ return Promise.reject(new Error('One of `options.email` or `options.id` is required'));
150
+ }
151
+
152
+ return this.request({
153
+ uri: this.webex.config.credentials.generateOtpUrl,
154
+ method: 'POST',
155
+ body: options,
156
+ auth: {
157
+ user: this.webex.config.credentials.client_id,
158
+ pass: this.webex.config.credentials.client_secret,
159
+ },
160
+ }).then((res) => res.body);
161
+ },
162
+
163
+ /**
164
+ * Fetches details about the current user
165
+ * @returns {Promise<Object>}
166
+ */
167
+ get() {
168
+ return this.request({
169
+ service: 'conversation',
170
+ resource: 'users',
171
+ })
172
+ .then((res) => res.body)
173
+ .then(
174
+ tap((user) =>
175
+ this.recordUUID({
176
+ id: user.id,
177
+ // CI endpoints don't use the same user format as actors, so, email may
178
+ // be in one of a few fields
179
+ emailAddress: user.email || user.emailAddress,
180
+ })
181
+ )
182
+ );
183
+ },
184
+
185
+ /**
186
+ * Converts an email address to a uuid, perhaps by doing a network lookup
187
+ * @param {string} email
188
+ * @param {Object} options
189
+ * @param {boolean} options.create
190
+ * @returns {Promise<string>}
191
+ */
192
+ @oneFlight({keyFactory: (email, options) => email + String(options && options.create)})
193
+ getUUID(email, options) {
194
+ return this.store
195
+ .getByEmail(email)
196
+ .then((user) => {
197
+ if (options && options.create && !user.userExists) {
198
+ return Promise.reject(new Error('User for specified email cannot be confirmed to exist'));
199
+ }
200
+
201
+ if (!user.id) {
202
+ return Promise.reject(new Error('No id recorded for specified user'));
203
+ }
204
+
205
+ return user.id;
206
+ })
207
+ .catch(() => this.fetchUUID(email, options));
208
+ },
209
+
210
+ @persist('@')
211
+ initialize(...args) {
212
+ return Reflect.apply(WebexPlugin.prototype.initialize, this, args);
213
+ },
214
+
215
+ /**
216
+ * Caches the uuid for the specified email address
217
+ * @param {Object} user
218
+ * @param {string} user.id
219
+ * @param {string} user.emailAddress
220
+ * @returns {Promise}
221
+ */
222
+ recordUUID(user) {
223
+ if (!user) {
224
+ return Promise.reject(new Error('`user` is required'));
225
+ }
226
+
227
+ if (!user.id) {
228
+ return Promise.reject(new Error('`user.id` is required'));
229
+ }
230
+
231
+ if (!patterns.uuid.test(user.id)) {
232
+ return Promise.reject(new Error('`user.id` must be a uuid'));
233
+ }
234
+
235
+ if (!user.emailAddress) {
236
+ return Promise.reject(new Error('`user.emailAddress` is required'));
237
+ }
238
+
239
+ if (!patterns.email.test(user.emailAddress)) {
240
+ return Promise.reject(new Error('`user.emailAddress` must be an email address'));
241
+ }
242
+
243
+ return this.store.add(user);
244
+ },
245
+
246
+ @deprecated('Use User#verify()')
247
+ register(...args) {
248
+ return this.verify(...args);
249
+ },
250
+
251
+ /**
252
+ * Updates a user with webex.
253
+ * @param {Object} body
254
+ * @private
255
+ * @returns {Promise} Resolves with a response from PATCH request
256
+ */
257
+ _setUser(body) {
258
+ return this.webex.credentials.getUserToken().then((token) =>
259
+ this.request({
260
+ uri: `${this.webex.config.credentials.setPasswordUrl}/${this.webex.internal.device.userId}`,
261
+ method: 'PATCH',
262
+ headers: {
263
+ authorization: token.toString(),
264
+ },
265
+ body,
266
+ })
267
+ );
268
+ },
269
+
270
+ /**
271
+ * Updates a user's password with webex.
272
+ * @instance
273
+ * @memberof User
274
+ * @param {Object} options
275
+ * @param {string} options.password (required)
276
+ * @param {string} options.email (required when federation enabled)
277
+ * @returns {Promise} Resolves with complete user object containing new password
278
+ */
279
+ setPassword(options) {
280
+ options = options || {};
281
+ if (!options.password) {
282
+ return Promise.reject(new Error('`options.password` is required'));
283
+ }
284
+
285
+ return this._setUser({
286
+ schemas: ['urn:scim:schemas:core:1.0', 'urn:scim:schemas:extension:cisco:commonidentity:1.0'],
287
+ password: options.password,
288
+ }).then((res) => {
289
+ this.hasPassword = true;
290
+
291
+ return res.body;
292
+ });
293
+ },
294
+
295
+ /**
296
+ * Updates a user's name with webex.
297
+ * @instance
298
+ * @memberof User
299
+ * @param {string} givenName
300
+ * @param {string} familyName
301
+ * @param {string} displayName
302
+ * @returns {Promise<Object>}
303
+ */
304
+ updateName({givenName, familyName, displayName} = {}) {
305
+ if (!(givenName || familyName || displayName)) {
306
+ return Promise.reject(
307
+ new Error('One of `givenName` and `familyName` or `displayName` is required')
308
+ );
309
+ }
310
+
311
+ return this._setUser({
312
+ schemas: ['urn:scim:schemas:core:1.0', 'urn:scim:schemas:extension:cisco:commonidentity:1.0'],
313
+ name: {givenName, familyName},
314
+ displayName,
315
+ }).then((res) => res.body);
316
+ },
317
+
318
+ /**
319
+ * Updates the current user's display name
320
+ * @param {Object} options
321
+ * @param {string} options.displayName
322
+ * @returns {Promise<Object>}
323
+ */
324
+ update(options) {
325
+ options = options || {};
326
+ if (!options.displayName) {
327
+ return Promise.reject(new Error('`options.displayName` is required'));
328
+ }
329
+
330
+ return this.request({
331
+ method: 'PATCH',
332
+ service: 'conversation',
333
+ resource: 'users/user',
334
+ body: options,
335
+ }).then((res) => res.body);
336
+ },
337
+
338
+ /**
339
+ * Validated One Time Password.
340
+ * @instance
341
+ * @param {Object} options
342
+ * @param {string} options.email
343
+ * @param {string} options.id
344
+ * @param {string} options.oneTimePassword
345
+ * @returns {Promise}
346
+ */
347
+ validateOTP(options = {}) {
348
+ if (!(options.email || options.id) || !options.oneTimePassword) {
349
+ return Promise.reject(
350
+ new Error(
351
+ 'One of `options.email` or `options.id` and `options.oneTimePassword` are required'
352
+ )
353
+ );
354
+ }
355
+
356
+ options.scope = this.webex.config.credentials.scope;
357
+
358
+ return this.request({
359
+ uri: this.webex.config.credentials.validateOtpUrl,
360
+ method: 'POST',
361
+ body: options,
362
+ auth: {
363
+ user: this.webex.config.credentials.client_id,
364
+ pass: this.webex.config.credentials.client_secret,
365
+ },
366
+ }).then((res) => {
367
+ this.webex.credentials.set({supertoken: res.body.tokenData});
368
+
369
+ return res.body;
370
+ });
371
+ },
372
+
373
+ /**
374
+ * Determines if the specified user needs to signup or can signin.
375
+ * Triggers activation email if client credentials are used
376
+ * @param {Object} options
377
+ * @param {string} options.email (required)
378
+ * @param {string} options.reqId required if need to check email status
379
+ * @param {string} options.preloginId
380
+ * @returns {Promise<Object>}
381
+ */
382
+ verify(options) {
383
+ options = {...this.config.verifyDefaults, ...options};
384
+ const {email} = options;
385
+
386
+ if (!email) {
387
+ return Promise.reject(new Error('`options.email` is required'));
388
+ }
389
+
390
+ return this.webex.internal.services
391
+ .collectPreauthCatalog({email})
392
+ .then(() => this.webex.credentials.getUserToken())
393
+ .catch(() => this.webex.credentials.getClientToken())
394
+ .then((token) =>
395
+ this.request({
396
+ service: 'atlas',
397
+ resource: 'users/activations',
398
+ method: 'POST',
399
+ headers: {
400
+ authorization: token.toString(),
401
+ 'x-prelogin-userid': options.preloginId,
402
+ },
403
+ body: options,
404
+ shouldRefreshAccessToken: false,
405
+ })
406
+ )
407
+ .then((res) => {
408
+ if (res.body.hasPassword || res.body.sso) {
409
+ this.hasPassword = true;
410
+ }
411
+
412
+ return res.body;
413
+ });
414
+ },
415
+
416
+ /**
417
+ * If the passed-in lookupCI is true, retrieve the user's
418
+ * CI from Atlas and return the URL's via a Promise.
419
+ * Otherwise, return current CI in config via a Promise.
420
+ * Useful in a Promise chain to retrieve the CI based on
421
+ * conditions like Federation enabled, and suppresses sending
422
+ * an additional email to the user, since this is just a
423
+ * look-up.
424
+ * @param {string} email (required)
425
+ * @param {boolean} lookupCI (required)
426
+ * @returns {Promise<Object>}
427
+ */
428
+ getUserCI(email, lookupCI) {
429
+ if (lookupCI) {
430
+ // call verify first to get the user's CI, but suppress sending another email
431
+ const verifyOptions = {
432
+ email,
433
+ suppressEmail: true,
434
+ };
435
+
436
+ return this.verify(verifyOptions).then((res) => Promise.resolve(res.userEntities));
437
+ }
438
+
439
+ return Promise.resolve({
440
+ idBrokerUrl: this.webex.config.credentials.idbroker.url,
441
+ identityUrl: this.webex.config.credentials.identity.url,
442
+ });
443
+ },
444
+
445
+ /**
446
+ * Extracts the uuid from a user identifying object
447
+ * @param {string|Object} user
448
+ * @private
449
+ * @returns {string}
450
+ */
451
+ _extractUUID(user) {
452
+ return user.entryUUID || user.id || user;
453
+ },
454
+
455
+ /**
456
+ * Extracts the email address from a user identifying object
457
+ * @param {string|Object} user
458
+ * @private
459
+ * @returns {string}
460
+ */
461
+ _extractEmailAddress(user) {
462
+ return user.email || user.emailAddress || user.entryEmail || user;
463
+ },
464
+ });
465
+
466
+ export default User;