diff --git a/example.js b/example.js index 10a606d..8e1d2d4 100644 --- a/example.js +++ b/example.js @@ -219,6 +219,23 @@ client.on('message_ack', (msg, ack) => { } }); +client.on('group_join', (notification) => { + // User has joined or been added to the group. + console.log('join', notification); + notification.reply('User joined.'); +}); + +client.on('group_leave', (notification) => { + // User has left or been kicked from the group. + console.log('leave', notification); + notification.reply('User left.'); +}); + +client.on('group_update', (notification) => { + // Group picture, subject or description has been updated. + console.log('update', notification); +}); + client.on('disconnected', (reason) => { console.log('Client was logged out', reason); }); diff --git a/src/Client.js b/src/Client.js index 491a091..02176cc 100644 --- a/src/Client.js +++ b/src/Client.js @@ -10,8 +10,7 @@ const { WhatsWebURL, UserAgent, DefaultOptions, Events, WAState } = require('./u const { ExposeStore, LoadUtils } = require('./util/Injected'); const ChatFactory = require('./factories/ChatFactory'); const ContactFactory = require('./factories/ContactFactory'); -const { ClientInfo, Message, MessageMedia, Location } = require('./structures'); - +const { ClientInfo, Message, MessageMedia, Location, GroupNotification } = require('./structures'); /** * Starting point for interacting with the WhatsApp Web API * @extends {EventEmitter} @@ -146,6 +145,18 @@ class Client extends EventEmitter { await page.exposeFunction('onAddMessageEvent', msg => { if (!msg.isNewMsg) return; + if (msg.type === 'gp2') { + const notification = new GroupNotification(this, msg); + if (msg.subtype === 'add' || msg.subtype === 'invite') { + this.emit(Events.GROUP_JOIN, notification); + } else if (msg.subtype === 'remove' || msg.subtype === 'leave') { + this.emit(Events.GROUP_LEAVE, notification); + } else { + this.emit(Events.GROUP_UPDATE, notification); + } + return; + } + const message = new Message(this, msg); /** diff --git a/src/structures/GroupNotification.js b/src/structures/GroupNotification.js new file mode 100644 index 0000000..d022b70 --- /dev/null +++ b/src/structures/GroupNotification.js @@ -0,0 +1,104 @@ +'use strict'; + +const Base = require('./Base'); + +/** + * Represents a GroupNotification on WhatsApp + * @extends {Base} + */ +class GroupNotification extends Base { + constructor(client, data) { + super(client); + + if(data) this._patch(data); + } + + _patch(data) { + /** + * ID that represents the groupNotification + * @type {object} + */ + this.id = data.id; + + /** + * Extra content + * @type {string} + */ + this.body = data.body || ''; + + /** + * GroupNotification type + * @type {GroupNotificationTypes} + */ + this.type = data.subtype; + + /** + * Unix timestamp for when the groupNotification was created + * @type {number} + */ + this.timestamp = data.t; + + /** + * ID for the Chat that this groupNotification was sent for. + * + * @type {string} + */ + this.chatId = typeof (data.to) === 'object' ? data.to._serialized : data.to; + + /** + * ContactId for the user that produced the GroupNotification. + * @type {string} + */ + this.author = typeof (data.author) === 'object' ? data.author._serialized : data.author; + + /** + * Contact IDs for the users that were affected by this GroupNotification. + * @type {Array} + */ + this.recipientIds = []; + + if (data.recipients) { + this.recipientIds = data.recipients; + } + + return super._patch(data); + } + + /** + * Returns the Chat this groupNotification was sent in + * @returns {Promise} + */ + getChat() { + return this.client.getChatById(this.chatId); + } + + /** + * Returns the Contact this GroupNotification was produced by + * @returns {Promise} + */ + getContact() { + return this.client.getContactById(this.author); + } + + /** + * Returns the Contacts affected by this GroupNotification. + * @returns {Promise>} + */ + async getRecipients() { + return await Promise.all(this.recipientIds.map(async m => await this.client.getContactById(m))); + } + + /** + * Sends a message to the same chat this GroupNotification was produced in. + * + * @param {string|MessageMedia|Location} content + * @param {object} options + * @returns {Promise} + */ + async reply(content, options={}) { + return this.client.sendMessage(this.chatId, content, options); + } + +} + +module.exports = GroupNotification; diff --git a/src/util/Constants.js b/src/util/Constants.js index 26a95d0..7e89600 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -36,6 +36,9 @@ exports.Events = { MESSAGE_REVOKED_EVERYONE: 'message_revoke_everyone', MESSAGE_REVOKED_ME: 'message_revoke_me', MESSAGE_ACK: 'message_ack', + GROUP_JOIN: 'group_join', + GROUP_LEAVE: 'group_leave', + GROUP_UPDATE: 'group_update', QR_RECEIVED: 'qr', DISCONNECTED: 'disconnected', STATE_CHANGED: 'change_state', @@ -61,6 +64,23 @@ exports.MessageTypes = { UNKNOWN: 'unknown' }; +/** + * Group notification types + * @readonly + * @enum {string} + */ +exports.GroupNotificationTypes = { + ADD: 'add', + INVITE: 'invite', + REMOVE: 'remove', + LEAVE: 'leave', + SUBJECT: 'subject', + DESCRIPTION: 'description', + PICTURE: 'picture', + ANNOUNCE: 'announce', + RESTRICT: 'restrict', +}; + /** * Chat types * @readonly