@webex/plugin-messages 2.59.3-next.1 → 2.59.4

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/messages.js CHANGED
@@ -1,461 +1,461 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- import {
6
- SDK_EVENT,
7
- buildHydraMessageId,
8
- buildHydraPersonId,
9
- buildHydraRoomId,
10
- createEventEnvelope,
11
- getHydraClusterString,
12
- } from '@webex/common';
13
- import {Page, WebexPlugin} from '@webex/webex-core';
14
- import {cloneDeep, isArray} from 'lodash';
15
-
16
- const verbToType = {
17
- [SDK_EVENT.INTERNAL.ACTIVITY_VERB.SHARE]: SDK_EVENT.EXTERNAL.EVENT_TYPE.CREATED,
18
- [SDK_EVENT.INTERNAL.ACTIVITY_VERB.POST]: SDK_EVENT.EXTERNAL.EVENT_TYPE.CREATED,
19
- [SDK_EVENT.INTERNAL.ACTIVITY_VERB.DELETE]: SDK_EVENT.EXTERNAL.EVENT_TYPE.DELETED,
20
- };
21
-
22
- const getRoomType = (roomTags) =>
23
- roomTags.includes(SDK_EVENT.INTERNAL.ACTIVITY_TAG.ONE_ON_ONE)
24
- ? SDK_EVENT.EXTERNAL.SPACE_TYPE.DIRECT
25
- : SDK_EVENT.EXTERNAL.SPACE_TYPE.GROUP;
26
-
27
- /**
28
- * @typedef {Object} MessageObject
29
- * @property {string} id - (server generated) Unique identifier for the message
30
- * @property {string} personId - The ID for the author of the message
31
- * @property {email} personEmail - The email for the author of the message
32
- * @property {string} roomId - The ID for the room of the message
33
- * @property {string} text - The message posted to the room in plain text
34
- * @property {string} markdown - The message posted to the room in markdown
35
- * @property {Array<string>} files - The source URL(s) for the message attachment(s).
36
- * See the {@link https://developer.webex.com/docs/api/basics#message-attachments|Message Attachments}
37
- * Guide for a list of supported media types.
38
- * @property {isoDate} created - (server generated) The date and time that the message was created
39
- */
40
-
41
- /**
42
- * Messages are how people communicate in rooms. Each message timestamped and
43
- * represented in Webex as a distinct block of content. Messages can contain
44
- * plain text and a single file attachment. See the
45
- * {@link https://developer.webex.com/docs/api/basics#message-attachments|Message Attachments} Guide
46
- * for a list of supported media types.
47
- * @class
48
- */
49
- const Messages = WebexPlugin.extend({
50
- /**
51
- * Initializer used to generate Messages
52
- * as a plugin wrapped around the provided arguments.
53
- * @private
54
- * @see WebexPlugin.initialize
55
- * @param {...any} args
56
- * @returns {undefined}
57
- */
58
- initialize(...args) {
59
- Reflect.apply(WebexPlugin.prototype.initialize, this, args);
60
- },
61
-
62
- /**
63
- * Register to listen for incoming messages events
64
- * This is an alternate approach to registering for messages webhooks.
65
- * The events passed to any registered handlers will be similar to the webhook JSON,
66
- * but will omit webhook specific fields such as name, secret, url, etc.
67
- * The messages.listen() event objects can also include additional fields not
68
- * available in the webhook's JSON payload: `text`, `markdown`, and `files`.
69
- * These fields are available when their details are included in the web socket's
70
- * `activity` object. Retrieving other fields, such as the `html` field,
71
- * will require a manual request to get the corresponding message object.
72
- * To utilize the `listen()` method, the authorization token used
73
- * will need to have `spark:all` and `spark:kms` scopes enabled.
74
- * Note that by configuring your application to enable or disable `spark:all`
75
- * via its configuration page will also enable or disable `spark:kms`.
76
- * See the <a href="https://webex.github.io/webex-js-sdk/samples/browser-socket/">Sample App</a>
77
- * for more details.
78
- * @instance
79
- * @memberof Messages
80
- * @returns {Promise}
81
- * @example
82
- * webex.messages.listen()
83
- * .then(() => {
84
- * console.log('listening to message events');
85
- * webex.messages.on('created', (event) => console.log(`Got a message:created event:\n${event}`));
86
- * webex.messages.on('deleted', (event) => console.log(`Got a message:deleted event:\n${event}`));
87
- * })
88
- * .catch((e) => console.error(`Unable to register for message events: ${e}`));
89
- * // Some app logic...
90
- * // When it is time to cleanup
91
- * webex.messages.stopListening();
92
- * webex.messages.off('created');
93
- * webex.messages.off('deleted');
94
- */
95
- listen() {
96
- // Create a common envelope that we will wrap all events in
97
- return createEventEnvelope(this.webex, SDK_EVENT.EXTERNAL.RESOURCE.MESSAGES).then(
98
- (envelope) => {
99
- this.eventEnvelope = envelope;
100
-
101
- // Register to listen to events
102
- return this.webex.internal.mercury.connect().then(() => {
103
- this.listenTo(this.webex.internal.mercury, SDK_EVENT.INTERNAL.WEBEX_ACTIVITY, (event) =>
104
- this.onWebexApiEvent(event)
105
- );
106
- });
107
- }
108
- );
109
- },
110
-
111
- /**
112
- * Post a new message and/or media content into a room.
113
- * @instance
114
- * @memberof Messages
115
- * @param {MessageObject} message
116
- * @returns {Promise<MessageObject>}
117
- * @example
118
- * webex.rooms.create({title: 'Create Message Example'})
119
- * .then(function(room) {
120
- * return webex.messages.create({
121
- * text: 'Howdy!',
122
- * roomId: room.id
123
- * });
124
- * })
125
- * .then(function(message) {
126
- * var assert = require('assert');
127
- * assert(message.id);
128
- * assert(message.personId);
129
- * assert(message.personEmail);
130
- * assert(message.roomId);
131
- * assert(message.created);
132
- * return 'success';
133
- * });
134
- * // => success
135
- */
136
- create(message) {
137
- let key = 'body';
138
-
139
- if (message.file) {
140
- this.logger.warn(
141
- 'Supplying a single `file` property is deprecated; please supply a `files` array'
142
- );
143
- message.files = [message.file];
144
- Reflect.deleteProperty(message, 'file');
145
- }
146
-
147
- if (
148
- isArray(message.files) &&
149
- message.files.reduce((type, file) => type || typeof file !== 'string', false)
150
- ) {
151
- key = 'formData';
152
- }
153
-
154
- const options = {
155
- method: 'POST',
156
- service: 'hydra',
157
- resource: 'messages',
158
- [key]: message,
159
- };
160
-
161
- return this.request(options).then((res) => res.body);
162
- },
163
- /**
164
- * Put an updated message and/or media content into a room instead of existing message.
165
- * @instance
166
- * @memberof Messages
167
- * @param {MessageObject} message
168
- * @param {MessageObject} altMessage
169
- * @returns {Promise<MessageObject>}
170
- * @example
171
- * webex.rooms.create({title: 'Create Message Example'})
172
- * .then(function(room) {
173
- * return webex.messages.create({
174
- * text: 'Howdy!',
175
- * roomId: room.id
176
- * });
177
- * })
178
- * .then(function(m) {
179
- * message = m;
180
- * return webex.messages.update(message,{markdown:`**What up**`});
181
- * })
182
- * .then(function(m) {
183
- * message = m;
184
- * return webex.messages.update(message.id,{roomId:message.roomId,text:'Howdy!'});
185
- * })
186
- * .then(function(message) {
187
- * var assert = require('assert');
188
- * assert(message.id);
189
- * assert(message.personId);
190
- * assert(message.personEmail);
191
- * assert(message.roomId);
192
- * assert(message.created);
193
- * return 'success';
194
- * });
195
- * // => success
196
- */
197
- update(message, altMessage) {
198
- const id = message.id || message;
199
- let key = 'body';
200
-
201
- if (message.file) {
202
- this.logger.warn(
203
- 'Supplying a single `file` property is deprecated; please supply a `files` array'
204
- );
205
- message.files = [message.file];
206
- Reflect.deleteProperty(message, 'file');
207
- }
208
-
209
- if (
210
- message.files &&
211
- isArray(message.files) &&
212
- message.files.reduce((type, file) => type || typeof file !== 'string', false)
213
- ) {
214
- key = 'formData';
215
- }
216
-
217
- if (!altMessage.roomId && !message.roomId) {
218
- this.logger.error(
219
- 'Error: RoomID is mandatory for message update call in one of the parameter, message or altMessage'
220
- );
221
- } else {
222
- /* if altMessage doesnt contain RoomId use roomId from message object.
223
- I dont understand why RESTAPI call has RoomId Mandatory in body something webex Developers to clarity.
224
- In my opinion messageId provided in REST URL call should be enough to get roomID at serverside
225
- */
226
- altMessage.roomId = altMessage.roomId ? altMessage.roomId : message.roomId;
227
-
228
- const options = {
229
- method: 'PUT',
230
- service: 'hydra',
231
- resource: 'messages/'.concat(id),
232
- [key]: altMessage,
233
- };
234
-
235
- return this.request(options).then((res) => res.body);
236
- }
237
-
238
- return null;
239
- },
240
-
241
- /**
242
- * Returns a single message.
243
- * @instance
244
- * @memberof Messages
245
- * @param {RoomObject|string} message
246
- * @returns {Promise<MessageObject>}
247
- * @example
248
- * var message;
249
- * webex.rooms.create({title: 'Get Message Example'})
250
- * .then(function(room) {
251
- * return webex.messages.create({
252
- * text: 'Howdy!',
253
- * roomId: room.id
254
- * });
255
- * })
256
- * .then(function(m) {
257
- * message = m;
258
- * return webex.messages.get(message.id);
259
- * })
260
- * .then(function(message2) {
261
- * var assert = require('assert');
262
- * assert.deepEqual(message2, message);
263
- * return 'success';
264
- * });
265
- * // => success
266
- */
267
- get(message) {
268
- const id = message.id || message;
269
-
270
- return this.request({
271
- service: 'hydra',
272
- resource: `messages/${id}`,
273
- }).then((res) => res.body.items || res.body);
274
- },
275
-
276
- /**
277
- * Returns a list of messages. In most cases the results will only contain
278
- * messages posted in rooms that the authenticated user is a member of.
279
- * @instance
280
- * @memberof Messages
281
- * @param {Object} options
282
- * @param {string} options.roomId
283
- * @param {number} options.max
284
- * @returns {Promise<Page<MessageObject>>}
285
- * @example
286
- * var message1, message2, room;
287
- * webex.rooms.create({title: 'List Messages Example'})
288
- * .then(function(r) {
289
- * room = r;
290
- * return webex.messages.create({
291
- * text: 'Howdy!',
292
- * roomId: room.id
293
- * });
294
- * })
295
- * .then(function(m) {
296
- * message1 = m;
297
- * return webex.messages.create({
298
- * text: 'How are you?',
299
- * roomId: room.id
300
- * });
301
- * })
302
- * .then(function(m) {
303
- * message2 = m;
304
- * return webex.messages.list({roomId: room.id});
305
- * })
306
- * .then(function(messages) {
307
- * var assert = require('assert');
308
- * assert.equal(messages.length, 2);
309
- * assert.equal(messages.items[0].id, message2.id);
310
- * assert.equal(messages.items[1].id, message1.id);
311
- * return 'success';
312
- * });
313
- * // => success
314
- */
315
- list(options) {
316
- return this.request({
317
- service: 'hydra',
318
- resource: 'messages',
319
- qs: options,
320
- }).then((res) => new Page(res, this.webex));
321
- },
322
-
323
- /**
324
- * Deletes a single message. Deleting a message will notify all members of the
325
- * room that the authenticated user deleted the message. Generally, users can
326
- * only delete their own messages except for the case of Moderated Rooms and
327
- * Org Administrators.
328
- * @instance
329
- * @memberof Messages
330
- * @param {MessageObject|uuid} message
331
- * @returns {Promise}}
332
- * @example
333
- * var message1, room;
334
- * webex.rooms.create({title: 'Messages Example'})
335
- * .then(function(r) {
336
- * room = r;
337
- * return webex.messages.create({
338
- * text: 'Howdy!',
339
- * roomId: room.id
340
- * });
341
- * })
342
- * .then(function(m) {
343
- * message1 = m;
344
- * return webex.messages.create({
345
- * text: 'How are you?',
346
- * roomId: room.id
347
- * });
348
- * })
349
- * .then(function() {
350
- * return webex.messages.remove(message1);
351
- * })
352
- * .then(function() {
353
- * return webex.messages.list({roomId: room.id});
354
- * })
355
- * .then(function(messages) {
356
- * var assert = require('assert');
357
- * assert.equal(messages.items.length, 1);
358
- * assert(messages.items[0].id !== message1.id);
359
- * return 'success';
360
- * });
361
- * // => success
362
- */
363
- remove(message) {
364
- const id = message.id || message;
365
-
366
- return this.request({
367
- method: 'DELETE',
368
- service: 'hydra',
369
- resource: `messages/${id}`,
370
- }).then((res) => {
371
- // Firefox has some issues with 204s and/or DELETE. This should move to
372
- // http-core
373
- if (res.statusCode === 204) {
374
- return undefined;
375
- }
376
-
377
- return res.body;
378
- });
379
- },
380
-
381
- /**
382
- * Curry the 'trigger' method
383
- * @private
384
- * @memberof Messages
385
- * @param {string} type the type of event to fire
386
- * @returns {function} takes event and triggers it
387
- */
388
- fire(type) {
389
- return (event) => this.trigger(type, event);
390
- },
391
-
392
- /**
393
- * This function is called when an internal membership events fires,
394
- * if the user registered for these events with the listen() function.
395
- * External users of the SDK should not call this function
396
- * @private
397
- * @memberof Messages
398
- * @param {Object} event
399
- * @param {Object} event.data contains the data of the event
400
- * @param {Object} event.data.activity the activity that triggered the event
401
- * @returns {void}
402
- */
403
- onWebexApiEvent({data: {activity}}) {
404
- const type = verbToType[activity.verb];
405
-
406
- if (!type) {
407
- return;
408
- }
409
-
410
- this.getMessageEvent(activity, type).then(this.fire(type));
411
- },
412
-
413
- /**
414
- * Constructs the data object for an event on the messages resource,
415
- * adhering to Hydra's Webhook data structure messages.
416
- * External users of the SDK should not call this function
417
- * @private
418
- * @memberof Messages
419
- * @param {Object} activity from mercury
420
- * @param {String} type the type of event
421
- * @returns {Object} constructed event
422
- */
423
- getMessageEvent(activity, type) {
424
- const {
425
- id,
426
- actor: {entryUUID: actorId, emailAddress},
427
- object: {id: objectId},
428
- target: {id: roomId, url: roomUrl, tags: roomTags},
429
- } = activity;
430
-
431
- const cluster = getHydraClusterString(this.webex, roomUrl);
432
- const combinedEvent = cloneDeep(this.eventEnvelope);
433
-
434
- combinedEvent.event = type;
435
- if (type === SDK_EVENT.EXTERNAL.EVENT_TYPE.DELETED) {
436
- // Cannot fetch since the message is deleted
437
- // Convert the Mercury event to a Hydra event
438
- const personId = buildHydraPersonId(actorId, cluster);
439
-
440
- return Promise.resolve({
441
- ...combinedEvent,
442
- actorId: personId,
443
- data: {
444
- id: buildHydraMessageId(objectId, cluster),
445
- personEmail: emailAddress || actorId,
446
- personId,
447
- roomId: buildHydraRoomId(roomId, cluster),
448
- roomType: getRoomType(roomTags),
449
- },
450
- });
451
- }
452
-
453
- return this.get(buildHydraMessageId(id, cluster)).then((data) => ({
454
- ...combinedEvent,
455
- actorId: data.personId,
456
- data,
457
- }));
458
- },
459
- });
460
-
461
- export default Messages;
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {
6
+ SDK_EVENT,
7
+ buildHydraMessageId,
8
+ buildHydraPersonId,
9
+ buildHydraRoomId,
10
+ createEventEnvelope,
11
+ getHydraClusterString,
12
+ } from '@webex/common';
13
+ import {Page, WebexPlugin} from '@webex/webex-core';
14
+ import {cloneDeep, isArray} from 'lodash';
15
+
16
+ const verbToType = {
17
+ [SDK_EVENT.INTERNAL.ACTIVITY_VERB.SHARE]: SDK_EVENT.EXTERNAL.EVENT_TYPE.CREATED,
18
+ [SDK_EVENT.INTERNAL.ACTIVITY_VERB.POST]: SDK_EVENT.EXTERNAL.EVENT_TYPE.CREATED,
19
+ [SDK_EVENT.INTERNAL.ACTIVITY_VERB.DELETE]: SDK_EVENT.EXTERNAL.EVENT_TYPE.DELETED,
20
+ };
21
+
22
+ const getRoomType = (roomTags) =>
23
+ roomTags.includes(SDK_EVENT.INTERNAL.ACTIVITY_TAG.ONE_ON_ONE)
24
+ ? SDK_EVENT.EXTERNAL.SPACE_TYPE.DIRECT
25
+ : SDK_EVENT.EXTERNAL.SPACE_TYPE.GROUP;
26
+
27
+ /**
28
+ * @typedef {Object} MessageObject
29
+ * @property {string} id - (server generated) Unique identifier for the message
30
+ * @property {string} personId - The ID for the author of the message
31
+ * @property {email} personEmail - The email for the author of the message
32
+ * @property {string} roomId - The ID for the room of the message
33
+ * @property {string} text - The message posted to the room in plain text
34
+ * @property {string} markdown - The message posted to the room in markdown
35
+ * @property {Array<string>} files - The source URL(s) for the message attachment(s).
36
+ * See the {@link https://developer.webex.com/docs/api/basics#message-attachments|Message Attachments}
37
+ * Guide for a list of supported media types.
38
+ * @property {isoDate} created - (server generated) The date and time that the message was created
39
+ */
40
+
41
+ /**
42
+ * Messages are how people communicate in rooms. Each message timestamped and
43
+ * represented in Webex as a distinct block of content. Messages can contain
44
+ * plain text and a single file attachment. See the
45
+ * {@link https://developer.webex.com/docs/api/basics#message-attachments|Message Attachments} Guide
46
+ * for a list of supported media types.
47
+ * @class
48
+ */
49
+ const Messages = WebexPlugin.extend({
50
+ /**
51
+ * Initializer used to generate Messages
52
+ * as a plugin wrapped around the provided arguments.
53
+ * @private
54
+ * @see WebexPlugin.initialize
55
+ * @param {...any} args
56
+ * @returns {undefined}
57
+ */
58
+ initialize(...args) {
59
+ Reflect.apply(WebexPlugin.prototype.initialize, this, args);
60
+ },
61
+
62
+ /**
63
+ * Register to listen for incoming messages events
64
+ * This is an alternate approach to registering for messages webhooks.
65
+ * The events passed to any registered handlers will be similar to the webhook JSON,
66
+ * but will omit webhook specific fields such as name, secret, url, etc.
67
+ * The messages.listen() event objects can also include additional fields not
68
+ * available in the webhook's JSON payload: `text`, `markdown`, and `files`.
69
+ * These fields are available when their details are included in the web socket's
70
+ * `activity` object. Retrieving other fields, such as the `html` field,
71
+ * will require a manual request to get the corresponding message object.
72
+ * To utilize the `listen()` method, the authorization token used
73
+ * will need to have `spark:all` and `spark:kms` scopes enabled.
74
+ * Note that by configuring your application to enable or disable `spark:all`
75
+ * via its configuration page will also enable or disable `spark:kms`.
76
+ * See the <a href="https://webex.github.io/webex-js-sdk/samples/browser-socket/">Sample App</a>
77
+ * for more details.
78
+ * @instance
79
+ * @memberof Messages
80
+ * @returns {Promise}
81
+ * @example
82
+ * webex.messages.listen()
83
+ * .then(() => {
84
+ * console.log('listening to message events');
85
+ * webex.messages.on('created', (event) => console.log(`Got a message:created event:\n${event}`));
86
+ * webex.messages.on('deleted', (event) => console.log(`Got a message:deleted event:\n${event}`));
87
+ * })
88
+ * .catch((e) => console.error(`Unable to register for message events: ${e}`));
89
+ * // Some app logic...
90
+ * // When it is time to cleanup
91
+ * webex.messages.stopListening();
92
+ * webex.messages.off('created');
93
+ * webex.messages.off('deleted');
94
+ */
95
+ listen() {
96
+ // Create a common envelope that we will wrap all events in
97
+ return createEventEnvelope(this.webex, SDK_EVENT.EXTERNAL.RESOURCE.MESSAGES).then(
98
+ (envelope) => {
99
+ this.eventEnvelope = envelope;
100
+
101
+ // Register to listen to events
102
+ return this.webex.internal.mercury.connect().then(() => {
103
+ this.listenTo(this.webex.internal.mercury, SDK_EVENT.INTERNAL.WEBEX_ACTIVITY, (event) =>
104
+ this.onWebexApiEvent(event)
105
+ );
106
+ });
107
+ }
108
+ );
109
+ },
110
+
111
+ /**
112
+ * Post a new message and/or media content into a room.
113
+ * @instance
114
+ * @memberof Messages
115
+ * @param {MessageObject} message
116
+ * @returns {Promise<MessageObject>}
117
+ * @example
118
+ * webex.rooms.create({title: 'Create Message Example'})
119
+ * .then(function(room) {
120
+ * return webex.messages.create({
121
+ * text: 'Howdy!',
122
+ * roomId: room.id
123
+ * });
124
+ * })
125
+ * .then(function(message) {
126
+ * var assert = require('assert');
127
+ * assert(message.id);
128
+ * assert(message.personId);
129
+ * assert(message.personEmail);
130
+ * assert(message.roomId);
131
+ * assert(message.created);
132
+ * return 'success';
133
+ * });
134
+ * // => success
135
+ */
136
+ create(message) {
137
+ let key = 'body';
138
+
139
+ if (message.file) {
140
+ this.logger.warn(
141
+ 'Supplying a single `file` property is deprecated; please supply a `files` array'
142
+ );
143
+ message.files = [message.file];
144
+ Reflect.deleteProperty(message, 'file');
145
+ }
146
+
147
+ if (
148
+ isArray(message.files) &&
149
+ message.files.reduce((type, file) => type || typeof file !== 'string', false)
150
+ ) {
151
+ key = 'formData';
152
+ }
153
+
154
+ const options = {
155
+ method: 'POST',
156
+ service: 'hydra',
157
+ resource: 'messages',
158
+ [key]: message,
159
+ };
160
+
161
+ return this.request(options).then((res) => res.body);
162
+ },
163
+ /**
164
+ * Put an updated message and/or media content into a room instead of existing message.
165
+ * @instance
166
+ * @memberof Messages
167
+ * @param {MessageObject} message
168
+ * @param {MessageObject} altMessage
169
+ * @returns {Promise<MessageObject>}
170
+ * @example
171
+ * webex.rooms.create({title: 'Create Message Example'})
172
+ * .then(function(room) {
173
+ * return webex.messages.create({
174
+ * text: 'Howdy!',
175
+ * roomId: room.id
176
+ * });
177
+ * })
178
+ * .then(function(m) {
179
+ * message = m;
180
+ * return webex.messages.update(message,{markdown:`**What up**`});
181
+ * })
182
+ * .then(function(m) {
183
+ * message = m;
184
+ * return webex.messages.update(message.id,{roomId:message.roomId,text:'Howdy!'});
185
+ * })
186
+ * .then(function(message) {
187
+ * var assert = require('assert');
188
+ * assert(message.id);
189
+ * assert(message.personId);
190
+ * assert(message.personEmail);
191
+ * assert(message.roomId);
192
+ * assert(message.created);
193
+ * return 'success';
194
+ * });
195
+ * // => success
196
+ */
197
+ update(message, altMessage) {
198
+ const id = message.id || message;
199
+ let key = 'body';
200
+
201
+ if (message.file) {
202
+ this.logger.warn(
203
+ 'Supplying a single `file` property is deprecated; please supply a `files` array'
204
+ );
205
+ message.files = [message.file];
206
+ Reflect.deleteProperty(message, 'file');
207
+ }
208
+
209
+ if (
210
+ message.files &&
211
+ isArray(message.files) &&
212
+ message.files.reduce((type, file) => type || typeof file !== 'string', false)
213
+ ) {
214
+ key = 'formData';
215
+ }
216
+
217
+ if (!altMessage.roomId && !message.roomId) {
218
+ this.logger.error(
219
+ 'Error: RoomID is mandatory for message update call in one of the parameter, message or altMessage'
220
+ );
221
+ } else {
222
+ /* if altMessage doesnt contain RoomId use roomId from message object.
223
+ I dont understand why RESTAPI call has RoomId Mandatory in body something webex Developers to clarity.
224
+ In my opinion messageId provided in REST URL call should be enough to get roomID at serverside
225
+ */
226
+ altMessage.roomId = altMessage.roomId ? altMessage.roomId : message.roomId;
227
+
228
+ const options = {
229
+ method: 'PUT',
230
+ service: 'hydra',
231
+ resource: 'messages/'.concat(id),
232
+ [key]: altMessage,
233
+ };
234
+
235
+ return this.request(options).then((res) => res.body);
236
+ }
237
+
238
+ return null;
239
+ },
240
+
241
+ /**
242
+ * Returns a single message.
243
+ * @instance
244
+ * @memberof Messages
245
+ * @param {RoomObject|string} message
246
+ * @returns {Promise<MessageObject>}
247
+ * @example
248
+ * var message;
249
+ * webex.rooms.create({title: 'Get Message Example'})
250
+ * .then(function(room) {
251
+ * return webex.messages.create({
252
+ * text: 'Howdy!',
253
+ * roomId: room.id
254
+ * });
255
+ * })
256
+ * .then(function(m) {
257
+ * message = m;
258
+ * return webex.messages.get(message.id);
259
+ * })
260
+ * .then(function(message2) {
261
+ * var assert = require('assert');
262
+ * assert.deepEqual(message2, message);
263
+ * return 'success';
264
+ * });
265
+ * // => success
266
+ */
267
+ get(message) {
268
+ const id = message.id || message;
269
+
270
+ return this.request({
271
+ service: 'hydra',
272
+ resource: `messages/${id}`,
273
+ }).then((res) => res.body.items || res.body);
274
+ },
275
+
276
+ /**
277
+ * Returns a list of messages. In most cases the results will only contain
278
+ * messages posted in rooms that the authenticated user is a member of.
279
+ * @instance
280
+ * @memberof Messages
281
+ * @param {Object} options
282
+ * @param {string} options.roomId
283
+ * @param {number} options.max
284
+ * @returns {Promise<Page<MessageObject>>}
285
+ * @example
286
+ * var message1, message2, room;
287
+ * webex.rooms.create({title: 'List Messages Example'})
288
+ * .then(function(r) {
289
+ * room = r;
290
+ * return webex.messages.create({
291
+ * text: 'Howdy!',
292
+ * roomId: room.id
293
+ * });
294
+ * })
295
+ * .then(function(m) {
296
+ * message1 = m;
297
+ * return webex.messages.create({
298
+ * text: 'How are you?',
299
+ * roomId: room.id
300
+ * });
301
+ * })
302
+ * .then(function(m) {
303
+ * message2 = m;
304
+ * return webex.messages.list({roomId: room.id});
305
+ * })
306
+ * .then(function(messages) {
307
+ * var assert = require('assert');
308
+ * assert.equal(messages.length, 2);
309
+ * assert.equal(messages.items[0].id, message2.id);
310
+ * assert.equal(messages.items[1].id, message1.id);
311
+ * return 'success';
312
+ * });
313
+ * // => success
314
+ */
315
+ list(options) {
316
+ return this.request({
317
+ service: 'hydra',
318
+ resource: 'messages',
319
+ qs: options,
320
+ }).then((res) => new Page(res, this.webex));
321
+ },
322
+
323
+ /**
324
+ * Deletes a single message. Deleting a message will notify all members of the
325
+ * room that the authenticated user deleted the message. Generally, users can
326
+ * only delete their own messages except for the case of Moderated Rooms and
327
+ * Org Administrators.
328
+ * @instance
329
+ * @memberof Messages
330
+ * @param {MessageObject|uuid} message
331
+ * @returns {Promise}}
332
+ * @example
333
+ * var message1, room;
334
+ * webex.rooms.create({title: 'Messages Example'})
335
+ * .then(function(r) {
336
+ * room = r;
337
+ * return webex.messages.create({
338
+ * text: 'Howdy!',
339
+ * roomId: room.id
340
+ * });
341
+ * })
342
+ * .then(function(m) {
343
+ * message1 = m;
344
+ * return webex.messages.create({
345
+ * text: 'How are you?',
346
+ * roomId: room.id
347
+ * });
348
+ * })
349
+ * .then(function() {
350
+ * return webex.messages.remove(message1);
351
+ * })
352
+ * .then(function() {
353
+ * return webex.messages.list({roomId: room.id});
354
+ * })
355
+ * .then(function(messages) {
356
+ * var assert = require('assert');
357
+ * assert.equal(messages.items.length, 1);
358
+ * assert(messages.items[0].id !== message1.id);
359
+ * return 'success';
360
+ * });
361
+ * // => success
362
+ */
363
+ remove(message) {
364
+ const id = message.id || message;
365
+
366
+ return this.request({
367
+ method: 'DELETE',
368
+ service: 'hydra',
369
+ resource: `messages/${id}`,
370
+ }).then((res) => {
371
+ // Firefox has some issues with 204s and/or DELETE. This should move to
372
+ // http-core
373
+ if (res.statusCode === 204) {
374
+ return undefined;
375
+ }
376
+
377
+ return res.body;
378
+ });
379
+ },
380
+
381
+ /**
382
+ * Curry the 'trigger' method
383
+ * @private
384
+ * @memberof Messages
385
+ * @param {string} type the type of event to fire
386
+ * @returns {function} takes event and triggers it
387
+ */
388
+ fire(type) {
389
+ return (event) => this.trigger(type, event);
390
+ },
391
+
392
+ /**
393
+ * This function is called when an internal membership events fires,
394
+ * if the user registered for these events with the listen() function.
395
+ * External users of the SDK should not call this function
396
+ * @private
397
+ * @memberof Messages
398
+ * @param {Object} event
399
+ * @param {Object} event.data contains the data of the event
400
+ * @param {Object} event.data.activity the activity that triggered the event
401
+ * @returns {void}
402
+ */
403
+ onWebexApiEvent({data: {activity}}) {
404
+ const type = verbToType[activity.verb];
405
+
406
+ if (!type) {
407
+ return;
408
+ }
409
+
410
+ this.getMessageEvent(activity, type).then(this.fire(type));
411
+ },
412
+
413
+ /**
414
+ * Constructs the data object for an event on the messages resource,
415
+ * adhering to Hydra's Webhook data structure messages.
416
+ * External users of the SDK should not call this function
417
+ * @private
418
+ * @memberof Messages
419
+ * @param {Object} activity from mercury
420
+ * @param {String} type the type of event
421
+ * @returns {Object} constructed event
422
+ */
423
+ getMessageEvent(activity, type) {
424
+ const {
425
+ id,
426
+ actor: {entryUUID: actorId, emailAddress},
427
+ object: {id: objectId},
428
+ target: {id: roomId, url: roomUrl, tags: roomTags},
429
+ } = activity;
430
+
431
+ const cluster = getHydraClusterString(this.webex, roomUrl);
432
+ const combinedEvent = cloneDeep(this.eventEnvelope);
433
+
434
+ combinedEvent.event = type;
435
+ if (type === SDK_EVENT.EXTERNAL.EVENT_TYPE.DELETED) {
436
+ // Cannot fetch since the message is deleted
437
+ // Convert the Mercury event to a Hydra event
438
+ const personId = buildHydraPersonId(actorId, cluster);
439
+
440
+ return Promise.resolve({
441
+ ...combinedEvent,
442
+ actorId: personId,
443
+ data: {
444
+ id: buildHydraMessageId(objectId, cluster),
445
+ personEmail: emailAddress || actorId,
446
+ personId,
447
+ roomId: buildHydraRoomId(roomId, cluster),
448
+ roomType: getRoomType(roomTags),
449
+ },
450
+ });
451
+ }
452
+
453
+ return this.get(buildHydraMessageId(id, cluster)).then((data) => ({
454
+ ...combinedEvent,
455
+ actorId: data.personId,
456
+ data,
457
+ }));
458
+ },
459
+ });
460
+
461
+ export default Messages;