@webex/internal-plugin-avatar 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/.eslintrc.js +6 -6
- package/README.md +42 -42
- package/babel.config.js +3 -3
- package/dist/avatar-url-batcher.js +2 -2
- package/dist/avatar-url-batcher.js.map +1 -1
- package/dist/avatar-url-store.js +35 -35
- package/dist/avatar-url-store.js.map +1 -1
- package/dist/avatar.js +15 -15
- package/dist/avatar.js.map +1 -1
- package/dist/config.js +14 -14
- package/dist/config.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/jest.config.js +3 -3
- package/package.json +19 -18
- package/process +1 -1
- package/src/avatar-url-batcher.js +124 -124
- package/src/avatar-url-store.js +111 -111
- package/src/avatar.js +148 -148
- package/src/config.js +33 -33
- package/src/index.js +17 -17
- package/test/integration/spec/avatar.js +82 -82
- package/test/unit/spec/avatar-url-batcher.js +84 -84
- package/test/unit/spec/avatar-url-store.js +154 -154
- package/test/unit/spec/avatar.js +1574 -1574
|
@@ -1,124 +1,124 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {Batcher} from '@webex/webex-core';
|
|
6
|
-
import {uniq} from 'lodash';
|
|
7
|
-
|
|
8
|
-
const AvatarUrlBatcher = Batcher.extend({
|
|
9
|
-
namespace: 'Avatar',
|
|
10
|
-
|
|
11
|
-
handleHttpSuccess(res) {
|
|
12
|
-
// eslint-disable-next-line arrow-body-style
|
|
13
|
-
return Promise.all(
|
|
14
|
-
res.options.body.map((req) => {
|
|
15
|
-
return Promise.all(
|
|
16
|
-
req.sizes.map((size) => {
|
|
17
|
-
const response = (res.body[req.uuid] && res.body[req.uuid][size]) || undefined;
|
|
18
|
-
|
|
19
|
-
return this.acceptItem({
|
|
20
|
-
response,
|
|
21
|
-
uuid: req.uuid,
|
|
22
|
-
size,
|
|
23
|
-
});
|
|
24
|
-
})
|
|
25
|
-
);
|
|
26
|
-
})
|
|
27
|
-
);
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
handleHttpError(reason) {
|
|
31
|
-
const msg = reason.message || reason.body || reason;
|
|
32
|
-
|
|
33
|
-
// avoid multiple => on same line
|
|
34
|
-
// eslint-disable-next-line arrow-body-style
|
|
35
|
-
return Promise.all(
|
|
36
|
-
reason.options.body.map((item) => {
|
|
37
|
-
return Promise.all(
|
|
38
|
-
item.sizes.map((size) =>
|
|
39
|
-
this.getDeferredForRequest({
|
|
40
|
-
uuid: item.uuid,
|
|
41
|
-
size,
|
|
42
|
-
})
|
|
43
|
-
// I don't see a better way to do this than with an additional nesting
|
|
44
|
-
// eslint-disable-next-line max-nested-callbacks
|
|
45
|
-
.then((defer) => defer.reject(msg instanceof Error ? msg : new Error(msg)))
|
|
46
|
-
)
|
|
47
|
-
);
|
|
48
|
-
})
|
|
49
|
-
);
|
|
50
|
-
},
|
|
51
|
-
|
|
52
|
-
didItemFail(item) {
|
|
53
|
-
if (item.response) {
|
|
54
|
-
if (item.size !== item.response.size) {
|
|
55
|
-
this.logger.warn(`Avatar: substituted size "${item.response.size}" for "${item.size}"`);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return Promise.resolve(false);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return Promise.resolve(true);
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
handleItemFailure(item) {
|
|
65
|
-
return this.getDeferredForRequest(item).then((defer) => {
|
|
66
|
-
defer.reject(new Error(item.response || 'Failed to retrieve avatar'));
|
|
67
|
-
});
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
handleItemSuccess(item) {
|
|
71
|
-
return this.getDeferredForResponse(item).then((defer) =>
|
|
72
|
-
defer.resolve({
|
|
73
|
-
hasDefaultAvatar: item.response.defaultAvatar,
|
|
74
|
-
uuid: item.uuid,
|
|
75
|
-
size: item.size,
|
|
76
|
-
url: item.response.url,
|
|
77
|
-
})
|
|
78
|
-
);
|
|
79
|
-
},
|
|
80
|
-
|
|
81
|
-
fingerprintRequest(item) {
|
|
82
|
-
return Promise.resolve(`${item.uuid}-${item.size}`);
|
|
83
|
-
},
|
|
84
|
-
|
|
85
|
-
fingerprintResponse(item) {
|
|
86
|
-
return Promise.resolve(`${item.uuid}-${item.size}`);
|
|
87
|
-
},
|
|
88
|
-
|
|
89
|
-
prepareRequest(queue) {
|
|
90
|
-
const map = queue.reduce((m, item) => {
|
|
91
|
-
let o = m.get(item.uuid);
|
|
92
|
-
|
|
93
|
-
if (!o) {
|
|
94
|
-
o = [];
|
|
95
|
-
m.set(item.uuid, o);
|
|
96
|
-
}
|
|
97
|
-
o.push(item.size);
|
|
98
|
-
|
|
99
|
-
return m;
|
|
100
|
-
}, new Map());
|
|
101
|
-
|
|
102
|
-
const payload = [];
|
|
103
|
-
|
|
104
|
-
map.forEach((value, key) => {
|
|
105
|
-
payload.push({
|
|
106
|
-
uuid: key,
|
|
107
|
-
sizes: uniq(value),
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
return Promise.resolve(payload);
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
submitHttpRequest(payload) {
|
|
115
|
-
return this.webex.request({
|
|
116
|
-
method: 'POST',
|
|
117
|
-
api: 'avatar',
|
|
118
|
-
resource: 'profiles/urls',
|
|
119
|
-
body: payload,
|
|
120
|
-
});
|
|
121
|
-
},
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
export default AvatarUrlBatcher;
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {Batcher} from '@webex/webex-core';
|
|
6
|
+
import {uniq} from 'lodash';
|
|
7
|
+
|
|
8
|
+
const AvatarUrlBatcher = Batcher.extend({
|
|
9
|
+
namespace: 'Avatar',
|
|
10
|
+
|
|
11
|
+
handleHttpSuccess(res) {
|
|
12
|
+
// eslint-disable-next-line arrow-body-style
|
|
13
|
+
return Promise.all(
|
|
14
|
+
res.options.body.map((req) => {
|
|
15
|
+
return Promise.all(
|
|
16
|
+
req.sizes.map((size) => {
|
|
17
|
+
const response = (res.body[req.uuid] && res.body[req.uuid][size]) || undefined;
|
|
18
|
+
|
|
19
|
+
return this.acceptItem({
|
|
20
|
+
response,
|
|
21
|
+
uuid: req.uuid,
|
|
22
|
+
size,
|
|
23
|
+
});
|
|
24
|
+
})
|
|
25
|
+
);
|
|
26
|
+
})
|
|
27
|
+
);
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
handleHttpError(reason) {
|
|
31
|
+
const msg = reason.message || reason.body || reason;
|
|
32
|
+
|
|
33
|
+
// avoid multiple => on same line
|
|
34
|
+
// eslint-disable-next-line arrow-body-style
|
|
35
|
+
return Promise.all(
|
|
36
|
+
reason.options.body.map((item) => {
|
|
37
|
+
return Promise.all(
|
|
38
|
+
item.sizes.map((size) =>
|
|
39
|
+
this.getDeferredForRequest({
|
|
40
|
+
uuid: item.uuid,
|
|
41
|
+
size,
|
|
42
|
+
})
|
|
43
|
+
// I don't see a better way to do this than with an additional nesting
|
|
44
|
+
// eslint-disable-next-line max-nested-callbacks
|
|
45
|
+
.then((defer) => defer.reject(msg instanceof Error ? msg : new Error(msg)))
|
|
46
|
+
)
|
|
47
|
+
);
|
|
48
|
+
})
|
|
49
|
+
);
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
didItemFail(item) {
|
|
53
|
+
if (item.response) {
|
|
54
|
+
if (item.size !== item.response.size) {
|
|
55
|
+
this.logger.warn(`Avatar: substituted size "${item.response.size}" for "${item.size}"`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return Promise.resolve(false);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return Promise.resolve(true);
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
handleItemFailure(item) {
|
|
65
|
+
return this.getDeferredForRequest(item).then((defer) => {
|
|
66
|
+
defer.reject(new Error(item.response || 'Failed to retrieve avatar'));
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
handleItemSuccess(item) {
|
|
71
|
+
return this.getDeferredForResponse(item).then((defer) =>
|
|
72
|
+
defer.resolve({
|
|
73
|
+
hasDefaultAvatar: item.response.defaultAvatar,
|
|
74
|
+
uuid: item.uuid,
|
|
75
|
+
size: item.size,
|
|
76
|
+
url: item.response.url,
|
|
77
|
+
})
|
|
78
|
+
);
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
fingerprintRequest(item) {
|
|
82
|
+
return Promise.resolve(`${item.uuid}-${item.size}`);
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
fingerprintResponse(item) {
|
|
86
|
+
return Promise.resolve(`${item.uuid}-${item.size}`);
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
prepareRequest(queue) {
|
|
90
|
+
const map = queue.reduce((m, item) => {
|
|
91
|
+
let o = m.get(item.uuid);
|
|
92
|
+
|
|
93
|
+
if (!o) {
|
|
94
|
+
o = [];
|
|
95
|
+
m.set(item.uuid, o);
|
|
96
|
+
}
|
|
97
|
+
o.push(item.size);
|
|
98
|
+
|
|
99
|
+
return m;
|
|
100
|
+
}, new Map());
|
|
101
|
+
|
|
102
|
+
const payload = [];
|
|
103
|
+
|
|
104
|
+
map.forEach((value, key) => {
|
|
105
|
+
payload.push({
|
|
106
|
+
uuid: key,
|
|
107
|
+
sizes: uniq(value),
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return Promise.resolve(payload);
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
submitHttpRequest(payload) {
|
|
115
|
+
return this.webex.request({
|
|
116
|
+
method: 'POST',
|
|
117
|
+
api: 'avatar',
|
|
118
|
+
resource: 'profiles/urls',
|
|
119
|
+
body: payload,
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
export default AvatarUrlBatcher;
|
package/src/avatar-url-store.js
CHANGED
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/* eslint-disable complexity */
|
|
6
|
-
|
|
7
|
-
import {patterns} from '@webex/common';
|
|
8
|
-
import {safeSetTimeout} from '@webex/common-timers';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* <uuid+size, {uuid, size, url}> map
|
|
12
|
-
*/
|
|
13
|
-
const urlByUuid = new WeakMap();
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @class AvatarUrlStore
|
|
17
|
-
*/
|
|
18
|
-
export default class AvatarUrlStore {
|
|
19
|
-
/**
|
|
20
|
-
* @constructs {AvatarUrlStore}
|
|
21
|
-
*/
|
|
22
|
-
constructor() {
|
|
23
|
-
urlByUuid.set(this, new Map());
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Get the URL associated with the given uuid and size.
|
|
28
|
-
*
|
|
29
|
-
* @param {object} item
|
|
30
|
-
* @param {string} item.uuid A user uuid
|
|
31
|
-
* @param {integer}item.size the requested size
|
|
32
|
-
* @returns {Promise<object>} Resolves to the avatar item {uuid, url, size, cacheControl}
|
|
33
|
-
* or Rejects on bad param, not in store
|
|
34
|
-
*
|
|
35
|
-
* @memberOf AvatarUrlStore
|
|
36
|
-
*/
|
|
37
|
-
get(item) {
|
|
38
|
-
if (!item) {
|
|
39
|
-
return Promise.reject(new Error('`item` is required'));
|
|
40
|
-
}
|
|
41
|
-
if (!item.uuid) {
|
|
42
|
-
return Promise.reject(new Error('`item.uuid` is required'));
|
|
43
|
-
}
|
|
44
|
-
if (!item.size) {
|
|
45
|
-
return Promise.reject(new Error('`item.size` is required'));
|
|
46
|
-
}
|
|
47
|
-
if (!patterns.uuid.test(item.uuid)) {
|
|
48
|
-
return Promise.reject(new Error('`item.uuid` does not appear to be a uuid'));
|
|
49
|
-
}
|
|
50
|
-
const ret = urlByUuid.get(this).get(`${item.uuid} - ${item.size}`);
|
|
51
|
-
|
|
52
|
-
if (ret) {
|
|
53
|
-
return Promise.resolve(ret);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return Promise.reject(new Error(`No URL found by specified id: ${JSON.stringify(item)}`));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Adds the given item to the store
|
|
61
|
-
* @param {Object} item
|
|
62
|
-
* @param {integer} item.cacheControl
|
|
63
|
-
* @param {integer} item.hasDefaultAvatar
|
|
64
|
-
* @param {integer} item.size
|
|
65
|
-
* @param {string} item.url
|
|
66
|
-
* @param {string} item.uuid
|
|
67
|
-
* @returns {Promise<object>} Resolves to the added avatar item or rejects on bad params
|
|
68
|
-
*/
|
|
69
|
-
add(item) {
|
|
70
|
-
if (!item) {
|
|
71
|
-
return Promise.reject(new Error('`item` is required'));
|
|
72
|
-
}
|
|
73
|
-
if (!item.uuid) {
|
|
74
|
-
return Promise.reject(new Error('`item.uuid` is required'));
|
|
75
|
-
}
|
|
76
|
-
if (!item.size) {
|
|
77
|
-
return Promise.reject(new Error('`item.size` is required'));
|
|
78
|
-
}
|
|
79
|
-
if (!patterns.uuid.test(item.uuid)) {
|
|
80
|
-
return Promise.reject(new Error('`item.uuid` does not appear to be a uuid'));
|
|
81
|
-
}
|
|
82
|
-
if (!item.url) {
|
|
83
|
-
return Promise.reject(new Error('`item.url` is required'));
|
|
84
|
-
}
|
|
85
|
-
if (!item.cacheControl) {
|
|
86
|
-
return Promise.reject(new Error('`item.cacheControl` is required'));
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
safeSetTimeout(this.remove.bind(this, item), item.cacheControl * 1000);
|
|
90
|
-
urlByUuid.get(this).set(`${item.uuid} - ${item.size}`, item);
|
|
91
|
-
|
|
92
|
-
return Promise.resolve(item);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Remove the URL associated with the uuid and size
|
|
97
|
-
* Remove urls of all sizes if size is not given
|
|
98
|
-
*
|
|
99
|
-
* @param {object} item
|
|
100
|
-
* @param {string} item.uuid The user unique id
|
|
101
|
-
* @param {integer} item.size The size of the avatar to remove
|
|
102
|
-
* @returns {Promise<true>}
|
|
103
|
-
*/
|
|
104
|
-
remove(item) {
|
|
105
|
-
const sizes = (item.size && [item.size]) || [40, 50, 80, 110, 135, 192, 640, 1600];
|
|
106
|
-
|
|
107
|
-
sizes.forEach((one) => urlByUuid.get(this).delete(`${item.uuid} - ${one}`));
|
|
108
|
-
|
|
109
|
-
return Promise.resolve(true);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/* eslint-disable complexity */
|
|
6
|
+
|
|
7
|
+
import {patterns} from '@webex/common';
|
|
8
|
+
import {safeSetTimeout} from '@webex/common-timers';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* <uuid+size, {uuid, size, url}> map
|
|
12
|
+
*/
|
|
13
|
+
const urlByUuid = new WeakMap();
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @class AvatarUrlStore
|
|
17
|
+
*/
|
|
18
|
+
export default class AvatarUrlStore {
|
|
19
|
+
/**
|
|
20
|
+
* @constructs {AvatarUrlStore}
|
|
21
|
+
*/
|
|
22
|
+
constructor() {
|
|
23
|
+
urlByUuid.set(this, new Map());
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get the URL associated with the given uuid and size.
|
|
28
|
+
*
|
|
29
|
+
* @param {object} item
|
|
30
|
+
* @param {string} item.uuid A user uuid
|
|
31
|
+
* @param {integer}item.size the requested size
|
|
32
|
+
* @returns {Promise<object>} Resolves to the avatar item {uuid, url, size, cacheControl}
|
|
33
|
+
* or Rejects on bad param, not in store
|
|
34
|
+
*
|
|
35
|
+
* @memberOf AvatarUrlStore
|
|
36
|
+
*/
|
|
37
|
+
get(item) {
|
|
38
|
+
if (!item) {
|
|
39
|
+
return Promise.reject(new Error('`item` is required'));
|
|
40
|
+
}
|
|
41
|
+
if (!item.uuid) {
|
|
42
|
+
return Promise.reject(new Error('`item.uuid` is required'));
|
|
43
|
+
}
|
|
44
|
+
if (!item.size) {
|
|
45
|
+
return Promise.reject(new Error('`item.size` is required'));
|
|
46
|
+
}
|
|
47
|
+
if (!patterns.uuid.test(item.uuid)) {
|
|
48
|
+
return Promise.reject(new Error('`item.uuid` does not appear to be a uuid'));
|
|
49
|
+
}
|
|
50
|
+
const ret = urlByUuid.get(this).get(`${item.uuid} - ${item.size}`);
|
|
51
|
+
|
|
52
|
+
if (ret) {
|
|
53
|
+
return Promise.resolve(ret);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return Promise.reject(new Error(`No URL found by specified id: ${JSON.stringify(item)}`));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Adds the given item to the store
|
|
61
|
+
* @param {Object} item
|
|
62
|
+
* @param {integer} item.cacheControl
|
|
63
|
+
* @param {integer} item.hasDefaultAvatar
|
|
64
|
+
* @param {integer} item.size
|
|
65
|
+
* @param {string} item.url
|
|
66
|
+
* @param {string} item.uuid
|
|
67
|
+
* @returns {Promise<object>} Resolves to the added avatar item or rejects on bad params
|
|
68
|
+
*/
|
|
69
|
+
add(item) {
|
|
70
|
+
if (!item) {
|
|
71
|
+
return Promise.reject(new Error('`item` is required'));
|
|
72
|
+
}
|
|
73
|
+
if (!item.uuid) {
|
|
74
|
+
return Promise.reject(new Error('`item.uuid` is required'));
|
|
75
|
+
}
|
|
76
|
+
if (!item.size) {
|
|
77
|
+
return Promise.reject(new Error('`item.size` is required'));
|
|
78
|
+
}
|
|
79
|
+
if (!patterns.uuid.test(item.uuid)) {
|
|
80
|
+
return Promise.reject(new Error('`item.uuid` does not appear to be a uuid'));
|
|
81
|
+
}
|
|
82
|
+
if (!item.url) {
|
|
83
|
+
return Promise.reject(new Error('`item.url` is required'));
|
|
84
|
+
}
|
|
85
|
+
if (!item.cacheControl) {
|
|
86
|
+
return Promise.reject(new Error('`item.cacheControl` is required'));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
safeSetTimeout(this.remove.bind(this, item), item.cacheControl * 1000);
|
|
90
|
+
urlByUuid.get(this).set(`${item.uuid} - ${item.size}`, item);
|
|
91
|
+
|
|
92
|
+
return Promise.resolve(item);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Remove the URL associated with the uuid and size
|
|
97
|
+
* Remove urls of all sizes if size is not given
|
|
98
|
+
*
|
|
99
|
+
* @param {object} item
|
|
100
|
+
* @param {string} item.uuid The user unique id
|
|
101
|
+
* @param {integer} item.size The size of the avatar to remove
|
|
102
|
+
* @returns {Promise<true>}
|
|
103
|
+
*/
|
|
104
|
+
remove(item) {
|
|
105
|
+
const sizes = (item.size && [item.size]) || [40, 50, 80, 110, 135, 192, 640, 1600];
|
|
106
|
+
|
|
107
|
+
sizes.forEach((one) => urlByUuid.get(this).delete(`${item.uuid} - ${one}`));
|
|
108
|
+
|
|
109
|
+
return Promise.resolve(true);
|
|
110
|
+
}
|
|
111
|
+
}
|