yt-dlp support
This commit is contained in:
22
node_modules/whatsapp-web.js/src/structures/Base.js
generated
vendored
Normal file
22
node_modules/whatsapp-web.js/src/structures/Base.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Represents a WhatsApp data structure
|
||||
*/
|
||||
class Base {
|
||||
constructor(client) {
|
||||
/**
|
||||
* The client that instantiated this
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(this, 'client', { value: client });
|
||||
}
|
||||
|
||||
_clone() {
|
||||
return Object.assign(Object.create(this), this);
|
||||
}
|
||||
|
||||
_patch(data) { return data; }
|
||||
}
|
||||
|
||||
module.exports = Base;
|
||||
69
node_modules/whatsapp-web.js/src/structures/Broadcast.js
generated
vendored
Normal file
69
node_modules/whatsapp-web.js/src/structures/Broadcast.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
const Message = require('./Message');
|
||||
|
||||
/**
|
||||
* Represents a Status/Story on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Broadcast extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* ID that represents the chat
|
||||
* @type {object}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* Unix timestamp of last status
|
||||
* @type {number}
|
||||
*/
|
||||
this.timestamp = data.t;
|
||||
|
||||
/**
|
||||
* Number of available statuses
|
||||
* @type {number}
|
||||
*/
|
||||
this.totalCount = data.totalCount;
|
||||
|
||||
/**
|
||||
* Number of not viewed
|
||||
* @type {number}
|
||||
*/
|
||||
this.unreadCount = data.unreadCount;
|
||||
|
||||
/**
|
||||
* Messages statuses
|
||||
* @type {Message[]}
|
||||
*/
|
||||
this.msgs = data.msgs?.map(msg => new Message(this.client, msg));
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Chat this message was sent in
|
||||
* @returns {Promise<Chat>}
|
||||
*/
|
||||
getChat() {
|
||||
return this.client.getChatById(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Contact this message was sent from
|
||||
* @returns {Promise<Contact>}
|
||||
*/
|
||||
getContact() {
|
||||
return this.client.getContactById(this.id._serialized);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Broadcast;
|
||||
21
node_modules/whatsapp-web.js/src/structures/BusinessContact.js
generated
vendored
Normal file
21
node_modules/whatsapp-web.js/src/structures/BusinessContact.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
const Contact = require('./Contact');
|
||||
|
||||
/**
|
||||
* Represents a Business Contact on WhatsApp
|
||||
* @extends {Contact}
|
||||
*/
|
||||
class BusinessContact extends Contact {
|
||||
_patch(data) {
|
||||
/**
|
||||
* The contact's business profile
|
||||
*/
|
||||
this.businessProfile = data.businessProfile;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = BusinessContact;
|
||||
82
node_modules/whatsapp-web.js/src/structures/Buttons.js
generated
vendored
Normal file
82
node_modules/whatsapp-web.js/src/structures/Buttons.js
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
'use strict';
|
||||
|
||||
const MessageMedia = require('./MessageMedia');
|
||||
const Util = require('../util/Util');
|
||||
|
||||
/**
|
||||
* Button spec used in Buttons constructor
|
||||
* @typedef {Object} ButtonSpec
|
||||
* @property {string=} id - Custom ID to set on the button. A random one will be generated if one is not passed.
|
||||
* @property {string} body - The text to show on the button.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} FormattedButtonSpec
|
||||
* @property {string} buttonId
|
||||
* @property {number} type
|
||||
* @property {Object} buttonText
|
||||
*/
|
||||
|
||||
/**
|
||||
* Message type buttons
|
||||
*/
|
||||
class Buttons {
|
||||
/**
|
||||
* @param {string|MessageMedia} body
|
||||
* @param {ButtonSpec[]} buttons - See {@link ButtonSpec}
|
||||
* @param {string?} title
|
||||
* @param {string?} footer
|
||||
*/
|
||||
constructor(body, buttons, title, footer) {
|
||||
/**
|
||||
* Message body
|
||||
* @type {string|MessageMedia}
|
||||
*/
|
||||
this.body = body;
|
||||
|
||||
/**
|
||||
* title of message
|
||||
* @type {string}
|
||||
*/
|
||||
this.title = title;
|
||||
|
||||
/**
|
||||
* footer of message
|
||||
* @type {string}
|
||||
*/
|
||||
this.footer = footer;
|
||||
|
||||
if (body instanceof MessageMedia) {
|
||||
this.type = 'media';
|
||||
this.title = '';
|
||||
}else{
|
||||
this.type = 'chat';
|
||||
}
|
||||
|
||||
/**
|
||||
* buttons of message
|
||||
* @type {FormattedButtonSpec[]}
|
||||
*/
|
||||
this.buttons = this._format(buttons);
|
||||
if(!this.buttons.length){ throw '[BT01] No buttons';}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates button array from simple array
|
||||
* @param {ButtonSpec[]} buttons
|
||||
* @returns {FormattedButtonSpec[]}
|
||||
* @example
|
||||
* Input: [{id:'customId',body:'button1'},{body:'button2'},{body:'button3'},{body:'button4'}]
|
||||
* Returns: [{ buttonId:'customId',buttonText:{'displayText':'button1'},type: 1 },{buttonId:'n3XKsL',buttonText:{'displayText':'button2'},type:1},{buttonId:'NDJk0a',buttonText:{'displayText':'button3'},type:1}]
|
||||
*/
|
||||
_format(buttons){
|
||||
buttons = buttons.slice(0,3); // phone users can only see 3 buttons, so lets limit this
|
||||
return buttons.map((btn) => {
|
||||
return {'buttonId':btn.id ? String(btn.id) : Util.generateHash(6),'buttonText':{'displayText':btn.body},'type':1};
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Buttons;
|
||||
76
node_modules/whatsapp-web.js/src/structures/Call.js
generated
vendored
Normal file
76
node_modules/whatsapp-web.js/src/structures/Call.js
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
|
||||
/**
|
||||
* Represents a Call on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Call extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* Call ID
|
||||
* @type {string}
|
||||
*/
|
||||
this.id = data.id;
|
||||
/**
|
||||
* From
|
||||
* @type {string}
|
||||
*/
|
||||
this.from = data.peerJid;
|
||||
/**
|
||||
* Unix timestamp for when the call was created
|
||||
* @type {number}
|
||||
*/
|
||||
this.timestamp = data.offerTime;
|
||||
/**
|
||||
* Is video
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isVideo = data.isVideo;
|
||||
/**
|
||||
* Is Group
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isGroup = data.isGroup;
|
||||
/**
|
||||
* Indicates if the call was sent by the current user
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.fromMe = data.outgoing;
|
||||
/**
|
||||
* Indicates if the call can be handled in waweb
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.canHandleLocally = data.canHandleLocally;
|
||||
/**
|
||||
* Indicates if the call Should be handled in waweb
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.webClientShouldHandle = data.webClientShouldHandle;
|
||||
/**
|
||||
* Object with participants
|
||||
* @type {object}
|
||||
*/
|
||||
this.participants = data.participants;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject the call
|
||||
*/
|
||||
async reject() {
|
||||
return this.client.pupPage.evaluate((peerJid, id) => {
|
||||
return window.WWebJS.rejectCall(peerJid, id);
|
||||
}, this.from, this.id);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Call;
|
||||
382
node_modules/whatsapp-web.js/src/structures/Channel.js
generated
vendored
Normal file
382
node_modules/whatsapp-web.js/src/structures/Channel.js
generated
vendored
Normal file
@@ -0,0 +1,382 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
const Message = require('./Message');
|
||||
|
||||
/**
|
||||
* Channel ID structure
|
||||
* @typedef {Object} ChannelId
|
||||
* @property {string} server
|
||||
* @property {string} user
|
||||
* @property {string} _serialized
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a Channel on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Channel extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
this.channelMetadata = data.channelMetadata;
|
||||
|
||||
/**
|
||||
* ID that represents the channel
|
||||
* @type {ChannelId}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* Title of the channel
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = data.name;
|
||||
|
||||
/**
|
||||
* The channel description
|
||||
* @type {string}
|
||||
*/
|
||||
this.description = data.channelMetadata.description;
|
||||
|
||||
/**
|
||||
* Indicates if it is a Channel
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isChannel = data.isChannel;
|
||||
|
||||
/**
|
||||
* Indicates if it is a Group
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isGroup = data.isGroup;
|
||||
|
||||
/**
|
||||
* Indicates if the channel is readonly
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isReadOnly = data.isReadOnly;
|
||||
|
||||
/**
|
||||
* Amount of messages unread
|
||||
* @type {number}
|
||||
*/
|
||||
this.unreadCount = data.unreadCount;
|
||||
|
||||
/**
|
||||
* Unix timestamp for when the last activity occurred
|
||||
* @type {number}
|
||||
*/
|
||||
this.timestamp = data.t;
|
||||
|
||||
/**
|
||||
* Indicates if the channel is muted or not
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isMuted = data.isMuted;
|
||||
|
||||
/**
|
||||
* Unix timestamp for when the mute expires
|
||||
* @type {number}
|
||||
*/
|
||||
this.muteExpiration = data.muteExpiration;
|
||||
|
||||
/**
|
||||
* Last message in the channel
|
||||
* @type {Message}
|
||||
*/
|
||||
this.lastMessage = data.lastMessage ? new Message(super.client, data.lastMessage) : undefined;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the subscribers of the channel (only those who are in your contact list)
|
||||
* @param {?number} limit Optional parameter to specify the limit of subscribers to retrieve
|
||||
* @returns {Promise<Array<{contact: Contact, role: string}>>} Returns an array of objects that handle the subscribed contacts and their roles in the channel
|
||||
*/
|
||||
async getSubscribers(limit) {
|
||||
return await this.client.pupPage.evaluate(async (channelId, limit) => {
|
||||
const channel = await window.WWebJS.getChat(channelId, { getAsModel: false });
|
||||
if (!channel) return [];
|
||||
!limit && (limit = window.Store.ChannelUtils.getMaxSubscriberNumber());
|
||||
const response = await window.Store.ChannelSubscribers.mexFetchNewsletterSubscribers(channelId, limit);
|
||||
const contacts = window.Store.ChannelSubscribers.getSubscribersInContacts(response.subscribers);
|
||||
return Promise.all(contacts.map((obj) => ({
|
||||
...obj,
|
||||
contact: window.WWebJS.getContactModel(obj.contact)
|
||||
})));
|
||||
}, this.id._serialized, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the channel subject
|
||||
* @param {string} newSubject
|
||||
* @returns {Promise<boolean>} Returns true if the subject was properly updated. This can return false if the user does not have the necessary permissions.
|
||||
*/
|
||||
async setSubject(newSubject) {
|
||||
const success = await this._setChannelMetadata({ name: newSubject }, { editName: true });
|
||||
success && (this.name = newSubject);
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the channel description
|
||||
* @param {string} newDescription
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async setDescription(newDescription) {
|
||||
const success = await this._setChannelMetadata({ description: newDescription }, { editDescription: true });
|
||||
success && (this.description = newDescription);
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the channel profile picture
|
||||
* @param {MessageMedia} newProfilePicture
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async setProfilePicture(newProfilePicture) {
|
||||
return await this._setChannelMetadata({ picture: newProfilePicture }, { editPicture: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates available reactions to use in the channel
|
||||
*
|
||||
* Valid values for passing to the method are:
|
||||
* 0 for NONE reactions to be avaliable
|
||||
* 1 for BASIC reactions to be available: 👍, ❤️, 😂, 😮, 😢, 🙏
|
||||
* 2 for ALL reactions to be available
|
||||
* @param {number} reactionCode
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async setReactionSetting(reactionCode) {
|
||||
if (![0, 1, 2].includes(reactionCode)) return false;
|
||||
const reactionMapper = {
|
||||
0: 3,
|
||||
1: 1,
|
||||
2: 0
|
||||
};
|
||||
const success = await this._setChannelMetadata(
|
||||
{ reactionCodesSetting: reactionMapper[reactionCode] },
|
||||
{ editReactionCodesSetting: true }
|
||||
);
|
||||
success && (this.channelMetadata.reactionCodesSetting = reactionCode);
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutes the channel
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async mute() {
|
||||
const success = await this._muteUnmuteChannel('MUTE');
|
||||
if (success) {
|
||||
this.isMuted = true;
|
||||
this.muteExpiration = -1;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmutes the channel
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async unmute() {
|
||||
const success = await this._muteUnmuteChannel('UNMUTE');
|
||||
if (success) {
|
||||
this.isMuted = false;
|
||||
this.muteExpiration = 0;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Message options
|
||||
* @typedef {Object} MessageSendOptions
|
||||
* @property {?string} caption Image or video caption
|
||||
* @property {?string[]} mentions User IDs of user that will be mentioned in the message
|
||||
* @property {?MessageMedia} media Image or video to be sent
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sends a message to this channel
|
||||
* @param {string|MessageMedia} content
|
||||
* @param {?MessageSendOptions} options
|
||||
* @returns {Promise<Message>} Message that was just sent
|
||||
*/
|
||||
async sendMessage(content, options) {
|
||||
return this.client.sendMessage(this.id._serialized, content, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the channel as seen
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async sendSeen() {
|
||||
return this.client.sendSeen(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} SendChannelAdminInviteOptions
|
||||
* @property {?string} comment The comment to be added to an invitation
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sends a channel admin invitation to a user, allowing them to become an admin of the channel
|
||||
* @param {string} chatId The ID of a user to send the channel admin invitation to
|
||||
* @param {SendChannelAdminInviteOptions} options
|
||||
* @returns {Promise<boolean>} Returns true if an invitation was sent successfully, false otherwise
|
||||
*/
|
||||
async sendChannelAdminInvite(chatId, options = {}) {
|
||||
return this.client.sendChannelAdminInvite(chatId, this.id._serialized, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a channel admin invitation and promotes the current user to a channel admin
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async acceptChannelAdminInvite() {
|
||||
return this.client.acceptChannelAdminInvite(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revokes a channel admin invitation sent to a user by a channel owner
|
||||
* @param {string} userId The user ID the invitation was sent to
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async revokeChannelAdminInvite(userId) {
|
||||
return this.client.revokeChannelAdminInvite(this.id._serialized, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Demotes a channel admin to a regular subscriber (can be used also for self-demotion)
|
||||
* @param {string} userId The user ID to demote
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async demoteChannelAdmin(userId) {
|
||||
return this.client.demoteChannelAdmin(this.id._serialized, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for transferring a channel ownership to another user
|
||||
* @typedef {Object} TransferChannelOwnershipOptions
|
||||
* @property {boolean} [shouldDismissSelfAsAdmin = false] If true, after the channel ownership is being transferred to another user, the current user will be dismissed as a channel admin and will become to a channel subscriber.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Transfers a channel ownership to another user.
|
||||
* Note: the user you are transferring the channel ownership to must be a channel admin.
|
||||
* @param {string} newOwnerId
|
||||
* @param {TransferChannelOwnershipOptions} options
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async transferChannelOwnership(newOwnerId, options = {}) {
|
||||
return this.client.transferChannelOwnership(this.id._serialized, newOwnerId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads channel messages, sorted from earliest to latest
|
||||
* @param {Object} searchOptions Options for searching messages. Right now only limit and fromMe is supported
|
||||
* @param {Number} [searchOptions.limit] The amount of messages to return. If no limit is specified, the available messages will be returned. Note that the actual number of returned messages may be smaller if there aren't enough messages in the conversation. Set this to Infinity to load all messages
|
||||
* @param {Boolean} [searchOptions.fromMe] Return only messages from the bot number or vise versa. To get all messages, leave the option undefined
|
||||
* @returns {Promise<Array<Message>>}
|
||||
*/
|
||||
async fetchMessages(searchOptions) {
|
||||
let messages = await this.client.pupPage.evaluate(async (channelId, searchOptions) => {
|
||||
const msgFilter = (m) => {
|
||||
if (m.isNotification || m.type === 'newsletter_notification') {
|
||||
return false; // dont include notification messages
|
||||
}
|
||||
if (searchOptions && searchOptions.fromMe !== undefined && m.id.fromMe !== searchOptions.fromMe) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const channel = await window.WWebJS.getChat(channelId, { getAsModel: false });
|
||||
let msgs = channel.msgs.getModelsArray().filter(msgFilter);
|
||||
|
||||
if (searchOptions && searchOptions.limit > 0) {
|
||||
while (msgs.length < searchOptions.limit) {
|
||||
const loadedMessages = await window.Store.ConversationMsgs.loadEarlierMsgs(channel);
|
||||
if (!loadedMessages || !loadedMessages.length) break;
|
||||
msgs = [...loadedMessages.filter(msgFilter), ...msgs];
|
||||
}
|
||||
|
||||
if (msgs.length > searchOptions.limit) {
|
||||
msgs.sort((a, b) => (a.t > b.t) ? 1 : -1);
|
||||
msgs = msgs.splice(msgs.length - searchOptions.limit);
|
||||
}
|
||||
}
|
||||
|
||||
return msgs.map(m => window.WWebJS.getMessageModel(m));
|
||||
|
||||
}, this.id._serialized, searchOptions);
|
||||
|
||||
return messages.map((msg) => new Message(this.client, msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the channel you created
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async deleteChannel() {
|
||||
return this.client.deleteChannel(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to change the channel metadata
|
||||
* @param {string|number|MessageMedia} value The new value to set
|
||||
* @param {string} property The property of a channel metadata to change
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async _setChannelMetadata(value, property) {
|
||||
return await this.client.pupPage.evaluate(async (channelId, value, property) => {
|
||||
const channel = await window.WWebJS.getChat(channelId, { getAsModel: false });
|
||||
if (!channel) return false;
|
||||
if (property.editPicture) {
|
||||
value.picture = value.picture
|
||||
? await window.WWebJS.cropAndResizeImage(value.picture, {
|
||||
asDataUrl: true,
|
||||
mimetype: 'image/jpeg',
|
||||
size: 640,
|
||||
quality: 1
|
||||
})
|
||||
: null;
|
||||
}
|
||||
try {
|
||||
await window.Store.ChannelUtils.editNewsletterMetadataAction(channel, property, value);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, value, property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to mute or unmute the channel
|
||||
* @param {string} action The action: 'MUTE' or 'UNMUTE'
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async _muteUnmuteChannel(action) {
|
||||
return await this.client.pupPage.evaluate(async (channelId, action) => {
|
||||
try {
|
||||
action === 'MUTE'
|
||||
? await window.Store.ChannelUtils.muteNewsletter([channelId])
|
||||
: await window.Store.ChannelUtils.unmuteNewsletter([channelId]);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, action);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Channel;
|
||||
329
node_modules/whatsapp-web.js/src/structures/Chat.js
generated
vendored
Normal file
329
node_modules/whatsapp-web.js/src/structures/Chat.js
generated
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
const Message = require('./Message');
|
||||
|
||||
/**
|
||||
* Represents a Chat on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Chat extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* ID that represents the chat
|
||||
* @type {object}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* Title of the chat
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = data.formattedTitle;
|
||||
|
||||
/**
|
||||
* Indicates if the Chat is a Group Chat
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isGroup = data.isGroup;
|
||||
|
||||
/**
|
||||
* Indicates if the Chat is readonly
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isReadOnly = data.isReadOnly;
|
||||
|
||||
/**
|
||||
* Amount of messages unread
|
||||
* @type {number}
|
||||
*/
|
||||
this.unreadCount = data.unreadCount;
|
||||
|
||||
/**
|
||||
* Unix timestamp for when the last activity occurred
|
||||
* @type {number}
|
||||
*/
|
||||
this.timestamp = data.t;
|
||||
|
||||
/**
|
||||
* Indicates if the Chat is archived
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.archived = data.archive;
|
||||
|
||||
/**
|
||||
* Indicates if the Chat is pinned
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.pinned = !!data.pin;
|
||||
|
||||
/**
|
||||
* Indicates if the chat is muted or not
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isMuted = data.isMuted;
|
||||
|
||||
/**
|
||||
* Unix timestamp for when the mute expires
|
||||
* @type {number}
|
||||
*/
|
||||
this.muteExpiration = data.muteExpiration;
|
||||
|
||||
/**
|
||||
* Last message fo chat
|
||||
* @type {Message}
|
||||
*/
|
||||
this.lastMessage = data.lastMessage ? new Message(this.client, data.lastMessage) : undefined;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to this chat
|
||||
* @param {string|MessageMedia|Location} content
|
||||
* @param {MessageSendOptions} [options]
|
||||
* @returns {Promise<Message>} Message that was just sent
|
||||
*/
|
||||
async sendMessage(content, options) {
|
||||
return this.client.sendMessage(this.id._serialized, content, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chat as seen
|
||||
* @returns {Promise<Boolean>} result
|
||||
*/
|
||||
async sendSeen() {
|
||||
return this.client.sendSeen(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all messages from the chat
|
||||
* @returns {Promise<boolean>} result
|
||||
*/
|
||||
async clearMessages() {
|
||||
return this.client.pupPage.evaluate(chatId => {
|
||||
return window.WWebJS.sendClearChat(chatId);
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the chat
|
||||
* @returns {Promise<Boolean>} result
|
||||
*/
|
||||
async delete() {
|
||||
return this.client.pupPage.evaluate(chatId => {
|
||||
return window.WWebJS.sendDeleteChat(chatId);
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Archives this chat
|
||||
*/
|
||||
async archive() {
|
||||
return this.client.archiveChat(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* un-archives this chat
|
||||
*/
|
||||
async unarchive() {
|
||||
return this.client.unarchiveChat(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pins this chat
|
||||
* @returns {Promise<boolean>} New pin state. Could be false if the max number of pinned chats was reached.
|
||||
*/
|
||||
async pin() {
|
||||
return this.client.pinChat(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpins this chat
|
||||
* @returns {Promise<boolean>} New pin state
|
||||
*/
|
||||
async unpin() {
|
||||
return this.client.unpinChat(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutes this chat forever, unless a date is specified
|
||||
* @param {?Date} unmuteDate Date when the chat will be unmuted, don't provide a value to mute forever
|
||||
* @returns {Promise<{isMuted: boolean, muteExpiration: number}>}
|
||||
*/
|
||||
async mute(unmuteDate) {
|
||||
const result = await this.client.muteChat(this.id._serialized, unmuteDate);
|
||||
this.isMuted = result.isMuted;
|
||||
this.muteExpiration = result.muteExpiration;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmutes this chat
|
||||
* @returns {Promise<{isMuted: boolean, muteExpiration: number}>}
|
||||
*/
|
||||
async unmute() {
|
||||
const result = await this.client.unmuteChat(this.id._serialized);
|
||||
this.isMuted = result.isMuted;
|
||||
this.muteExpiration = result.muteExpiration;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this chat as unread
|
||||
*/
|
||||
async markUnread(){
|
||||
return this.client.markChatUnread(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads chat messages, sorted from earliest to latest.
|
||||
* @param {Object} searchOptions Options for searching messages. Right now only limit and fromMe is supported.
|
||||
* @param {Number} [searchOptions.limit] The amount of messages to return. If no limit is specified, the available messages will be returned. Note that the actual number of returned messages may be smaller if there aren't enough messages in the conversation. Set this to Infinity to load all messages.
|
||||
* @param {Boolean} [searchOptions.fromMe] Return only messages from the bot number or vise versa. To get all messages, leave the option undefined.
|
||||
* @returns {Promise<Array<Message>>}
|
||||
*/
|
||||
async fetchMessages(searchOptions) {
|
||||
let messages = await this.client.pupPage.evaluate(async (chatId, searchOptions) => {
|
||||
const msgFilter = (m) => {
|
||||
if (m.isNotification) {
|
||||
return false; // dont include notification messages
|
||||
}
|
||||
if (searchOptions && searchOptions.fromMe !== undefined && m.id.fromMe !== searchOptions.fromMe) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
let msgs = chat.msgs.getModelsArray().filter(msgFilter);
|
||||
|
||||
if (searchOptions && searchOptions.limit > 0) {
|
||||
while (msgs.length < searchOptions.limit) {
|
||||
const loadedMessages = await window.Store.ConversationMsgs.loadEarlierMsgs(chat,chat.msgs);
|
||||
if (!loadedMessages || !loadedMessages.length) break;
|
||||
msgs = [...loadedMessages.filter(msgFilter), ...msgs];
|
||||
}
|
||||
|
||||
if (msgs.length > searchOptions.limit) {
|
||||
msgs.sort((a, b) => (a.t > b.t) ? 1 : -1);
|
||||
msgs = msgs.splice(msgs.length - searchOptions.limit);
|
||||
}
|
||||
}
|
||||
|
||||
return msgs.map(m => window.WWebJS.getMessageModel(m));
|
||||
|
||||
}, this.id._serialized, searchOptions);
|
||||
|
||||
return messages.map(m => new Message(this.client, m));
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate typing in chat. This will last for 25 seconds.
|
||||
*/
|
||||
async sendStateTyping() {
|
||||
return this.client.pupPage.evaluate(chatId => {
|
||||
window.WWebJS.sendChatstate('typing', chatId);
|
||||
return true;
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate recording audio in chat. This will last for 25 seconds.
|
||||
*/
|
||||
async sendStateRecording() {
|
||||
return this.client.pupPage.evaluate(chatId => {
|
||||
window.WWebJS.sendChatstate('recording', chatId);
|
||||
return true;
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops typing or recording in chat immediately.
|
||||
*/
|
||||
async clearState() {
|
||||
return this.client.pupPage.evaluate(chatId => {
|
||||
window.WWebJS.sendChatstate('stop', chatId);
|
||||
return true;
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Contact that corresponds to this Chat.
|
||||
* @returns {Promise<Contact>}
|
||||
*/
|
||||
async getContact() {
|
||||
return await this.client.getContactById(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of all Labels assigned to this Chat
|
||||
* @returns {Promise<Array<Label>>}
|
||||
*/
|
||||
async getLabels() {
|
||||
return this.client.getChatLabels(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or remove labels to this Chat
|
||||
* @param {Array<number|string>} labelIds
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async changeLabels(labelIds) {
|
||||
return this.client.addOrRemoveLabels(labelIds, [this.id._serialized]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets instances of all pinned messages in a chat
|
||||
* @returns {Promise<Array<Message>>}
|
||||
*/
|
||||
async getPinnedMessages() {
|
||||
return this.client.getPinnedMessages(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync chat history conversation
|
||||
* @return {Promise<boolean>} True if operation completed successfully, false otherwise.
|
||||
*/
|
||||
async syncHistory() {
|
||||
return this.client.syncHistory(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or edit a customer note
|
||||
* @see https://faq.whatsapp.com/1433099287594476
|
||||
* @param {string} note The note to add
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async addOrEditCustomerNote(note) {
|
||||
if (this.isGroup || this.isChannel) return;
|
||||
|
||||
return this.client.addOrEditCustomerNote(this.id._serialized, note);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a customer note
|
||||
* @see https://faq.whatsapp.com/1433099287594476
|
||||
* @returns {Promise<{
|
||||
* chatId: string,
|
||||
* content: string,
|
||||
* createdAt: number,
|
||||
* id: string,
|
||||
* modifiedAt: number,
|
||||
* type: string
|
||||
* }>}
|
||||
*/
|
||||
async getCustomerNote() {
|
||||
if (this.isGroup || this.isChannel) return null;
|
||||
|
||||
return this.client.getCustomerNote(this.id._serialized);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Chat;
|
||||
71
node_modules/whatsapp-web.js/src/structures/ClientInfo.js
generated
vendored
Normal file
71
node_modules/whatsapp-web.js/src/structures/ClientInfo.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
|
||||
/**
|
||||
* Current connection information
|
||||
* @extends {Base}
|
||||
*/
|
||||
class ClientInfo extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* Name configured to be shown in push notifications
|
||||
* @type {string}
|
||||
*/
|
||||
this.pushname = data.pushname;
|
||||
|
||||
/**
|
||||
* Current user ID
|
||||
* @type {object}
|
||||
*/
|
||||
this.wid = data.wid;
|
||||
|
||||
/**
|
||||
* @type {object}
|
||||
* @deprecated Use .wid instead
|
||||
*/
|
||||
this.me = data.wid;
|
||||
|
||||
/**
|
||||
* Information about the phone this client is connected to. Not available in multi-device.
|
||||
* @type {object}
|
||||
* @property {string} wa_version WhatsApp Version running on the phone
|
||||
* @property {string} os_version OS Version running on the phone (iOS or Android version)
|
||||
* @property {string} device_manufacturer Device manufacturer
|
||||
* @property {string} device_model Device model
|
||||
* @property {string} os_build_number OS build number
|
||||
* @deprecated
|
||||
*/
|
||||
this.phone = data.phone;
|
||||
|
||||
/**
|
||||
* Platform WhatsApp is running on
|
||||
* @type {string}
|
||||
*/
|
||||
this.platform = data.platform;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current battery percentage and charging status for the attached device
|
||||
* @returns {object} batteryStatus
|
||||
* @returns {number} batteryStatus.battery - The current battery percentage
|
||||
* @returns {boolean} batteryStatus.plugged - Indicates if the phone is plugged in (true) or not (false)
|
||||
* @deprecated
|
||||
*/
|
||||
async getBatteryStatus() {
|
||||
return await this.client.pupPage.evaluate(() => {
|
||||
const { battery, plugged } = window.Store.Conn;
|
||||
return { battery, plugged };
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ClientInfo;
|
||||
215
node_modules/whatsapp-web.js/src/structures/Contact.js
generated
vendored
Normal file
215
node_modules/whatsapp-web.js/src/structures/Contact.js
generated
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
|
||||
/**
|
||||
* ID that represents a contact
|
||||
* @typedef {Object} ContactId
|
||||
* @property {string} server
|
||||
* @property {string} user
|
||||
* @property {string} _serialized
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a Contact on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Contact extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if(data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* ID that represents the contact
|
||||
* @type {ContactId}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* Contact's phone number
|
||||
* @type {string}
|
||||
*/
|
||||
this.number = data.userid;
|
||||
|
||||
/**
|
||||
* Indicates if the contact is a business contact
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isBusiness = data.isBusiness;
|
||||
|
||||
/**
|
||||
* Indicates if the contact is an enterprise contact
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isEnterprise = data.isEnterprise;
|
||||
|
||||
this.labels = data.labels;
|
||||
|
||||
/**
|
||||
* The contact's name, as saved by the current user
|
||||
* @type {?string}
|
||||
*/
|
||||
this.name = data.name;
|
||||
|
||||
/**
|
||||
* The name that the contact has configured to be shown publically
|
||||
* @type {string}
|
||||
*/
|
||||
this.pushname = data.pushname;
|
||||
|
||||
this.sectionHeader = data.sectionHeader;
|
||||
|
||||
/**
|
||||
* A shortened version of name
|
||||
* @type {?string}
|
||||
*/
|
||||
this.shortName = data.shortName;
|
||||
|
||||
this.statusMute = data.statusMute;
|
||||
this.type = data.type;
|
||||
this.verifiedLevel = data.verifiedLevel;
|
||||
this.verifiedName = data.verifiedName;
|
||||
|
||||
/**
|
||||
* Indicates if the contact is the current user's contact
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isMe = data.isMe;
|
||||
|
||||
/**
|
||||
* Indicates if the contact is a user contact
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isUser = data.isUser;
|
||||
|
||||
/**
|
||||
* Indicates if the contact is a group contact
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isGroup = data.isGroup;
|
||||
|
||||
/**
|
||||
* Indicates if the number is registered on WhatsApp
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isWAContact = data.isWAContact;
|
||||
|
||||
/**
|
||||
* Indicates if the number is saved in the current phone's contacts
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isMyContact = data.isMyContact;
|
||||
|
||||
/**
|
||||
* Indicates if you have blocked this contact
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isBlocked = data.isBlocked;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contact's profile picture URL, if privacy settings allow it
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async getProfilePicUrl() {
|
||||
return await this.client.getProfilePicUrl(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contact's formatted phone number, (12345678901@c.us) => (+1 (234) 5678-901)
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async getFormattedNumber() {
|
||||
return await this.client.getFormattedNumber(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contact's countrycode, (1541859685@c.us) => (1)
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async getCountryCode() {
|
||||
return await this.client.getCountryCode(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Chat that corresponds to this Contact.
|
||||
* Will return null when getting chat for currently logged in user.
|
||||
* @returns {Promise<Chat>}
|
||||
*/
|
||||
async getChat() {
|
||||
if(this.isMe) return null;
|
||||
|
||||
return await this.client.getChatById(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks this contact from WhatsApp
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async block() {
|
||||
if(this.isGroup) return false;
|
||||
|
||||
await this.client.pupPage.evaluate(async (contactId) => {
|
||||
const contact = window.Store.Contact.get(contactId);
|
||||
await window.Store.BlockContact.blockContact({contact});
|
||||
}, this.id._serialized);
|
||||
|
||||
this.isBlocked = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unblocks this contact from WhatsApp
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async unblock() {
|
||||
if(this.isGroup) return false;
|
||||
|
||||
await this.client.pupPage.evaluate(async (contactId) => {
|
||||
const contact = window.Store.Contact.get(contactId);
|
||||
await window.Store.BlockContact.unblockContact(contact);
|
||||
}, this.id._serialized);
|
||||
|
||||
this.isBlocked = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Contact's current "about" info. Returns null if you don't have permission to read their status.
|
||||
* @returns {Promise<?string>}
|
||||
*/
|
||||
async getAbout() {
|
||||
const about = await this.client.pupPage.evaluate(async (contactId) => {
|
||||
const wid = window.Store.WidFactory.createWid(contactId);
|
||||
return window.Store.StatusUtils.getStatus({'token':'', 'wid': wid});
|
||||
}, this.id._serialized);
|
||||
|
||||
if (typeof about.status !== 'string')
|
||||
return null;
|
||||
|
||||
return about.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Contact's common groups with you. Returns empty array if you don't have any common group.
|
||||
* @returns {Promise<WAWebJS.ChatId[]>}
|
||||
*/
|
||||
async getCommonGroups() {
|
||||
return await this.client.getCommonGroups(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Contact's current status broadcast.
|
||||
* @returns {Promise<Broadcast>}
|
||||
*/
|
||||
async getBroadcast() {
|
||||
return await this.client.getBroadcastById(this.id._serialized);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Contact;
|
||||
485
node_modules/whatsapp-web.js/src/structures/GroupChat.js
generated
vendored
Normal file
485
node_modules/whatsapp-web.js/src/structures/GroupChat.js
generated
vendored
Normal file
@@ -0,0 +1,485 @@
|
||||
'use strict';
|
||||
|
||||
const Chat = require('./Chat');
|
||||
|
||||
/**
|
||||
* Group participant information
|
||||
* @typedef {Object} GroupParticipant
|
||||
* @property {ContactId} id
|
||||
* @property {boolean} isAdmin
|
||||
* @property {boolean} isSuperAdmin
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a Group Chat on WhatsApp
|
||||
* @extends {Chat}
|
||||
*/
|
||||
class GroupChat extends Chat {
|
||||
_patch(data) {
|
||||
this.groupMetadata = data.groupMetadata;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the group owner
|
||||
* @type {ContactId}
|
||||
*/
|
||||
get owner() {
|
||||
return this.groupMetadata.owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the date at which the group was created
|
||||
* @type {date}
|
||||
*/
|
||||
get createdAt() {
|
||||
return new Date(this.groupMetadata.creation * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the group description
|
||||
* @type {string}
|
||||
*/
|
||||
get description() {
|
||||
return this.groupMetadata.desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the group participants
|
||||
* @type {Array<GroupParticipant>}
|
||||
*/
|
||||
get participants() {
|
||||
return this.groupMetadata.participants;
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that handles the result for {@link addParticipants} method
|
||||
* @typedef {Object} AddParticipantsResult
|
||||
* @property {number} code The code of the result
|
||||
* @property {string} message The result message
|
||||
* @property {boolean} isInviteV4Sent Indicates if the inviteV4 was sent to the partitipant
|
||||
*/
|
||||
|
||||
/**
|
||||
* An object that handles options for adding participants
|
||||
* @typedef {Object} AddParticipnatsOptions
|
||||
* @property {Array<number>|number} [sleep = [250, 500]] The number of milliseconds to wait before adding the next participant. If it is an array, a random sleep time between the sleep[0] and sleep[1] values will be added (the difference must be >=100 ms, otherwise, a random sleep time between sleep[1] and sleep[1] + 100 will be added). If sleep is a number, a sleep time equal to its value will be added. By default, sleep is an array with a value of [250, 500]
|
||||
* @property {boolean} [autoSendInviteV4 = true] If true, the inviteV4 will be sent to those participants who have restricted others from being automatically added to groups, otherwise the inviteV4 won't be sent (true by default)
|
||||
* @property {string} [comment = ''] The comment to be added to an inviteV4 (empty string by default)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds a list of participants by ID to the group
|
||||
* @param {string|Array<string>} participantIds
|
||||
* @param {AddParticipnatsOptions} options An object thay handles options for adding participants
|
||||
* @returns {Promise<Object.<string, AddParticipantsResult>|string>} Returns an object with the resulting data or an error message as a string
|
||||
*/
|
||||
async addParticipants(participantIds, options = {}) {
|
||||
return await this.client.pupPage.evaluate(async (groupId, participantIds, options) => {
|
||||
const { sleep = [250, 500], autoSendInviteV4 = true, comment = '' } = options;
|
||||
const participantData = {};
|
||||
|
||||
!Array.isArray(participantIds) && (participantIds = [participantIds]);
|
||||
const groupWid = window.Store.WidFactory.createWid(groupId);
|
||||
const group = window.Store.Chat.get(groupWid) || (await window.Store.Chat.find(groupWid));
|
||||
const participantWids = participantIds.map((p) => window.Store.WidFactory.createWid(p));
|
||||
|
||||
const errorCodes = {
|
||||
default: 'An unknown error occupied while adding a participant',
|
||||
isGroupEmpty: 'AddParticipantsError: The participant can\'t be added to an empty group',
|
||||
iAmNotAdmin: 'AddParticipantsError: You have no admin rights to add a participant to a group',
|
||||
200: 'The participant was added successfully',
|
||||
403: 'The participant can be added by sending private invitation only',
|
||||
404: 'The phone number is not registered on WhatsApp',
|
||||
408: 'You cannot add this participant because they recently left the group',
|
||||
409: 'The participant is already a group member',
|
||||
417: 'The participant can\'t be added to the community. You can invite them privately to join this group through its invite link',
|
||||
419: 'The participant can\'t be added because the group is full'
|
||||
};
|
||||
|
||||
await window.Store.GroupQueryAndUpdate({ id: groupId });
|
||||
|
||||
let groupParticipants = group.groupMetadata?.participants.serialize();
|
||||
|
||||
if (!groupParticipants) {
|
||||
return errorCodes.isGroupEmpty;
|
||||
}
|
||||
|
||||
if (!group.iAmAdmin()) {
|
||||
return errorCodes.iAmNotAdmin;
|
||||
}
|
||||
|
||||
groupParticipants.map(({ id }) => {
|
||||
return id.server === 'lid' ? window.Store.LidUtils.getPhoneNumber(id) : id;
|
||||
});
|
||||
|
||||
const _getSleepTime = (sleep) => {
|
||||
if (!Array.isArray(sleep) || sleep.length === 2 && sleep[0] === sleep[1]) {
|
||||
return sleep;
|
||||
}
|
||||
if (sleep.length === 1) {
|
||||
return sleep[0];
|
||||
}
|
||||
(sleep[1] - sleep[0]) < 100 && (sleep[0] = sleep[1]) && (sleep[1] += 100);
|
||||
return Math.floor(Math.random() * (sleep[1] - sleep[0] + 1)) + sleep[0];
|
||||
};
|
||||
|
||||
for (let pWid of participantWids) {
|
||||
const pId = pWid._serialized;
|
||||
pWid = pWid.server === 'lid' ? window.Store.LidUtils.getPhoneNumber(pWid) : pWid;
|
||||
|
||||
participantData[pId] = {
|
||||
code: undefined,
|
||||
message: undefined,
|
||||
isInviteV4Sent: false
|
||||
};
|
||||
|
||||
if (groupParticipants.some(p => p._serialized === pId)) {
|
||||
participantData[pId].code = 409;
|
||||
participantData[pId].message = errorCodes[409];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(await window.Store.QueryExist(pWid))?.wid) {
|
||||
participantData[pId].code = 404;
|
||||
participantData[pId].message = errorCodes[404];
|
||||
continue;
|
||||
}
|
||||
|
||||
const rpcResult =
|
||||
await window.WWebJS.getAddParticipantsRpcResult(groupWid, pWid);
|
||||
const { code: rpcResultCode } = rpcResult;
|
||||
|
||||
participantData[pId].code = rpcResultCode;
|
||||
participantData[pId].message =
|
||||
errorCodes[rpcResultCode] || errorCodes.default;
|
||||
|
||||
if (autoSendInviteV4 && rpcResultCode === 403) {
|
||||
let userChat, isInviteV4Sent = false;
|
||||
window.Store.Contact.gadd(pWid, { silent: true });
|
||||
|
||||
if (rpcResult.name === 'ParticipantRequestCodeCanBeSent' &&
|
||||
(userChat = window.Store.Chat.get(pWid) || (await window.Store.Chat.find(pWid)))) {
|
||||
const groupName = group.formattedTitle || group.name;
|
||||
const res = await window.Store.GroupInviteV4.sendGroupInviteMessage(
|
||||
userChat,
|
||||
group.id._serialized,
|
||||
groupName,
|
||||
rpcResult.inviteV4Code,
|
||||
rpcResult.inviteV4CodeExp,
|
||||
comment,
|
||||
await window.WWebJS.getProfilePicThumbToBase64(groupWid)
|
||||
);
|
||||
isInviteV4Sent = res.messageSendResult === 'OK';
|
||||
}
|
||||
|
||||
participantData[pId].isInviteV4Sent = isInviteV4Sent;
|
||||
}
|
||||
|
||||
sleep &&
|
||||
participantWids.length > 1 &&
|
||||
participantWids.indexOf(pWid) !== participantWids.length - 1 &&
|
||||
(await new Promise((resolve) => setTimeout(resolve, _getSleepTime(sleep))));
|
||||
}
|
||||
|
||||
return participantData;
|
||||
}, this.id._serialized, participantIds, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a list of participants by ID to the group
|
||||
* @param {Array<string>} participantIds
|
||||
* @returns {Promise<{ status: number }>}
|
||||
*/
|
||||
async removeParticipants(participantIds) {
|
||||
return await this.client.pupPage.evaluate(async (chatId, participantIds) => {
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
const participants = (await Promise.all(participantIds.map(async p => {
|
||||
const { lid, phone } = await window.WWebJS.enforceLidAndPnRetrieval(p);
|
||||
|
||||
return chat.groupMetadata.participants.get(lid?._serialized) ||
|
||||
chat.groupMetadata.participants.get(phone?._serialized);
|
||||
}))).filter(Boolean);
|
||||
await window.Store.GroupParticipants.removeParticipants(chat, participants);
|
||||
return { status: 200 };
|
||||
}, this.id._serialized, participantIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Promotes participants by IDs to admins
|
||||
* @param {Array<string>} participantIds
|
||||
* @returns {Promise<{ status: number }>} Object with status code indicating if the operation was successful
|
||||
*/
|
||||
async promoteParticipants(participantIds) {
|
||||
return await this.client.pupPage.evaluate(async (chatId, participantIds) => {
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
const participants = (await Promise.all(participantIds.map(async p => {
|
||||
const { lid, phone } = await window.WWebJS.enforceLidAndPnRetrieval(p);
|
||||
|
||||
return chat.groupMetadata.participants.get(lid?._serialized) ||
|
||||
chat.groupMetadata.participants.get(phone?._serialized);
|
||||
}))).filter(Boolean);
|
||||
await window.Store.GroupParticipants.promoteParticipants(chat, participants);
|
||||
return { status: 200 };
|
||||
}, this.id._serialized, participantIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Demotes participants by IDs to regular users
|
||||
* @param {Array<string>} participantIds
|
||||
* @returns {Promise<{ status: number }>} Object with status code indicating if the operation was successful
|
||||
*/
|
||||
async demoteParticipants(participantIds) {
|
||||
return await this.client.pupPage.evaluate(async (chatId, participantIds) => {
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
const participants = (await Promise.all(participantIds.map(async p => {
|
||||
const { lid, phone } = await window.WWebJS.enforceLidAndPnRetrieval(p);
|
||||
|
||||
return chat.groupMetadata.participants.get(lid?._serialized) ||
|
||||
chat.groupMetadata.participants.get(phone?._serialized);
|
||||
}))).filter(Boolean);
|
||||
await window.Store.GroupParticipants.demoteParticipants(chat, participants);
|
||||
return { status: 200 };
|
||||
}, this.id._serialized, participantIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the group subject
|
||||
* @param {string} subject
|
||||
* @returns {Promise<boolean>} Returns true if the subject was properly updated. This can return false if the user does not have the necessary permissions.
|
||||
*/
|
||||
async setSubject(subject) {
|
||||
const success = await this.client.pupPage.evaluate(async (chatId, subject) => {
|
||||
const chatWid = window.Store.WidFactory.createWid(chatId);
|
||||
try {
|
||||
await window.Store.GroupUtils.setGroupSubject(chatWid, subject);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, subject);
|
||||
|
||||
if(!success) return false;
|
||||
this.name = subject;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the group description
|
||||
* @param {string} description
|
||||
* @returns {Promise<boolean>} Returns true if the description was properly updated. This can return false if the user does not have the necessary permissions.
|
||||
*/
|
||||
async setDescription(description) {
|
||||
const success = await this.client.pupPage.evaluate(async (chatId, description) => {
|
||||
const chatWid = window.Store.WidFactory.createWid(chatId);
|
||||
let descId = window.Store.GroupMetadata.get(chatWid).descId;
|
||||
let newId = await window.Store.MsgKey.newId();
|
||||
try {
|
||||
await window.Store.GroupUtils.setGroupDescription(chatWid, description, newId, descId);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, description);
|
||||
|
||||
if(!success) return false;
|
||||
this.groupMetadata.desc = description;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the group setting to allow only admins to add members to the group.
|
||||
* @param {boolean} [adminsOnly=true] Enable or disable this option
|
||||
* @returns {Promise<boolean>} Returns true if the setting was properly updated. This can return false if the user does not have the necessary permissions.
|
||||
*/
|
||||
async setAddMembersAdminsOnly(adminsOnly=true) {
|
||||
const success = await this.client.pupPage.evaluate(async (groupId, adminsOnly) => {
|
||||
const chat = await window.WWebJS.getChat(groupId, { getAsModel: false });
|
||||
try {
|
||||
await window.Store.GroupUtils.setGroupProperty(chat, 'member_add_mode', adminsOnly ? 0 : 1);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, adminsOnly);
|
||||
|
||||
success && (this.groupMetadata.memberAddMode = adminsOnly ? 'admin_add' : 'all_member_add');
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the group settings to only allow admins to send messages.
|
||||
* @param {boolean} [adminsOnly=true] Enable or disable this option
|
||||
* @returns {Promise<boolean>} Returns true if the setting was properly updated. This can return false if the user does not have the necessary permissions.
|
||||
*/
|
||||
async setMessagesAdminsOnly(adminsOnly=true) {
|
||||
const success = await this.client.pupPage.evaluate(async (chatId, adminsOnly) => {
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
try {
|
||||
await window.Store.GroupUtils.setGroupProperty(chat, 'announcement', adminsOnly ? 1 : 0);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, adminsOnly);
|
||||
|
||||
if(!success) return false;
|
||||
|
||||
this.groupMetadata.announce = adminsOnly;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the group settings to only allow admins to edit group info (title, description, photo).
|
||||
* @param {boolean} [adminsOnly=true] Enable or disable this option
|
||||
* @returns {Promise<boolean>} Returns true if the setting was properly updated. This can return false if the user does not have the necessary permissions.
|
||||
*/
|
||||
async setInfoAdminsOnly(adminsOnly=true) {
|
||||
const success = await this.client.pupPage.evaluate(async (chatId, adminsOnly) => {
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
try {
|
||||
await window.Store.GroupUtils.setGroupProperty(chat, 'restrict', adminsOnly ? 1 : 0);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, adminsOnly);
|
||||
|
||||
if(!success) return false;
|
||||
|
||||
this.groupMetadata.restrict = adminsOnly;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the group's picture.
|
||||
* @returns {Promise<boolean>} Returns true if the picture was properly deleted. This can return false if the user does not have the necessary permissions.
|
||||
*/
|
||||
async deletePicture() {
|
||||
const success = await this.client.pupPage.evaluate((chatid) => {
|
||||
return window.WWebJS.deletePicture(chatid);
|
||||
}, this.id._serialized);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the group's picture.
|
||||
* @param {MessageMedia} media
|
||||
* @returns {Promise<boolean>} Returns true if the picture was properly updated. This can return false if the user does not have the necessary permissions.
|
||||
*/
|
||||
async setPicture(media) {
|
||||
const success = await this.client.pupPage.evaluate((chatid, media) => {
|
||||
return window.WWebJS.setPicture(chatid, media);
|
||||
}, this.id._serialized, media);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the invite code for a specific group
|
||||
* @returns {Promise<string>} Group's invite code
|
||||
*/
|
||||
async getInviteCode() {
|
||||
const codeRes = await this.client.pupPage.evaluate(async chatId => {
|
||||
const chatWid = window.Store.WidFactory.createWid(chatId);
|
||||
try {
|
||||
return window.compareWwebVersions(window.Debug.VERSION, '>=', '2.3000.1020730154')
|
||||
? await window.Store.GroupInvite.fetchMexGroupInviteCode(chatId)
|
||||
: await window.Store.GroupInvite.queryGroupInviteCode(chatWid, true);
|
||||
}
|
||||
catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return undefined;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized);
|
||||
|
||||
return codeRes?.code
|
||||
? codeRes?.code
|
||||
: codeRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the current group invite code and generates a new one
|
||||
* @returns {Promise<string>} New invite code
|
||||
*/
|
||||
async revokeInvite() {
|
||||
const codeRes = await this.client.pupPage.evaluate(chatId => {
|
||||
const chatWid = window.Store.WidFactory.createWid(chatId);
|
||||
return window.Store.GroupInvite.resetGroupInviteCode(chatWid);
|
||||
}, this.id._serialized);
|
||||
|
||||
return codeRes.code;
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that handles the information about the group membership request
|
||||
* @typedef {Object} GroupMembershipRequest
|
||||
* @property {Object} id The wid of a user who requests to enter the group
|
||||
* @property {Object} addedBy The wid of a user who created that request
|
||||
* @property {Object|null} parentGroupId The wid of a community parent group to which the current group is linked
|
||||
* @property {string} requestMethod The method used to create the request: NonAdminAdd/InviteLink/LinkedGroupJoin
|
||||
* @property {number} t The timestamp the request was created at
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets an array of membership requests
|
||||
* @returns {Promise<Array<GroupMembershipRequest>>} An array of membership requests
|
||||
*/
|
||||
async getGroupMembershipRequests() {
|
||||
return await this.client.getGroupMembershipRequests(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that handles the result for membership request action
|
||||
* @typedef {Object} MembershipRequestActionResult
|
||||
* @property {string} requesterId User ID whos membership request was approved/rejected
|
||||
* @property {number} error An error code that occurred during the operation for the participant
|
||||
* @property {string} message A message with a result of membership request action
|
||||
*/
|
||||
|
||||
/**
|
||||
* An object that handles options for {@link approveGroupMembershipRequests} and {@link rejectGroupMembershipRequests} methods
|
||||
* @typedef {Object} MembershipRequestActionOptions
|
||||
* @property {Array<string>|string|null} requesterIds User ID/s who requested to join the group, if no value is provided, the method will search for all membership requests for that group
|
||||
* @property {Array<number>|number|null} sleep The number of milliseconds to wait before performing an operation for the next requester. If it is an array, a random sleep time between the sleep[0] and sleep[1] values will be added (the difference must be >=100 ms, otherwise, a random sleep time between sleep[1] and sleep[1] + 100 will be added). If sleep is a number, a sleep time equal to its value will be added. By default, sleep is an array with a value of [250, 500]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Approves membership requests if any
|
||||
* @param {MembershipRequestActionOptions} options Options for performing a membership request action
|
||||
* @returns {Promise<Array<MembershipRequestActionResult>>} Returns an array of requester IDs whose membership requests were approved and an error for each requester, if any occurred during the operation. If there are no requests, an empty array will be returned
|
||||
*/
|
||||
async approveGroupMembershipRequests(options = {}) {
|
||||
return await this.client.approveGroupMembershipRequests(this.id._serialized, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rejects membership requests if any
|
||||
* @param {MembershipRequestActionOptions} options Options for performing a membership request action
|
||||
* @returns {Promise<Array<MembershipRequestActionResult>>} Returns an array of requester IDs whose membership requests were rejected and an error for each requester, if any occurred during the operation. If there are no requests, an empty array will be returned
|
||||
*/
|
||||
async rejectGroupMembershipRequests(options = {}) {
|
||||
return await this.client.rejectGroupMembershipRequests(this.id._serialized, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the bot leave the group
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async leave() {
|
||||
await this.client.pupPage.evaluate(async chatId => {
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
return window.Store.GroupUtils.sendExitGroup(chat);
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GroupChat;
|
||||
104
node_modules/whatsapp-web.js/src/structures/GroupNotification.js
generated
vendored
Normal file
104
node_modules/whatsapp-web.js/src/structures/GroupNotification.js
generated
vendored
Normal file
@@ -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.id.remote) === 'object' ? data.id.remote._serialized : data.id.remote;
|
||||
|
||||
/**
|
||||
* 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<string>}
|
||||
*/
|
||||
this.recipientIds = [];
|
||||
|
||||
if (data.recipients) {
|
||||
this.recipientIds = data.recipients;
|
||||
}
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Chat this groupNotification was sent in
|
||||
* @returns {Promise<Chat>}
|
||||
*/
|
||||
getChat() {
|
||||
return this.client.getChatById(this.chatId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Contact this GroupNotification was produced by
|
||||
* @returns {Promise<Contact>}
|
||||
*/
|
||||
getContact() {
|
||||
return this.client.getContactById(this.author);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Contacts affected by this GroupNotification.
|
||||
* @returns {Promise<Array<Contact>>}
|
||||
*/
|
||||
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<Message>}
|
||||
*/
|
||||
async reply(content, options={}) {
|
||||
return this.client.sendMessage(this.chatId, content, options);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GroupNotification;
|
||||
50
node_modules/whatsapp-web.js/src/structures/Label.js
generated
vendored
Normal file
50
node_modules/whatsapp-web.js/src/structures/Label.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const Chat = require('./Chat');
|
||||
|
||||
/**
|
||||
* WhatsApp Business Label information
|
||||
*/
|
||||
class Label extends Base {
|
||||
/**
|
||||
* @param {Base} client
|
||||
* @param {object} labelData
|
||||
*/
|
||||
constructor(client, labelData){
|
||||
super(client);
|
||||
|
||||
if(labelData) this._patch(labelData);
|
||||
}
|
||||
|
||||
_patch(labelData){
|
||||
/**
|
||||
* Label ID
|
||||
* @type {string}
|
||||
*/
|
||||
this.id = labelData.id;
|
||||
|
||||
/**
|
||||
* Label name
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = labelData.name;
|
||||
|
||||
/**
|
||||
* Label hex color
|
||||
* @type {string}
|
||||
*/
|
||||
this.hexColor = labelData.hexColor;
|
||||
}
|
||||
/**
|
||||
* Get all chats that have been assigned this Label
|
||||
* @returns {Promise<Array<Chat>>}
|
||||
*/
|
||||
async getChats(){
|
||||
return this.client.getChatsByLabelId(this.id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Label;
|
||||
79
node_modules/whatsapp-web.js/src/structures/List.js
generated
vendored
Normal file
79
node_modules/whatsapp-web.js/src/structures/List.js
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
'use strict';
|
||||
|
||||
const Util = require('../util/Util');
|
||||
|
||||
/**
|
||||
* Message type List
|
||||
*/
|
||||
class List {
|
||||
/**
|
||||
* @param {string} body
|
||||
* @param {string} buttonText
|
||||
* @param {Array<any>} sections
|
||||
* @param {string?} title
|
||||
* @param {string?} footer
|
||||
*/
|
||||
constructor(body, buttonText, sections, title, footer) {
|
||||
/**
|
||||
* Message body
|
||||
* @type {string}
|
||||
*/
|
||||
this.description = body;
|
||||
|
||||
/**
|
||||
* List button text
|
||||
* @type {string}
|
||||
*/
|
||||
this.buttonText = buttonText;
|
||||
|
||||
/**
|
||||
* title of message
|
||||
* @type {string}
|
||||
*/
|
||||
this.title = title;
|
||||
|
||||
|
||||
/**
|
||||
* footer of message
|
||||
* @type {string}
|
||||
*/
|
||||
this.footer = footer;
|
||||
|
||||
/**
|
||||
* sections of message
|
||||
* @type {Array<any>}
|
||||
*/
|
||||
this.sections = this._format(sections);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates section array from simple array
|
||||
* @param {Array<any>} sections
|
||||
* @returns {Array<any>}
|
||||
* @example
|
||||
* Input: [{title:'sectionTitle',rows:[{id:'customId', title:'ListItem2', description: 'desc'},{title:'ListItem2'}]}}]
|
||||
* Returns: [{'title':'sectionTitle','rows':[{'rowId':'customId','title':'ListItem1','description':'desc'},{'rowId':'oGSRoD','title':'ListItem2','description':''}]}]
|
||||
*/
|
||||
_format(sections){
|
||||
if(!sections.length){throw '[LT02] List without sections';}
|
||||
if(sections.length > 1 && sections.filter(s => typeof s.title == 'undefined').length > 1){throw '[LT05] You can\'t have more than one empty title.';}
|
||||
return sections.map( (section) =>{
|
||||
if(!section.rows.length){throw '[LT03] Section without rows';}
|
||||
return {
|
||||
title: section.title ? section.title : undefined,
|
||||
rows: section.rows.map( (row) => {
|
||||
if(!row.title){throw '[LT04] Row without title';}
|
||||
return {
|
||||
rowId: row.id ? row.id : Util.generateHash(6),
|
||||
title: row.title,
|
||||
description: row.description ? row.description : ''
|
||||
};
|
||||
})
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = List;
|
||||
62
node_modules/whatsapp-web.js/src/structures/Location.js
generated
vendored
Normal file
62
node_modules/whatsapp-web.js/src/structures/Location.js
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Location send options
|
||||
* @typedef {Object} LocationSendOptions
|
||||
* @property {string} [name] Location name
|
||||
* @property {string} [address] Location address
|
||||
* @property {string} [url] URL address to be shown within a location message
|
||||
* @property {string} [description] Location full description
|
||||
*/
|
||||
|
||||
/**
|
||||
* Location information
|
||||
*/
|
||||
class Location {
|
||||
/**
|
||||
* @param {number} latitude
|
||||
* @param {number} longitude
|
||||
* @param {LocationSendOptions} [options] Location send options
|
||||
*/
|
||||
constructor(latitude, longitude, options = {}) {
|
||||
/**
|
||||
* Location latitude
|
||||
* @type {number}
|
||||
*/
|
||||
this.latitude = latitude;
|
||||
|
||||
/**
|
||||
* Location longitude
|
||||
* @type {number}
|
||||
*/
|
||||
this.longitude = longitude;
|
||||
|
||||
/**
|
||||
* Name for the location
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.name = options.name;
|
||||
|
||||
/**
|
||||
* Location address
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.address = options.address;
|
||||
|
||||
/**
|
||||
* URL address to be shown within a location message
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.url = options.url;
|
||||
|
||||
/**
|
||||
* Location full description
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.description = this.name && this.address
|
||||
? `${this.name}\n${this.address}`
|
||||
: this.name || this.address || '';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Location;
|
||||
787
node_modules/whatsapp-web.js/src/structures/Message.js
generated
vendored
Normal file
787
node_modules/whatsapp-web.js/src/structures/Message.js
generated
vendored
Normal file
@@ -0,0 +1,787 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
const MessageMedia = require('./MessageMedia');
|
||||
const Location = require('./Location');
|
||||
const Order = require('./Order');
|
||||
const Payment = require('./Payment');
|
||||
const Reaction = require('./Reaction');
|
||||
const Contact = require('./Contact');
|
||||
const ScheduledEvent = require('./ScheduledEvent'); // eslint-disable-line no-unused-vars
|
||||
const { MessageTypes } = require('../util/Constants');
|
||||
|
||||
/**
|
||||
* Represents a Message on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Message extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
this._data = data;
|
||||
|
||||
/**
|
||||
* MediaKey that represents the sticker 'ID'
|
||||
* @type {string}
|
||||
*/
|
||||
this.mediaKey = data.mediaKey;
|
||||
|
||||
/**
|
||||
* ID that represents the message
|
||||
* @type {object}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* ACK status for the message
|
||||
* @type {MessageAck}
|
||||
*/
|
||||
this.ack = data.ack;
|
||||
|
||||
/**
|
||||
* Indicates if the message has media available for download
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.hasMedia = Boolean(data.directPath);
|
||||
|
||||
/**
|
||||
* Message content
|
||||
* @type {string}
|
||||
*/
|
||||
this.body = this.hasMedia ? data.caption || '' : data.body || data.pollName || data.eventName || '';
|
||||
|
||||
/**
|
||||
* Message type
|
||||
* @type {MessageTypes}
|
||||
*/
|
||||
this.type = data.type;
|
||||
|
||||
/**
|
||||
* Unix timestamp for when the message was created
|
||||
* @type {number}
|
||||
*/
|
||||
this.timestamp = data.t;
|
||||
|
||||
/**
|
||||
* ID for the Chat that this message was sent to, except if the message was sent by the current user.
|
||||
* @type {string}
|
||||
*/
|
||||
this.from = (typeof (data.from) === 'object' && data.from !== null) ? data.from._serialized : data.from;
|
||||
|
||||
/**
|
||||
* ID for who this message is for.
|
||||
*
|
||||
* If the message is sent by the current user, it will be the Chat to which the message is being sent.
|
||||
* If the message is sent by another user, it will be the ID for the current user.
|
||||
* @type {string}
|
||||
*/
|
||||
this.to = (typeof (data.to) === 'object' && data.to !== null) ? data.to._serialized : data.to;
|
||||
|
||||
/**
|
||||
* If the message was sent to a group, this field will contain the user that sent the message.
|
||||
* @type {string}
|
||||
*/
|
||||
this.author = (typeof (data.author) === 'object' && data.author !== null) ? data.author._serialized : data.author;
|
||||
|
||||
/**
|
||||
* String that represents from which device type the message was sent
|
||||
* @type {string}
|
||||
*/
|
||||
this.deviceType = typeof data.id.id === 'string' && data.id.id.length > 21 ? 'android' : typeof data.id.id === 'string' && data.id.id.substring(0, 2) === '3A' ? 'ios' : 'web';
|
||||
/**
|
||||
* Indicates if the message was forwarded
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isForwarded = data.isForwarded;
|
||||
|
||||
/**
|
||||
* Indicates how many times the message was forwarded.
|
||||
*
|
||||
* The maximum value is 127.
|
||||
* @type {number}
|
||||
*/
|
||||
this.forwardingScore = data.forwardingScore || 0;
|
||||
|
||||
/**
|
||||
* Indicates if the message is a status update
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isStatus = data.isStatusV3 || data.id.remote === 'status@broadcast';
|
||||
|
||||
/**
|
||||
* Indicates if the message was starred
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isStarred = data.star;
|
||||
|
||||
/**
|
||||
* Indicates if the message was a broadcast
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.broadcast = data.broadcast;
|
||||
|
||||
/**
|
||||
* Indicates if the message was sent by the current user
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.fromMe = data.id.fromMe;
|
||||
|
||||
/**
|
||||
* Indicates if the message was sent as a reply to another message.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.hasQuotedMsg = data.quotedMsg ? true : false;
|
||||
|
||||
/**
|
||||
* Indicates whether there are reactions to the message
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.hasReaction = data.hasReaction ? true : false;
|
||||
|
||||
/**
|
||||
* Indicates the duration of the message in seconds
|
||||
* @type {string}
|
||||
*/
|
||||
this.duration = data.duration ? data.duration : undefined;
|
||||
|
||||
/**
|
||||
* Location information contained in the message, if the message is type "location"
|
||||
* @type {Location}
|
||||
*/
|
||||
this.location = (() => {
|
||||
if (data.type !== MessageTypes.LOCATION) {
|
||||
return undefined;
|
||||
}
|
||||
let description;
|
||||
if (data.loc && typeof data.loc === 'string') {
|
||||
let splitted = data.loc.split('\n');
|
||||
description = {
|
||||
name: splitted[0],
|
||||
address: splitted[1],
|
||||
url: data.clientUrl
|
||||
};
|
||||
}
|
||||
return new Location(data.lat, data.lng, description);
|
||||
})();
|
||||
|
||||
/**
|
||||
* List of vCards contained in the message.
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
this.vCards = data.type === MessageTypes.CONTACT_CARD_MULTI ? data.vcardList.map((c) => c.vcard) : data.type === MessageTypes.CONTACT_CARD ? [data.body] : [];
|
||||
|
||||
/**
|
||||
* Group Invite Data
|
||||
* @type {object}
|
||||
*/
|
||||
this.inviteV4 = data.type === MessageTypes.GROUP_INVITE ? {
|
||||
inviteCode: data.inviteCode,
|
||||
inviteCodeExp: data.inviteCodeExp,
|
||||
groupId: data.inviteGrp,
|
||||
groupName: data.inviteGrpName,
|
||||
fromId: typeof data.from === 'object' && '_serialized' in data.from ? data.from._serialized : data.from,
|
||||
toId: typeof data.to === 'object' && '_serialized' in data.to ? data.to._serialized : data.to
|
||||
} : undefined;
|
||||
|
||||
/**
|
||||
* Indicates the mentions in the message body.
|
||||
* @type {string[]}
|
||||
*/
|
||||
this.mentionedIds = data.mentionedJidList || [];
|
||||
|
||||
/**
|
||||
* @typedef {Object} GroupMention
|
||||
* @property {string} groupSubject The name of the group
|
||||
* @property {string} groupJid The group ID
|
||||
*/
|
||||
|
||||
/**
|
||||
* Indicates whether there are group mentions in the message body
|
||||
* @type {GroupMention[]}
|
||||
*/
|
||||
this.groupMentions = data.groupMentions || [];
|
||||
|
||||
/**
|
||||
* Order ID for message type ORDER
|
||||
* @type {string}
|
||||
*/
|
||||
this.orderId = data.orderId ? data.orderId : undefined;
|
||||
/**
|
||||
* Order Token for message type ORDER
|
||||
* @type {string}
|
||||
*/
|
||||
this.token = data.token ? data.token : undefined;
|
||||
|
||||
/**
|
||||
* Indicates whether the message is a Gif
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isGif = Boolean(data.isGif);
|
||||
|
||||
/**
|
||||
* Indicates if the message will disappear after it expires
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isEphemeral = data.isEphemeral;
|
||||
|
||||
/** Title */
|
||||
if (data.title) {
|
||||
this.title = data.title;
|
||||
}
|
||||
|
||||
/** Description */
|
||||
if (data.description) {
|
||||
this.description = data.description;
|
||||
}
|
||||
|
||||
/** Business Owner JID */
|
||||
if (data.businessOwnerJid) {
|
||||
this.businessOwnerJid = data.businessOwnerJid;
|
||||
}
|
||||
|
||||
/** Product ID */
|
||||
if (data.productId) {
|
||||
this.productId = data.productId;
|
||||
}
|
||||
|
||||
/** Last edit time */
|
||||
if (data.latestEditSenderTimestampMs) {
|
||||
this.latestEditSenderTimestampMs = data.latestEditSenderTimestampMs;
|
||||
}
|
||||
|
||||
/** Last edit message author */
|
||||
if (data.latestEditMsgKey) {
|
||||
this.latestEditMsgKey = data.latestEditMsgKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protocol message key.
|
||||
* Can be used to retrieve the ID of an original message that was revoked.
|
||||
*/
|
||||
if (data.protocolMessageKey) {
|
||||
this.protocolMessageKey = data.protocolMessageKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Links included in the message.
|
||||
* @type {Array<{link: string, isSuspicious: boolean}>}
|
||||
*
|
||||
*/
|
||||
this.links = data.links;
|
||||
|
||||
/** Buttons */
|
||||
if (data.dynamicReplyButtons) {
|
||||
this.dynamicReplyButtons = data.dynamicReplyButtons;
|
||||
}
|
||||
|
||||
/** Selected Button Id **/
|
||||
if (data.selectedButtonId) {
|
||||
this.selectedButtonId = data.selectedButtonId;
|
||||
}
|
||||
|
||||
/** Selected List row Id **/
|
||||
if (data.listResponse && data.listResponse.singleSelectReply.selectedRowId) {
|
||||
this.selectedRowId = data.listResponse.singleSelectReply.selectedRowId;
|
||||
}
|
||||
|
||||
if (this.type === MessageTypes.POLL_CREATION) {
|
||||
this.pollName = data.pollName;
|
||||
this.pollOptions = data.pollOptions;
|
||||
this.allowMultipleAnswers = Boolean(!data.pollSelectableOptionsCount);
|
||||
this.pollInvalidated = data.pollInvalidated;
|
||||
this.isSentCagPollCreation = data.isSentCagPollCreation;
|
||||
this.messageSecret = data.messageSecret ? Object.keys(data.messageSecret).map((key) => data.messageSecret[key]) : [];
|
||||
}
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
_getChatId() {
|
||||
return this.fromMe ? this.to : this.from;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads this Message object's data in-place with the latest values from WhatsApp Web.
|
||||
* Note that the Message must still be in the web app cache for this to work, otherwise will return null.
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
async reload() {
|
||||
const newData = await this.client.pupPage.evaluate(async (msgId) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
if (!msg) return null;
|
||||
return window.WWebJS.getMessageModel(msg);
|
||||
}, this.id._serialized);
|
||||
|
||||
if(!newData) return null;
|
||||
|
||||
this._patch(newData);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns message in a raw format
|
||||
* @type {Object}
|
||||
*/
|
||||
get rawData() {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Chat this message was sent in
|
||||
* @returns {Promise<Chat>}
|
||||
*/
|
||||
getChat() {
|
||||
return this.client.getChatById(this._getChatId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Contact this message was sent from
|
||||
* @returns {Promise<Contact>}
|
||||
*/
|
||||
getContact() {
|
||||
return this.client.getContactById(this.author || this.from);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Contacts mentioned in this message
|
||||
* @returns {Promise<Array<Contact>>}
|
||||
*/
|
||||
async getMentions() {
|
||||
return await Promise.all(this.mentionedIds.map(async m => await this.client.getContactById(m)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns groups mentioned in this message
|
||||
* @returns {Promise<Array<GroupChat>>}
|
||||
*/
|
||||
async getGroupMentions() {
|
||||
return await Promise.all(this.groupMentions.map(async (m) => await this.client.getChatById(m.groupJid._serialized)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the quoted message, if any
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
async getQuotedMessage() {
|
||||
if (!this.hasQuotedMsg) return undefined;
|
||||
|
||||
const quotedMsg = await this.client.pupPage.evaluate(async (msgId) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
const quotedMsg = window.Store.QuotedMsg.getQuotedMsgObj(msg);
|
||||
return window.WWebJS.getMessageModel(quotedMsg);
|
||||
}, this.id._serialized);
|
||||
|
||||
return new Message(this.client, quotedMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message as a reply to this message. If chatId is specified, it will be sent
|
||||
* through the specified Chat. If not, it will send the message
|
||||
* in the same Chat as the original message was sent.
|
||||
*
|
||||
* @param {string|MessageMedia|Location} content
|
||||
* @param {string} [chatId]
|
||||
* @param {MessageSendOptions} [options]
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
async reply(content, chatId, options = {}) {
|
||||
if (!chatId) {
|
||||
chatId = this._getChatId();
|
||||
}
|
||||
|
||||
options = {
|
||||
...options,
|
||||
quotedMessageId: this.id._serialized
|
||||
};
|
||||
|
||||
return this.client.sendMessage(chatId, content, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* React to this message with an emoji
|
||||
* @param {string} reaction - Emoji to react with. Send an empty string to remove the reaction.
|
||||
* @return {Promise}
|
||||
*/
|
||||
async react(reaction){
|
||||
await this.client.pupPage.evaluate(async (messageId, reaction) => {
|
||||
if (!messageId) return null;
|
||||
const msg =
|
||||
window.Store.Msg.get(messageId) || (await window.Store.Msg.getMessagesById([messageId]))?.messages?.[0];
|
||||
if(!msg) return null;
|
||||
await window.Store.sendReactionToMsg(msg, reaction);
|
||||
}, this.id._serialized, reaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept Group V4 Invite
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
async acceptGroupV4Invite() {
|
||||
return await this.client.acceptGroupV4Invite(this.inviteV4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards this message to another chat (that you chatted before, otherwise it will fail)
|
||||
*
|
||||
* @param {string|Chat} chat Chat model or chat ID to which the message will be forwarded
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async forward(chat) {
|
||||
const chatId = typeof chat === 'string' ? chat : chat.id._serialized;
|
||||
|
||||
await this.client.pupPage.evaluate(async (msgId, chatId) => {
|
||||
return window.WWebJS.forwardMessage(chatId, msgId);
|
||||
}, this.id._serialized, chatId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads and returns the attatched message media
|
||||
* @returns {Promise<MessageMedia>}
|
||||
*/
|
||||
async downloadMedia() {
|
||||
if (!this.hasMedia) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result = await this.client.pupPage.evaluate(async (msgId) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
|
||||
// REUPLOADING mediaStage means the media is expired and the download button is spinning, cannot be downloaded now
|
||||
if (!msg || !msg.mediaData || msg.mediaData.mediaStage === 'REUPLOADING') {
|
||||
return null;
|
||||
}
|
||||
if (msg.mediaData.mediaStage != 'RESOLVED') {
|
||||
// try to resolve media
|
||||
await msg.downloadMedia({
|
||||
downloadEvenIfExpensive: true,
|
||||
rmrReason: 1
|
||||
});
|
||||
}
|
||||
|
||||
if (msg.mediaData.mediaStage.includes('ERROR') || msg.mediaData.mediaStage === 'FETCHING') {
|
||||
// media could not be downloaded
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
const mockQpl = {
|
||||
addAnnotations: function() { return this; },
|
||||
addPoint: function() { return this; }
|
||||
};
|
||||
const decryptedMedia = await window.Store.DownloadManager.downloadAndMaybeDecrypt({
|
||||
directPath: msg.directPath,
|
||||
encFilehash: msg.encFilehash,
|
||||
filehash: msg.filehash,
|
||||
mediaKey: msg.mediaKey,
|
||||
mediaKeyTimestamp: msg.mediaKeyTimestamp,
|
||||
type: msg.type,
|
||||
signal: (new AbortController).signal,
|
||||
downloadQpl: mockQpl
|
||||
});
|
||||
|
||||
const data = await window.WWebJS.arrayBufferToBase64Async(decryptedMedia);
|
||||
|
||||
return {
|
||||
data,
|
||||
mimetype: msg.mimetype,
|
||||
filename: msg.filename,
|
||||
filesize: msg.size
|
||||
};
|
||||
} catch (e) {
|
||||
if(e.status && e.status === 404) return undefined;
|
||||
throw e;
|
||||
}
|
||||
}, this.id._serialized);
|
||||
|
||||
if (!result) return undefined;
|
||||
return new MessageMedia(result.mimetype, result.data, result.filename, result.filesize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a message from the chat
|
||||
* @param {?boolean} everyone If true and the message is sent by the current user or the user is an admin, will delete it for everyone in the chat.
|
||||
* @param {?boolean} [clearMedia = true] If true, any associated media will also be deleted from a device.
|
||||
*/
|
||||
async delete(everyone, clearMedia = true) {
|
||||
await this.client.pupPage.evaluate(async (msgId, everyone, clearMedia) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
const chat = window.Store.Chat.get(msg.id.remote) || (await window.Store.Chat.find(msg.id.remote));
|
||||
|
||||
const canRevoke =
|
||||
window.Store.MsgActionChecks.canSenderRevokeMsg(msg) || window.Store.MsgActionChecks.canAdminRevokeMsg(msg);
|
||||
|
||||
if (everyone && canRevoke) {
|
||||
return window.compareWwebVersions(window.Debug.VERSION, '>=', '2.3000.0')
|
||||
? window.Store.Cmd.sendRevokeMsgs(chat, { list: [msg], type: 'message' }, { clearMedia: clearMedia })
|
||||
: window.Store.Cmd.sendRevokeMsgs(chat, [msg], { clearMedia: true, type: msg.id.fromMe ? 'Sender' : 'Admin' });
|
||||
}
|
||||
|
||||
return window.compareWwebVersions(window.Debug.VERSION, '>=', '2.3000.0')
|
||||
? window.Store.Cmd.sendDeleteMsgs(chat, { list: [msg], type: 'message' }, clearMedia)
|
||||
: window.Store.Cmd.sendDeleteMsgs(chat, [msg], clearMedia);
|
||||
}, this.id._serialized, everyone, clearMedia);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stars this message
|
||||
*/
|
||||
async star() {
|
||||
await this.client.pupPage.evaluate(async (msgId) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
if (window.Store.MsgActionChecks.canStarMsg(msg)) {
|
||||
let chat = await window.Store.Chat.find(msg.id.remote);
|
||||
return window.Store.Cmd.sendStarMsgs(chat, [msg], false);
|
||||
}
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unstars this message
|
||||
*/
|
||||
async unstar() {
|
||||
await this.client.pupPage.evaluate(async (msgId) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
if (window.Store.MsgActionChecks.canStarMsg(msg)) {
|
||||
let chat = await window.Store.Chat.find(msg.id.remote);
|
||||
return window.Store.Cmd.sendUnstarMsgs(chat, [msg], false);
|
||||
}
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pins the message (group admins can pin messages of all group members)
|
||||
* @param {number} duration The duration in seconds the message will be pinned in a chat
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async pin(duration) {
|
||||
return await this.client.pupPage.evaluate(async (msgId, duration) => {
|
||||
return await window.WWebJS.pinUnpinMsgAction(msgId, 1, duration);
|
||||
}, this.id._serialized, duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpins the message (group admins can unpin messages of all group members)
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async unpin() {
|
||||
return await this.client.pupPage.evaluate(async (msgId) => {
|
||||
return await window.WWebJS.pinUnpinMsgAction(msgId, 2, 0);
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Message Info
|
||||
* @typedef {Object} MessageInfo
|
||||
* @property {Array<{id: ContactId, t: number}>} delivery Contacts to which the message has been delivered to
|
||||
* @property {number} deliveryRemaining Amount of people to whom the message has not been delivered to
|
||||
* @property {Array<{id: ContactId, t: number}>} played Contacts who have listened to the voice message
|
||||
* @property {number} playedRemaining Amount of people who have not listened to the message
|
||||
* @property {Array<{id: ContactId, t: number}>} read Contacts who have read the message
|
||||
* @property {number} readRemaining Amount of people who have not read the message
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get information about message delivery status.
|
||||
* May return null if the message does not exist or is not sent by you.
|
||||
* @returns {Promise<?MessageInfo>}
|
||||
*/
|
||||
async getInfo() {
|
||||
const info = await this.client.pupPage.evaluate(async (msgId) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
if (!msg || !msg.id.fromMe) return null;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(async () => {
|
||||
resolve(await window.Store.getMsgInfo(msg.id));
|
||||
}, (Date.now() - msg.t * 1000 < 1250) && Math.floor(Math.random() * (1200 - 1100 + 1)) + 1100 || 0);
|
||||
});
|
||||
}, this.id._serialized);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the order associated with a given message
|
||||
* @return {Promise<Order>}
|
||||
*/
|
||||
async getOrder() {
|
||||
if (this.type === MessageTypes.ORDER) {
|
||||
const result = await this.client.pupPage.evaluate((orderId, token, chatId) => {
|
||||
return window.WWebJS.getOrderDetail(orderId, token, chatId);
|
||||
}, this.orderId, this.token, this._getChatId());
|
||||
if (!result) return undefined;
|
||||
return new Order(this.client, result);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* Gets the payment details associated with a given message
|
||||
* @return {Promise<Payment>}
|
||||
*/
|
||||
async getPayment() {
|
||||
if (this.type === MessageTypes.PAYMENT) {
|
||||
const msg = await this.client.pupPage.evaluate(async (msgId) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
if(!msg) return null;
|
||||
return msg.serialize();
|
||||
}, this.id._serialized);
|
||||
return new Payment(this.client, msg);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reaction List
|
||||
* @typedef {Object} ReactionList
|
||||
* @property {string} id Original emoji
|
||||
* @property {string} aggregateEmoji aggregate emoji
|
||||
* @property {boolean} hasReactionByMe Flag who sent the reaction
|
||||
* @property {Array<Reaction>} senders Reaction senders, to this message
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the reactions associated with the given message
|
||||
* @return {Promise<ReactionList[]>}
|
||||
*/
|
||||
async getReactions() {
|
||||
if (!this.hasReaction) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const reactions = await this.client.pupPage.evaluate(async (msgId) => {
|
||||
const msgReactions = await window.Store.Reactions.find(msgId);
|
||||
if (!msgReactions || !msgReactions.reactions.length) return null;
|
||||
return msgReactions.reactions.serialize();
|
||||
}, this.id._serialized);
|
||||
|
||||
if (!reactions) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return reactions.map(reaction => {
|
||||
reaction.senders = reaction.senders.map(sender => {
|
||||
sender.timestamp = Math.round(sender.timestamp / 1000);
|
||||
return new Reaction(this.client, sender);
|
||||
});
|
||||
return reaction;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits the current message.
|
||||
* @param {string} content
|
||||
* @param {MessageEditOptions} [options] - Options used when editing the message
|
||||
* @returns {Promise<?Message>}
|
||||
*/
|
||||
async edit(content, options = {}) {
|
||||
if (options.mentions) {
|
||||
!Array.isArray(options.mentions) && (options.mentions = [options.mentions]);
|
||||
if (options.mentions.some((possiblyContact) => possiblyContact instanceof Contact)) {
|
||||
console.warn('Mentions with an array of Contact are now deprecated. See more at https://github.com/pedroslopez/whatsapp-web.js/pull/2166.');
|
||||
options.mentions = options.mentions.map((a) => a.id._serialized);
|
||||
}
|
||||
}
|
||||
|
||||
options.groupMentions && !Array.isArray(options.groupMentions) && (options.groupMentions = [options.groupMentions]);
|
||||
|
||||
let internalOptions = {
|
||||
linkPreview: options.linkPreview === false ? undefined : true,
|
||||
mentionedJidList: options.mentions || [],
|
||||
groupMentions: options.groupMentions,
|
||||
extraOptions: options.extra
|
||||
};
|
||||
|
||||
if (!this.fromMe) {
|
||||
return null;
|
||||
}
|
||||
const messageEdit = await this.client.pupPage.evaluate(async (msgId, message, options) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
if (!msg) return null;
|
||||
|
||||
let canEdit = window.Store.MsgActionChecks.canEditText(msg) || window.Store.MsgActionChecks.canEditCaption(msg);
|
||||
if (canEdit) {
|
||||
const msgEdit = await window.WWebJS.editMessage(msg, message, options);
|
||||
return msgEdit.serialize();
|
||||
}
|
||||
return null;
|
||||
}, this.id._serialized, content, internalOptions);
|
||||
if (messageEdit) {
|
||||
return new Message(this.client, messageEdit);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits the current ScheduledEvent message.
|
||||
* Once the scheduled event is canceled, it can not be edited.
|
||||
* @param {ScheduledEvent} editedEventObject
|
||||
* @returns {Promise<?Message>}
|
||||
*/
|
||||
async editScheduledEvent(editedEventObject) {
|
||||
if (!this.fromMe) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const edittedEventMsg = await this.client.pupPage.evaluate(async (msgId, editedEventObject) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
if (!msg) return null;
|
||||
|
||||
const { name, startTimeTs, eventSendOptions } = editedEventObject;
|
||||
const eventOptions = {
|
||||
name: name,
|
||||
description: eventSendOptions.description,
|
||||
startTime: startTimeTs,
|
||||
endTime: eventSendOptions.endTimeTs,
|
||||
location: eventSendOptions.location,
|
||||
callType: eventSendOptions.callType,
|
||||
isEventCanceled: eventSendOptions.isEventCanceled,
|
||||
};
|
||||
|
||||
await window.Store.ScheduledEventMsgUtils.sendEventEditMessage(eventOptions, msg);
|
||||
const editedMsg = window.Store.Msg.get(msg.id._serialized);
|
||||
return editedMsg?.serialize();
|
||||
}, this.id._serialized, editedEventObject);
|
||||
|
||||
return edittedEventMsg && new Message(this.client, edittedEventMsg);
|
||||
}
|
||||
/**
|
||||
* Returns the PollVote this poll message
|
||||
* @returns {Promise<PollVote[]>}
|
||||
*/
|
||||
async getPollVotes() {
|
||||
return await this.client.getPollVotes(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send votes to the poll message
|
||||
* @param {Array<string>} selectedOptions Array of options selected.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async vote(selectedOptions) {
|
||||
if (this.type != MessageTypes.POLL_CREATION) throw 'Invalid usage! Can only be used with a pollCreation message';
|
||||
|
||||
await this.client.pupPage.evaluate(async (messageId, votes) => {
|
||||
if (!messageId) return null;
|
||||
if (!Array.isArray(votes)) votes = [votes];
|
||||
let localIdSet = new Set();
|
||||
const msg =
|
||||
window.Store.Msg.get(messageId) || (await window.Store.Msg.getMessagesById([messageId]))?.messages?.[0];
|
||||
if (!msg) return null;
|
||||
|
||||
msg.pollOptions.forEach(a => {
|
||||
for (const option of votes) {
|
||||
if (a.name === option) localIdSet.add(a.localId);
|
||||
}
|
||||
});
|
||||
|
||||
await window.Store.PollsSendVote.sendVote(msg, localIdSet);
|
||||
}, this.id._serialized, selectedOptions);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Message;
|
||||
111
node_modules/whatsapp-web.js/src/structures/MessageMedia.js
generated
vendored
Normal file
111
node_modules/whatsapp-web.js/src/structures/MessageMedia.js
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const mime = require('mime');
|
||||
const fetch = require('node-fetch');
|
||||
const { URL } = require('url');
|
||||
|
||||
/**
|
||||
* Media attached to a message
|
||||
* @param {string} mimetype MIME type of the attachment
|
||||
* @param {string} data Base64-encoded data of the file
|
||||
* @param {?string} filename Document file name. Value can be null
|
||||
* @param {?number} filesize Document file size in bytes. Value can be null
|
||||
*/
|
||||
class MessageMedia {
|
||||
constructor(mimetype, data, filename, filesize) {
|
||||
/**
|
||||
* MIME type of the attachment
|
||||
* @type {string}
|
||||
*/
|
||||
this.mimetype = mimetype;
|
||||
|
||||
/**
|
||||
* Base64 encoded data that represents the file
|
||||
* @type {string}
|
||||
*/
|
||||
this.data = data;
|
||||
|
||||
/**
|
||||
* Document file name. Value can be null
|
||||
* @type {?string}
|
||||
*/
|
||||
this.filename = filename;
|
||||
|
||||
/**
|
||||
* Document file size in bytes. Value can be null
|
||||
* @type {?number}
|
||||
*/
|
||||
this.filesize = filesize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MessageMedia instance from a local file path
|
||||
* @param {string} filePath
|
||||
* @returns {MessageMedia}
|
||||
*/
|
||||
static fromFilePath(filePath) {
|
||||
const b64data = fs.readFileSync(filePath, {encoding: 'base64'});
|
||||
const mimetype = mime.getType(filePath);
|
||||
const filename = path.basename(filePath);
|
||||
|
||||
return new MessageMedia(mimetype, b64data, filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MessageMedia instance from a URL
|
||||
* @param {string} url
|
||||
* @param {Object} [options]
|
||||
* @param {boolean} [options.unsafeMime=false]
|
||||
* @param {string} [options.filename]
|
||||
* @param {object} [options.client]
|
||||
* @param {object} [options.reqOptions]
|
||||
* @param {number} [options.reqOptions.size=0]
|
||||
* @returns {Promise<MessageMedia>}
|
||||
*/
|
||||
static async fromUrl(url, options = {}) {
|
||||
const pUrl = new URL(url);
|
||||
let mimetype = mime.getType(pUrl.pathname);
|
||||
|
||||
if (!mimetype && !options.unsafeMime)
|
||||
throw new Error('Unable to determine MIME type using URL. Set unsafeMime to true to download it anyway.');
|
||||
|
||||
async function fetchData (url, options) {
|
||||
const reqOptions = Object.assign({ headers: { accept: 'image/* video/* text/* audio/*' } }, options);
|
||||
const response = await fetch(url, reqOptions);
|
||||
const mime = response.headers.get('Content-Type');
|
||||
const size = response.headers.get('Content-Length');
|
||||
|
||||
const contentDisposition = response.headers.get('Content-Disposition');
|
||||
const name = contentDisposition ? contentDisposition.match(/((?<=filename=")(.*)(?="))/) : null;
|
||||
|
||||
let data = '';
|
||||
if (response.buffer) {
|
||||
data = (await response.buffer()).toString('base64');
|
||||
} else {
|
||||
const bArray = new Uint8Array(await response.arrayBuffer());
|
||||
bArray.forEach((b) => {
|
||||
data += String.fromCharCode(b);
|
||||
});
|
||||
data = btoa(data);
|
||||
}
|
||||
|
||||
return { data, mime, name, size };
|
||||
}
|
||||
|
||||
const res = options.client
|
||||
? (await options.client.pupPage.evaluate(fetchData, url, options.reqOptions))
|
||||
: (await fetchData(url, options.reqOptions));
|
||||
|
||||
const filename = options.filename ||
|
||||
(res.name ? res.name[0] : (pUrl.pathname.split('/').pop() || 'file'));
|
||||
|
||||
if (!mimetype)
|
||||
mimetype = res.mime;
|
||||
|
||||
return new MessageMedia(mimetype, res.data, filename, res.size || null);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MessageMedia;
|
||||
52
node_modules/whatsapp-web.js/src/structures/Order.js
generated
vendored
Normal file
52
node_modules/whatsapp-web.js/src/structures/Order.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
const Product = require('./Product');
|
||||
|
||||
/**
|
||||
* Represents a Order on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Order extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* List of products
|
||||
* @type {Array<Product>}
|
||||
*/
|
||||
if (data.products) {
|
||||
this.products = data.products.map(product => new Product(this.client, product));
|
||||
}
|
||||
/**
|
||||
* Order Subtotal
|
||||
* @type {string}
|
||||
*/
|
||||
this.subtotal = data.subtotal;
|
||||
/**
|
||||
* Order Total
|
||||
* @type {string}
|
||||
*/
|
||||
this.total = data.total;
|
||||
/**
|
||||
* Order Currency
|
||||
* @type {string}
|
||||
*/
|
||||
this.currency = data.currency;
|
||||
/**
|
||||
* Order Created At
|
||||
* @type {number}
|
||||
*/
|
||||
this.createdAt = data.createdAt;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
module.exports = Order;
|
||||
79
node_modules/whatsapp-web.js/src/structures/Payment.js
generated
vendored
Normal file
79
node_modules/whatsapp-web.js/src/structures/Payment.js
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
const Base = require('./Base');
|
||||
|
||||
class Payment extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* The payment Id
|
||||
* @type {object}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* The payment currency
|
||||
* @type {string}
|
||||
*/
|
||||
this.paymentCurrency = data.paymentCurrency;
|
||||
|
||||
/**
|
||||
* The payment ammount ( R$ 1.00 = 1000 )
|
||||
* @type {number}
|
||||
*/
|
||||
this.paymentAmount1000 = data.paymentAmount1000;
|
||||
|
||||
/**
|
||||
* The payment receiver
|
||||
* @type {object}
|
||||
*/
|
||||
this.paymentMessageReceiverJid = data.paymentMessageReceiverJid;
|
||||
|
||||
/**
|
||||
* The payment transaction timestamp
|
||||
* @type {number}
|
||||
*/
|
||||
this.paymentTransactionTimestamp = data.paymentTransactionTimestamp;
|
||||
|
||||
/**
|
||||
* The paymentStatus
|
||||
*
|
||||
* Possible Status
|
||||
* 0:UNKNOWN_STATUS
|
||||
* 1:PROCESSING
|
||||
* 2:SENT
|
||||
* 3:NEED_TO_ACCEPT
|
||||
* 4:COMPLETE
|
||||
* 5:COULD_NOT_COMPLETE
|
||||
* 6:REFUNDED
|
||||
* 7:EXPIRED
|
||||
* 8:REJECTED
|
||||
* 9:CANCELLED
|
||||
* 10:WAITING_FOR_PAYER
|
||||
* 11:WAITING
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
this.paymentStatus = data.paymentStatus;
|
||||
|
||||
/**
|
||||
* Integer that represents the payment Text
|
||||
* @type {number}
|
||||
*/
|
||||
this.paymentTxnStatus = data.paymentTxnStatus;
|
||||
|
||||
/**
|
||||
* The note sent with the payment
|
||||
* @type {string}
|
||||
*/
|
||||
this.paymentNote = !data.paymentNoteMsg ? undefined : data.paymentNoteMsg.body ? data.paymentNoteMsg.body : undefined ;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Payment;
|
||||
44
node_modules/whatsapp-web.js/src/structures/Poll.js
generated
vendored
Normal file
44
node_modules/whatsapp-web.js/src/structures/Poll.js
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Poll send options
|
||||
* @typedef {Object} PollSendOptions
|
||||
* @property {boolean} [allowMultipleAnswers=false] If false it is a single choice poll, otherwise it is a multiple choice poll (false by default)
|
||||
* @property {?Array<number>} messageSecret The custom message secret, can be used as a poll ID. NOTE: it has to be a unique vector with a length of 32
|
||||
*/
|
||||
|
||||
/** Represents a Poll on WhatsApp */
|
||||
class Poll {
|
||||
/**
|
||||
* @param {string} pollName
|
||||
* @param {Array<string>} pollOptions
|
||||
* @param {PollSendOptions} options
|
||||
*/
|
||||
constructor(pollName, pollOptions, options = {}) {
|
||||
/**
|
||||
* The name of the poll
|
||||
* @type {string}
|
||||
*/
|
||||
this.pollName = pollName.trim();
|
||||
|
||||
/**
|
||||
* The array of poll options
|
||||
* @type {Array.<{name: string, localId: number}>}
|
||||
*/
|
||||
this.pollOptions = pollOptions.map((option, index) => ({
|
||||
name: option.trim(),
|
||||
localId: index
|
||||
}));
|
||||
|
||||
/**
|
||||
* The send options for the poll
|
||||
* @type {PollSendOptions}
|
||||
*/
|
||||
this.options = {
|
||||
allowMultipleAnswers: options.allowMultipleAnswers === true,
|
||||
messageSecret: options.messageSecret
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Poll;
|
||||
75
node_modules/whatsapp-web.js/src/structures/PollVote.js
generated
vendored
Normal file
75
node_modules/whatsapp-web.js/src/structures/PollVote.js
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
'use strict';
|
||||
|
||||
const Message = require('./Message');
|
||||
const Base = require('./Base');
|
||||
|
||||
/**
|
||||
* Selected poll option structure
|
||||
* @typedef {Object} SelectedPollOption
|
||||
* @property {number} id The local selected or deselected option ID
|
||||
* @property {string} name The option name
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a Poll Vote on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class PollVote extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* The person who voted
|
||||
* @type {string}
|
||||
*/
|
||||
this.voter = data.sender;
|
||||
|
||||
/**
|
||||
* The selected poll option(s)
|
||||
* If it's an empty array, the user hasn't selected any options on the poll,
|
||||
* may occur when they deselected all poll options
|
||||
* @type {SelectedPollOption[]}
|
||||
*/
|
||||
if (data.selectedOptionLocalIds.length > 0) {
|
||||
if(data.parentMessage) { // temporary failsafe
|
||||
this.selectedOptions = data.selectedOptionLocalIds.map((e) => ({
|
||||
name: data.parentMessage.pollOptions.find((x) => x.localId === e).name,
|
||||
localId: e
|
||||
}));
|
||||
} else {
|
||||
this.selectedOptions = data.selectedOptionLocalIds.map((e) => ({
|
||||
name: undefined,
|
||||
localId: e
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
this.selectedOptions = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamp the option was selected or deselected at
|
||||
* @type {number}
|
||||
*/
|
||||
this.interractedAtTs = data.senderTimestampMs;
|
||||
|
||||
/**
|
||||
* The poll creation message associated with the poll vote
|
||||
* @type {Message}
|
||||
*/
|
||||
this.parentMessage = new Message(this.client, data.parentMessage);
|
||||
|
||||
/**
|
||||
* The poll creation message id
|
||||
* @type {Object}
|
||||
*/
|
||||
this.parentMsgKey = data.parentMsgKey;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PollVote;
|
||||
13
node_modules/whatsapp-web.js/src/structures/PrivateChat.js
generated
vendored
Normal file
13
node_modules/whatsapp-web.js/src/structures/PrivateChat.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const Chat = require('./Chat');
|
||||
|
||||
/**
|
||||
* Represents a Private Chat on WhatsApp
|
||||
* @extends {Chat}
|
||||
*/
|
||||
class PrivateChat extends Chat {
|
||||
|
||||
}
|
||||
|
||||
module.exports = PrivateChat;
|
||||
13
node_modules/whatsapp-web.js/src/structures/PrivateContact.js
generated
vendored
Normal file
13
node_modules/whatsapp-web.js/src/structures/PrivateContact.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const Contact = require('./Contact');
|
||||
|
||||
/**
|
||||
* Represents a Private Contact on WhatsApp
|
||||
* @extends {Contact}
|
||||
*/
|
||||
class PrivateContact extends Contact {
|
||||
|
||||
}
|
||||
|
||||
module.exports = PrivateContact;
|
||||
68
node_modules/whatsapp-web.js/src/structures/Product.js
generated
vendored
Normal file
68
node_modules/whatsapp-web.js/src/structures/Product.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
const ProductMetadata = require('./ProductMetadata');
|
||||
|
||||
/**
|
||||
* Represents a Product on WhatsAppBusiness
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Product extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* Product ID
|
||||
* @type {string}
|
||||
*/
|
||||
this.id = data.id;
|
||||
/**
|
||||
* Price
|
||||
* @type {string}
|
||||
*/
|
||||
this.price = data.price ? data.price : '';
|
||||
/**
|
||||
* Product Thumbnail
|
||||
* @type {string}
|
||||
*/
|
||||
this.thumbnailUrl = data.thumbnailUrl;
|
||||
/**
|
||||
* Currency
|
||||
* @type {string}
|
||||
*/
|
||||
this.currency = data.currency;
|
||||
/**
|
||||
* Product Name
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = data.name;
|
||||
/**
|
||||
* Product Quantity
|
||||
* @type {number}
|
||||
*/
|
||||
this.quantity = data.quantity;
|
||||
/** Product metadata */
|
||||
this.data = null;
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
async getData() {
|
||||
if (this.data === null) {
|
||||
let result = await this.client.pupPage.evaluate((productId) => {
|
||||
return window.WWebJS.getProductMetadata(productId);
|
||||
}, this.id);
|
||||
if (!result) {
|
||||
this.data = undefined;
|
||||
} else {
|
||||
this.data = new ProductMetadata(this.client, result);
|
||||
}
|
||||
}
|
||||
return this.data;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Product;
|
||||
25
node_modules/whatsapp-web.js/src/structures/ProductMetadata.js
generated
vendored
Normal file
25
node_modules/whatsapp-web.js/src/structures/ProductMetadata.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
const Base = require('./Base');
|
||||
|
||||
class ProductMetadata extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/** Product ID */
|
||||
this.id = data.id;
|
||||
/** Retailer ID */
|
||||
this.retailer_id = data.retailer_id;
|
||||
/** Product Name */
|
||||
this.name = data.name;
|
||||
/** Product Description */
|
||||
this.description = data.description;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = ProductMetadata;
|
||||
69
node_modules/whatsapp-web.js/src/structures/Reaction.js
generated
vendored
Normal file
69
node_modules/whatsapp-web.js/src/structures/Reaction.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
|
||||
/**
|
||||
* Represents a Reaction on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Reaction extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* Reaction ID
|
||||
* @type {object}
|
||||
*/
|
||||
this.id = data.msgKey;
|
||||
/**
|
||||
* Orphan
|
||||
* @type {number}
|
||||
*/
|
||||
this.orphan = data.orphan;
|
||||
/**
|
||||
* Orphan reason
|
||||
* @type {?string}
|
||||
*/
|
||||
this.orphanReason = data.orphanReason;
|
||||
/**
|
||||
* Unix timestamp for when the reaction was created
|
||||
* @type {number}
|
||||
*/
|
||||
this.timestamp = data.timestamp;
|
||||
/**
|
||||
* Reaction
|
||||
* @type {string}
|
||||
*/
|
||||
this.reaction = data.reactionText;
|
||||
/**
|
||||
* Read
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.read = data.read;
|
||||
/**
|
||||
* Message ID
|
||||
* @type {object}
|
||||
*/
|
||||
this.msgId = data.parentMsgKey;
|
||||
/**
|
||||
* Sender ID
|
||||
* @type {string}
|
||||
*/
|
||||
this.senderId = data.senderUserJid;
|
||||
/**
|
||||
* ACK
|
||||
* @type {?number}
|
||||
*/
|
||||
this.ack = data.ack;
|
||||
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Reaction;
|
||||
71
node_modules/whatsapp-web.js/src/structures/ScheduledEvent.js
generated
vendored
Normal file
71
node_modules/whatsapp-web.js/src/structures/ScheduledEvent.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* ScheduledEvent send options
|
||||
* @typedef {Object} ScheduledEventSendOptions
|
||||
* @property {?string} description The scheduled event description
|
||||
* @property {?Date} endTime The end time of the event
|
||||
* @property {?string} location The location of the event
|
||||
* @property {?string} callType The type of a WhatsApp call link to generate, valid values are: `video` | `voice` | `none`
|
||||
* @property {boolean} [isEventCanceled = false] Indicates if a scheduled event should be sent as an already canceled
|
||||
* @property {?Array<number>} messageSecret The custom message secret, can be used as an event ID. NOTE: it has to be a unique vector with a length of 32
|
||||
*/
|
||||
|
||||
/** Represents a ScheduledEvent on WhatsApp */
|
||||
class ScheduledEvent {
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {Date} startTime
|
||||
* @param {ScheduledEventSendOptions} options
|
||||
*/
|
||||
constructor(name, startTime, options = {}) {
|
||||
/**
|
||||
* The name of the event
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = this._validateInputs('name', name).trim();
|
||||
|
||||
/**
|
||||
* The start time of the event
|
||||
* @type {number}
|
||||
*/
|
||||
this.startTimeTs = Math.floor(startTime.getTime() / 1000);
|
||||
|
||||
/**
|
||||
* The send options for the event
|
||||
* @type {Object}
|
||||
*/
|
||||
this.eventSendOptions = {
|
||||
description: options.description?.trim(),
|
||||
endTimeTs: options.endTime ? Math.floor(options.endTime.getTime() / 1000) : null,
|
||||
location: options.location?.trim(),
|
||||
callType: this._validateInputs('callType', options.callType),
|
||||
isEventCanceled: options.isEventCanceled ?? false,
|
||||
messageSecret: options.messageSecret
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner function to validate input values
|
||||
* @param {string} propName The property name to validate the value of
|
||||
* @param {string | number} propValue The property value to validate
|
||||
* @returns {string | number} The property value if a validation succeeded
|
||||
*/
|
||||
_validateInputs(propName, propValue) {
|
||||
if (propName === 'name' && !propValue) {
|
||||
throw new class CreateScheduledEventError extends Error {
|
||||
constructor(m) { super(m); }
|
||||
}(`Empty '${propName}' parameter value is provided.`);
|
||||
}
|
||||
|
||||
if (propName === 'callType' && propValue && !['video', 'voice', 'none'].includes(propValue)) {
|
||||
throw new class CreateScheduledEventError extends Error {
|
||||
constructor(m) { super(m); }
|
||||
}(`Invalid '${propName}' parameter value is provided. Valid values are: 'voice' | 'video' | 'none'.`);
|
||||
}
|
||||
|
||||
return propValue;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ScheduledEvent;
|
||||
27
node_modules/whatsapp-web.js/src/structures/index.js
generated
vendored
Normal file
27
node_modules/whatsapp-web.js/src/structures/index.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
module.exports = {
|
||||
Base: require('./Base'),
|
||||
BusinessContact: require('./BusinessContact'),
|
||||
Chat: require('./Chat'),
|
||||
ClientInfo: require('./ClientInfo'),
|
||||
Contact: require('./Contact'),
|
||||
GroupChat: require('./GroupChat'),
|
||||
Channel: require('./Channel'),
|
||||
Location: require('./Location'),
|
||||
Message: require('./Message'),
|
||||
MessageMedia: require('./MessageMedia'),
|
||||
PrivateChat: require('./PrivateChat'),
|
||||
PrivateContact: require('./PrivateContact'),
|
||||
GroupNotification: require('./GroupNotification'),
|
||||
Label: require('./Label.js'),
|
||||
Order: require('./Order'),
|
||||
Product: require('./Product'),
|
||||
Call: require('./Call'),
|
||||
Buttons: require('./Buttons'),
|
||||
List: require('./List'),
|
||||
Payment: require('./Payment'),
|
||||
Reaction: require('./Reaction'),
|
||||
Poll: require('./Poll'),
|
||||
PollVote: require('./PollVote'),
|
||||
Broadcast: require('./Broadcast'),
|
||||
ScheduledEvent: require('./ScheduledEvent'),
|
||||
};
|
||||
Reference in New Issue
Block a user