chore: cleanup, ci workflows and formatting (#127064)
* ci: setup workflows, dependabot, labeler and commit linting * docs: update README, community files and issue templates * chore: configure prettier, editorconfig and format codebase * chore: restore changes lost during rebase * docs: adjust url for new logo * fix: align badges * chore: resolve conflicts and re-add temp lint
This commit is contained in:
parent
c2d978fd0a
commit
807efd502d
43 changed files with 6790 additions and 3547 deletions
2611
src/Client.js
2611
src/Client.js
File diff suppressed because it is too large
Load diff
|
|
@ -14,7 +14,7 @@ class BaseAuthStrategy {
|
|||
return {
|
||||
failed: false,
|
||||
restart: false,
|
||||
failureEventPayload: undefined
|
||||
failureEventPayload: undefined,
|
||||
};
|
||||
}
|
||||
async getAuthEventPayload() {}
|
||||
|
|
@ -24,4 +24,4 @@ class BaseAuthStrategy {
|
|||
async logout() {}
|
||||
}
|
||||
|
||||
module.exports = BaseAuthStrategy;
|
||||
module.exports = BaseAuthStrategy;
|
||||
|
|
|
|||
|
|
@ -8,16 +8,18 @@ const BaseAuthStrategy = require('./BaseAuthStrategy');
|
|||
* Local directory-based authentication
|
||||
* @param {object} options - options
|
||||
* @param {string} options.clientId - Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance
|
||||
* @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
|
||||
* @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
|
||||
* @param {number} options.rmMaxRetries - Sets the maximum number of retries for removing the session directory
|
||||
*/
|
||||
*/
|
||||
class LocalAuth extends BaseAuthStrategy {
|
||||
constructor({ clientId, dataPath, rmMaxRetries }={}) {
|
||||
constructor({ clientId, dataPath, rmMaxRetries } = {}) {
|
||||
super();
|
||||
|
||||
const idRegex = /^[-_\w]+$/i;
|
||||
if(clientId && !idRegex.test(clientId)) {
|
||||
throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
|
||||
if (clientId && !idRegex.test(clientId)) {
|
||||
throw new Error(
|
||||
'Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.',
|
||||
);
|
||||
}
|
||||
|
||||
this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
|
||||
|
|
@ -27,18 +29,25 @@ class LocalAuth extends BaseAuthStrategy {
|
|||
|
||||
async beforeBrowserInitialized() {
|
||||
const puppeteerOpts = this.client.options.puppeteer;
|
||||
const sessionDirName = this.clientId ? `session-${this.clientId}` : 'session';
|
||||
const sessionDirName = this.clientId
|
||||
? `session-${this.clientId}`
|
||||
: 'session';
|
||||
const dirPath = path.join(this.dataPath, sessionDirName);
|
||||
|
||||
if(puppeteerOpts.userDataDir && puppeteerOpts.userDataDir !== dirPath) {
|
||||
throw new Error('LocalAuth is not compatible with a user-supplied userDataDir.');
|
||||
if (
|
||||
puppeteerOpts.userDataDir &&
|
||||
puppeteerOpts.userDataDir !== dirPath
|
||||
) {
|
||||
throw new Error(
|
||||
'LocalAuth is not compatible with a user-supplied userDataDir.',
|
||||
);
|
||||
}
|
||||
|
||||
fs.mkdirSync(dirPath, { recursive: true });
|
||||
|
||||
|
||||
this.client.options.puppeteer = {
|
||||
...puppeteerOpts,
|
||||
userDataDir: dirPath
|
||||
userDataDir: dirPath,
|
||||
};
|
||||
|
||||
this.userDataDir = dirPath;
|
||||
|
|
@ -46,13 +55,17 @@ class LocalAuth extends BaseAuthStrategy {
|
|||
|
||||
async logout() {
|
||||
if (this.userDataDir) {
|
||||
await fs.promises.rm(this.userDataDir, { recursive: true, force: true, maxRetries: this.rmMaxRetries })
|
||||
await fs.promises
|
||||
.rm(this.userDataDir, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
maxRetries: this.rmMaxRetries,
|
||||
})
|
||||
.catch((e) => {
|
||||
throw new Error(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = LocalAuth;
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ const BaseAuthStrategy = require('./BaseAuthStrategy');
|
|||
/**
|
||||
* No session restoring functionality
|
||||
* Will need to authenticate via QR code every time
|
||||
*/
|
||||
class NoAuth extends BaseAuthStrategy { }
|
||||
*/
|
||||
class NoAuth extends BaseAuthStrategy {}
|
||||
|
||||
|
||||
module.exports = NoAuth;
|
||||
module.exports = NoAuth;
|
||||
|
|
|
|||
|
|
@ -20,40 +20,64 @@ const BaseAuthStrategy = require('./BaseAuthStrategy');
|
|||
* @param {object} options - options
|
||||
* @param {object} options.store - Remote database store instance
|
||||
* @param {string} options.clientId - Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance
|
||||
* @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
|
||||
* @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
|
||||
* @param {number} options.backupSyncIntervalMs - Sets the time interval for periodic session backups. Accepts values starting from 60000ms {1 minute}
|
||||
* @param {number} options.rmMaxRetries - Sets the maximum number of retries for removing the session directory
|
||||
*/
|
||||
class RemoteAuth extends BaseAuthStrategy {
|
||||
constructor({ clientId, dataPath, store, backupSyncIntervalMs, rmMaxRetries } = {}) {
|
||||
if (!fs && !unzipper && !archiver) throw new Error('Optional Dependencies [fs-extra, unzipper, archiver] are required to use RemoteAuth. Make sure to run npm install correctly and remove the --no-optional flag');
|
||||
constructor({
|
||||
clientId,
|
||||
dataPath,
|
||||
store,
|
||||
backupSyncIntervalMs,
|
||||
rmMaxRetries,
|
||||
} = {}) {
|
||||
if (!fs && !unzipper && !archiver)
|
||||
throw new Error(
|
||||
'Optional Dependencies [fs-extra, unzipper, archiver] are required to use RemoteAuth. Make sure to run npm install correctly and remove the --no-optional flag',
|
||||
);
|
||||
super();
|
||||
|
||||
const idRegex = /^[-_\w]+$/i;
|
||||
if (clientId && !idRegex.test(clientId)) {
|
||||
throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
|
||||
throw new Error(
|
||||
'Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.',
|
||||
);
|
||||
}
|
||||
if (!backupSyncIntervalMs || backupSyncIntervalMs < 60000) {
|
||||
throw new Error('Invalid backupSyncIntervalMs. Accepts values starting from 60000ms {1 minute}.');
|
||||
throw new Error(
|
||||
'Invalid backupSyncIntervalMs. Accepts values starting from 60000ms {1 minute}.',
|
||||
);
|
||||
}
|
||||
if(!store) throw new Error('Remote database store is required.');
|
||||
if (!store) throw new Error('Remote database store is required.');
|
||||
|
||||
this.store = store;
|
||||
this.clientId = clientId;
|
||||
this.backupSyncIntervalMs = backupSyncIntervalMs;
|
||||
this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
|
||||
this.tempDir = `${this.dataPath}/wwebjs_temp_session_${this.clientId}`;
|
||||
this.requiredDirs = ['Default', 'IndexedDB', 'Local Storage']; /* => Required Files & Dirs in WWebJS to restore session */
|
||||
this.requiredDirs = [
|
||||
'Default',
|
||||
'IndexedDB',
|
||||
'Local Storage',
|
||||
]; /* => Required Files & Dirs in WWebJS to restore session */
|
||||
this.rmMaxRetries = rmMaxRetries ?? 4;
|
||||
}
|
||||
|
||||
async beforeBrowserInitialized() {
|
||||
const puppeteerOpts = this.client.options.puppeteer;
|
||||
const sessionDirName = this.clientId ? `RemoteAuth-${this.clientId}` : 'RemoteAuth';
|
||||
const sessionDirName = this.clientId
|
||||
? `RemoteAuth-${this.clientId}`
|
||||
: 'RemoteAuth';
|
||||
const dirPath = path.join(this.dataPath, sessionDirName);
|
||||
|
||||
if (puppeteerOpts.userDataDir && puppeteerOpts.userDataDir !== dirPath) {
|
||||
throw new Error('RemoteAuth is not compatible with a user-supplied userDataDir.');
|
||||
if (
|
||||
puppeteerOpts.userDataDir &&
|
||||
puppeteerOpts.userDataDir !== dirPath
|
||||
) {
|
||||
throw new Error(
|
||||
'RemoteAuth is not compatible with a user-supplied userDataDir.',
|
||||
);
|
||||
}
|
||||
|
||||
this.userDataDir = dirPath;
|
||||
|
|
@ -63,7 +87,7 @@ class RemoteAuth extends BaseAuthStrategy {
|
|||
|
||||
this.client.options.puppeteer = {
|
||||
...puppeteerOpts,
|
||||
userDataDir: dirPath
|
||||
userDataDir: dirPath,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -80,20 +104,26 @@ class RemoteAuth extends BaseAuthStrategy {
|
|||
|
||||
let pathExists = await this.isValidPath(this.userDataDir);
|
||||
if (pathExists) {
|
||||
await fs.promises.rm(this.userDataDir, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
maxRetries: this.rmMaxRetries,
|
||||
}).catch(() => {});
|
||||
await fs.promises
|
||||
.rm(this.userDataDir, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
maxRetries: this.rmMaxRetries,
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
clearInterval(this.backupSync);
|
||||
}
|
||||
|
||||
async afterAuthReady() {
|
||||
const sessionExists = await this.store.sessionExists({session: this.sessionName});
|
||||
if(!sessionExists) {
|
||||
await this.delay(60000); /* Initial delay sync required for session to be stable enough to recover */
|
||||
await this.storeRemoteSession({emit: true});
|
||||
const sessionExists = await this.store.sessionExists({
|
||||
session: this.sessionName,
|
||||
});
|
||||
if (!sessionExists) {
|
||||
await this.delay(
|
||||
60000,
|
||||
); /* Initial delay sync required for session to be stable enough to recover */
|
||||
await this.storeRemoteSession({ emit: true });
|
||||
}
|
||||
var self = this;
|
||||
this.backupSync = setInterval(async function () {
|
||||
|
|
@ -108,12 +138,15 @@ class RemoteAuth extends BaseAuthStrategy {
|
|||
let compressedSessionPath;
|
||||
try {
|
||||
compressedSessionPath = await this.compressSession();
|
||||
await this.store.save({ session: path.join(this.dataPath, this.sessionName) });
|
||||
if(options && options.emit) this.client.emit(Events.REMOTE_SESSION_SAVED);
|
||||
await this.store.save({
|
||||
session: path.join(this.dataPath, this.sessionName),
|
||||
});
|
||||
if (options && options.emit)
|
||||
this.client.emit(Events.REMOTE_SESSION_SAVED);
|
||||
} finally {
|
||||
const paths = [
|
||||
this.tempDir,
|
||||
...(compressedSessionPath ? [compressedSessionPath] : [])
|
||||
...(compressedSessionPath ? [compressedSessionPath] : []),
|
||||
];
|
||||
await Promise.allSettled(
|
||||
paths.map((p) =>
|
||||
|
|
@ -121,25 +154,35 @@ class RemoteAuth extends BaseAuthStrategy {
|
|||
recursive: true,
|
||||
force: true,
|
||||
maxRetries: this.rmMaxRetries,
|
||||
})
|
||||
)
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async extractRemoteSession() {
|
||||
const pathExists = await this.isValidPath(this.userDataDir);
|
||||
const compressedSessionPath = path.join(this.dataPath, `${this.sessionName}.zip`);
|
||||
const sessionExists = await this.store.sessionExists({session: this.sessionName});
|
||||
const compressedSessionPath = path.join(
|
||||
this.dataPath,
|
||||
`${this.sessionName}.zip`,
|
||||
);
|
||||
const sessionExists = await this.store.sessionExists({
|
||||
session: this.sessionName,
|
||||
});
|
||||
if (pathExists) {
|
||||
await fs.promises.rm(this.userDataDir, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
maxRetries: this.rmMaxRetries,
|
||||
}).catch(() => {});
|
||||
await fs.promises
|
||||
.rm(this.userDataDir, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
maxRetries: this.rmMaxRetries,
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
if (sessionExists) {
|
||||
await this.store.extract({session: this.sessionName, path: compressedSessionPath});
|
||||
await this.store.extract({
|
||||
session: this.sessionName,
|
||||
path: compressedSessionPath,
|
||||
});
|
||||
await this.unCompressSession(compressedSessionPath);
|
||||
} else {
|
||||
fs.mkdirSync(this.userDataDir, { recursive: true });
|
||||
|
|
@ -147,8 +190,11 @@ class RemoteAuth extends BaseAuthStrategy {
|
|||
}
|
||||
|
||||
async deleteRemoteSession() {
|
||||
const sessionExists = await this.store.sessionExists({session: this.sessionName});
|
||||
if (sessionExists) await this.store.delete({session: this.sessionName});
|
||||
const sessionExists = await this.store.sessionExists({
|
||||
session: this.sessionName,
|
||||
});
|
||||
if (sessionExists)
|
||||
await this.store.delete({ session: this.sessionName });
|
||||
}
|
||||
|
||||
async compressSession() {
|
||||
|
|
@ -166,7 +212,7 @@ class RemoteAuth extends BaseAuthStrategy {
|
|||
out.once('close', resolve);
|
||||
out.once('error', reject);
|
||||
archive.once('error', reject);
|
||||
|
||||
|
||||
archive.pipe(out);
|
||||
archive.directory(this.tempDir, false);
|
||||
archive.finalize();
|
||||
|
|
@ -177,11 +223,14 @@ class RemoteAuth extends BaseAuthStrategy {
|
|||
async unCompressSession(compressedSessionPath) {
|
||||
var stream = fs.createReadStream(compressedSessionPath);
|
||||
await new Promise((resolve, reject) => {
|
||||
stream.pipe(unzipper.Extract({
|
||||
path: this.userDataDir,
|
||||
concurrency: 10
|
||||
}))
|
||||
.on('error', err => reject(err))
|
||||
stream
|
||||
.pipe(
|
||||
unzipper.Extract({
|
||||
path: this.userDataDir,
|
||||
concurrency: 10,
|
||||
}),
|
||||
)
|
||||
.on('error', (err) => reject(err))
|
||||
.on('finish', () => resolve());
|
||||
});
|
||||
await fs.promises.unlink(compressedSessionPath);
|
||||
|
|
@ -195,7 +244,7 @@ class RemoteAuth extends BaseAuthStrategy {
|
|||
await fs.promises.cp(src, dest, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
errorOnExist: false
|
||||
errorOnExist: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -211,7 +260,7 @@ class RemoteAuth extends BaseAuthStrategy {
|
|||
}
|
||||
|
||||
async delay(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class ChatFactory {
|
|||
if (data.isGroup) {
|
||||
return new GroupChat(client, data);
|
||||
}
|
||||
|
||||
|
||||
if (data.isChannel) {
|
||||
return new Channel(client, data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ const BusinessContact = require('../structures/BusinessContact');
|
|||
|
||||
class ContactFactory {
|
||||
static create(client, data) {
|
||||
if(data.isBusiness) {
|
||||
if (data.isBusiness) {
|
||||
return new BusinessContact(client, data);
|
||||
}
|
||||
|
||||
|
|
@ -13,4 +13,4 @@ class ContactFactory {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = ContactFactory;
|
||||
module.exports = ContactFactory;
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@ class Base {
|
|||
_clone() {
|
||||
return Object.assign(Object.create(this), this);
|
||||
}
|
||||
|
||||
_patch(data) { return data; }
|
||||
|
||||
_patch(data) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Base;
|
||||
module.exports = Base;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class Broadcast extends Base {
|
|||
* Messages statuses
|
||||
* @type {Message[]}
|
||||
*/
|
||||
this.msgs = data.msgs?.map(msg => new Message(this.client, msg));
|
||||
this.msgs = data.msgs?.map((msg) => new Message(this.client, msg));
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
|
@ -63,7 +63,6 @@ class Broadcast extends Base {
|
|||
getContact() {
|
||||
return this.client.getContactById(this.id._serialized);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Broadcast;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ class BusinessContact extends Contact {
|
|||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = BusinessContact;
|
||||
module.exports = BusinessContact;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class Buttons {
|
|||
* @type {string}
|
||||
*/
|
||||
this.title = title;
|
||||
|
||||
|
||||
/**
|
||||
* footer of message
|
||||
* @type {string}
|
||||
|
|
@ -49,7 +49,7 @@ class Buttons {
|
|||
if (body instanceof MessageMedia) {
|
||||
this.type = 'media';
|
||||
this.title = '';
|
||||
}else{
|
||||
} else {
|
||||
this.type = 'chat';
|
||||
}
|
||||
|
||||
|
|
@ -58,25 +58,29 @@ class Buttons {
|
|||
* @type {FormattedButtonSpec[]}
|
||||
*/
|
||||
this.buttons = this._format(buttons);
|
||||
if(!this.buttons.length){ throw '[BT01] No buttons';}
|
||||
|
||||
if (!this.buttons.length) {
|
||||
throw '[BT01] No buttons';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates button array from simple array
|
||||
* @param {ButtonSpec[]} buttons
|
||||
* @returns {FormattedButtonSpec[]}
|
||||
* @example
|
||||
* @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
|
||||
_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};
|
||||
return {
|
||||
buttonId: btn.id ? String(btn.id) : Util.generateHash(6),
|
||||
buttonText: { displayText: btn.body },
|
||||
type: 1,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Buttons;
|
||||
module.exports = Buttons;
|
||||
|
|
|
|||
|
|
@ -59,18 +59,22 @@ class Call extends Base {
|
|||
* @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);
|
||||
return this.client.pupPage.evaluate(
|
||||
(peerJid, id) => {
|
||||
return window.WWebJS.rejectCall(peerJid, id);
|
||||
},
|
||||
this.from,
|
||||
this.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Call;
|
||||
module.exports = Call;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class Channel extends Base {
|
|||
*/
|
||||
this.name = data.name;
|
||||
|
||||
/**
|
||||
/**
|
||||
* The channel description
|
||||
* @type {string}
|
||||
*/
|
||||
|
|
@ -89,7 +89,9 @@ class Channel extends Base {
|
|||
* Last message in the channel
|
||||
* @type {Message}
|
||||
*/
|
||||
this.lastMessage = data.lastMessage ? new Message(super.client, data.lastMessage) : undefined;
|
||||
this.lastMessage = data.lastMessage
|
||||
? new Message(super.client, data.lastMessage)
|
||||
: undefined;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
|
@ -100,58 +102,82 @@ class Channel extends Base {
|
|||
* @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.require('WAWebNewsletterGatingUtils').getMaxSubscriberNumber());
|
||||
const response = await (window.require('WAWebMexFetchNewsletterSubscribersJob')).mexFetchNewsletterSubscribers(channelId, limit);
|
||||
const contacts = (window.require('WAWebNewsletterSubscriberListAction')).getSubscribersInContacts(response.subscribers);
|
||||
return Promise.all(contacts.map((obj) => ({
|
||||
...obj,
|
||||
contact: window.WWebJS.getContactModel(obj.contact)
|
||||
})));
|
||||
}, this.id._serialized, 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
|
||||
.require('WAWebNewsletterGatingUtils')
|
||||
.getMaxSubscriberNumber());
|
||||
const response = await window
|
||||
.require('WAWebMexFetchNewsletterSubscribersJob')
|
||||
.mexFetchNewsletterSubscribers(channelId, limit);
|
||||
const contacts = window
|
||||
.require('WAWebNewsletterSubscriberListAction')
|
||||
.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
|
||||
* @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 });
|
||||
const success = await this._setChannelMetadata(
|
||||
{ name: newSubject },
|
||||
{ editName: true },
|
||||
);
|
||||
success && (this.name = newSubject);
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the channel description
|
||||
* @param {string} newDescription
|
||||
* @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 });
|
||||
const success = await this._setChannelMetadata(
|
||||
{ description: newDescription },
|
||||
{ editDescription: true },
|
||||
);
|
||||
success && (this.description = newDescription);
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the channel profile picture
|
||||
* @param {MessageMedia} newProfilePicture
|
||||
* @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 });
|
||||
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
|
||||
* @param {number} reactionCode
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async setReactionSetting(reactionCode) {
|
||||
|
|
@ -159,11 +185,11 @@ class Channel extends Base {
|
|||
const reactionMapper = {
|
||||
0: 3,
|
||||
1: 1,
|
||||
2: 0
|
||||
2: 0,
|
||||
};
|
||||
const success = await this._setChannelMetadata(
|
||||
{ reactionCodesSetting: reactionMapper[reactionCode] },
|
||||
{ editReactionCodesSetting: true }
|
||||
{ editReactionCodesSetting: true },
|
||||
);
|
||||
success && (this.channelMetadata.reactionCodesSetting = reactionCode);
|
||||
return success;
|
||||
|
|
@ -181,7 +207,7 @@ class Channel extends Base {
|
|||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unmutes the channel
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
|
|
@ -229,11 +255,15 @@ class Channel extends Base {
|
|||
/**
|
||||
* 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
|
||||
* @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);
|
||||
return this.client.sendChannelAdminInvite(
|
||||
chatId,
|
||||
this.id._serialized,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -250,7 +280,10 @@ class Channel extends Base {
|
|||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async revokeChannelAdminInvite(userId) {
|
||||
return this.client.revokeChannelAdminInvite(this.id._serialized, userId);
|
||||
return this.client.revokeChannelAdminInvite(
|
||||
this.id._serialized,
|
||||
userId,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -276,7 +309,11 @@ class Channel extends Base {
|
|||
* @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);
|
||||
return this.client.transferChannelOwnership(
|
||||
this.id._serialized,
|
||||
newOwnerId,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -287,36 +324,50 @@ class Channel extends Base {
|
|||
* @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;
|
||||
};
|
||||
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);
|
||||
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.require('WAWebChatLoadMessages')).loadEarlierMsgs(channel);
|
||||
if (!loadedMessages || !loadedMessages.length) break;
|
||||
msgs = [...loadedMessages.filter(msgFilter), ...msgs];
|
||||
if (searchOptions && searchOptions.limit > 0) {
|
||||
while (msgs.length < searchOptions.limit) {
|
||||
const loadedMessages = await window
|
||||
.require('WAWebChatLoadMessages')
|
||||
.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);
|
||||
}
|
||||
}
|
||||
|
||||
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 msgs.map((m) => window.WWebJS.getMessageModel(m));
|
||||
},
|
||||
this.id._serialized,
|
||||
searchOptions,
|
||||
);
|
||||
|
||||
return messages.map((msg) => new Message(this.client, msg));
|
||||
}
|
||||
|
|
@ -336,27 +387,39 @@ class Channel extends Base {
|
|||
* @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.require('WAWebEditNewsletterMetadataAction')).editNewsletterMetadataAction(channel, property, value);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, 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
|
||||
.require('WAWebEditNewsletterMetadataAction')
|
||||
.editNewsletterMetadataAction(channel, property, value);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
this.id._serialized,
|
||||
value,
|
||||
property,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -365,19 +428,35 @@ class Channel extends Base {
|
|||
* @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 {
|
||||
await (window.require('WAWebNewsletterUpdateUserSettingJob')).updateNewsletterUserSetting({
|
||||
newsletterJid: window.require('WAJids').toNewsletterJid(channelId),
|
||||
type: window.require('WAWebNewsletterModelUtils').ADMIN_NOTIFICATIONS,
|
||||
muteExpirationValue: action === 'MUTE' ? window.require('WAWebNewsletterModelUtils').MUTED_STATE : window.require('WAWebNewsletterModelUtils').UNMUTED_STATE
|
||||
});
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, action);
|
||||
return await this.client.pupPage.evaluate(
|
||||
async (channelId, action) => {
|
||||
try {
|
||||
await window
|
||||
.require('WAWebNewsletterUpdateUserSettingJob')
|
||||
.updateNewsletterUserSetting({
|
||||
newsletterJid: window
|
||||
.require('WAJids')
|
||||
.toNewsletterJid(channelId),
|
||||
type: window.require('WAWebNewsletterModelUtils')
|
||||
.ADMIN_NOTIFICATIONS,
|
||||
muteExpirationValue:
|
||||
action === 'MUTE'
|
||||
? window.require(
|
||||
'WAWebNewsletterModelUtils',
|
||||
).MUTED_STATE
|
||||
: window.require(
|
||||
'WAWebNewsletterModelUtils',
|
||||
).UNMUTED_STATE,
|
||||
});
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
this.id._serialized,
|
||||
action,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -85,15 +85,17 @@ class Chat extends Base {
|
|||
* Last message fo chat
|
||||
* @type {Message}
|
||||
*/
|
||||
this.lastMessage = data.lastMessage ? new Message(this.client, data.lastMessage) : undefined;
|
||||
|
||||
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]
|
||||
* @param {MessageSendOptions} [options]
|
||||
* @returns {Promise<Message>} Message that was just sent
|
||||
*/
|
||||
async sendMessage(content, options) {
|
||||
|
|
@ -113,7 +115,7 @@ class Chat extends Base {
|
|||
* @returns {Promise<boolean>} result
|
||||
*/
|
||||
async clearMessages() {
|
||||
return this.client.pupPage.evaluate(chatId => {
|
||||
return this.client.pupPage.evaluate((chatId) => {
|
||||
return window.WWebJS.sendClearChat(chatId);
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
|
@ -123,7 +125,7 @@ class Chat extends Base {
|
|||
* @returns {Promise<Boolean>} result
|
||||
*/
|
||||
async delete() {
|
||||
return this.client.pupPage.evaluate(chatId => {
|
||||
return this.client.pupPage.evaluate((chatId) => {
|
||||
return window.WWebJS.sendDeleteChat(chatId);
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
|
@ -164,7 +166,10 @@ class Chat extends Base {
|
|||
* @returns {Promise<{isMuted: boolean, muteExpiration: number}>}
|
||||
*/
|
||||
async mute(unmuteDate) {
|
||||
const result = await this.client.muteChat(this.id._serialized, unmuteDate);
|
||||
const result = await this.client.muteChat(
|
||||
this.id._serialized,
|
||||
unmuteDate,
|
||||
);
|
||||
this.isMuted = result.isMuted;
|
||||
this.muteExpiration = result.muteExpiration;
|
||||
return result;
|
||||
|
|
@ -184,7 +189,7 @@ class Chat extends Base {
|
|||
/**
|
||||
* Mark this chat as unread
|
||||
*/
|
||||
async markUnread(){
|
||||
async markUnread() {
|
||||
return this.client.markChatUnread(this.id._serialized);
|
||||
}
|
||||
|
||||
|
|
@ -196,45 +201,56 @@ class Chat extends Base {
|
|||
* @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
|
||||
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
|
||||
.require('WAWebChatLoadMessages')
|
||||
.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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
return msgs.map((m) => window.WWebJS.getMessageModel(m));
|
||||
},
|
||||
this.id._serialized,
|
||||
searchOptions,
|
||||
);
|
||||
|
||||
if (searchOptions && searchOptions.limit > 0) {
|
||||
while (msgs.length < searchOptions.limit) {
|
||||
const loadedMessages = await (window.require('WAWebChatLoadMessages')).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));
|
||||
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 => {
|
||||
return this.client.pupPage.evaluate((chatId) => {
|
||||
window.WWebJS.sendChatstate('typing', chatId);
|
||||
return true;
|
||||
}, this.id._serialized);
|
||||
|
|
@ -244,7 +260,7 @@ class Chat extends Base {
|
|||
* Simulate recording audio in chat. This will last for 25 seconds.
|
||||
*/
|
||||
async sendStateRecording() {
|
||||
return this.client.pupPage.evaluate(chatId => {
|
||||
return this.client.pupPage.evaluate((chatId) => {
|
||||
window.WWebJS.sendChatstate('recording', chatId);
|
||||
return true;
|
||||
}, this.id._serialized);
|
||||
|
|
@ -254,7 +270,7 @@ class Chat extends Base {
|
|||
* Stops typing or recording in chat immediately.
|
||||
*/
|
||||
async clearState() {
|
||||
return this.client.pupPage.evaluate(chatId => {
|
||||
return this.client.pupPage.evaluate((chatId) => {
|
||||
window.WWebJS.sendChatstate('stop', chatId);
|
||||
return true;
|
||||
}, this.id._serialized);
|
||||
|
|
@ -292,7 +308,7 @@ class Chat extends Base {
|
|||
async getPinnedMessages() {
|
||||
return this.client.getPinnedMessages(this.id._serialized);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sync chat history conversation
|
||||
* @return {Promise<boolean>} True if operation completed successfully, false otherwise.
|
||||
|
|
@ -327,7 +343,7 @@ class Chat extends Base {
|
|||
*/
|
||||
async getCustomerNote() {
|
||||
if (this.isGroup || this.isChannel) return null;
|
||||
|
||||
|
||||
return this.client.getCustomerNote(this.id._serialized);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,4 +68,4 @@ class ClientInfo extends Base {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = ClientInfo;
|
||||
module.exports = ClientInfo;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class Contact extends Base {
|
|||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if(data) this._patch(data);
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
|
|
@ -108,7 +108,7 @@ class Contact extends Base {
|
|||
* @type {boolean}
|
||||
*/
|
||||
this.isBlocked = data.isBlocked;
|
||||
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ class Contact extends Base {
|
|||
async getFormattedNumber() {
|
||||
return await this.client.getFormattedNumber(this.id._serialized);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the contact's countrycode, (1541859685@c.us) => (1)
|
||||
* @returns {Promise<string>}
|
||||
|
|
@ -135,14 +135,14 @@ class Contact extends Base {
|
|||
async getCountryCode() {
|
||||
return await this.client.getCountryCode(this.id._serialized);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the Chat that corresponds to this Contact.
|
||||
* 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;
|
||||
if (this.isMe) return null;
|
||||
|
||||
return await this.client.getChatById(this.id._serialized);
|
||||
}
|
||||
|
|
@ -152,11 +152,13 @@ class Contact extends Base {
|
|||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async block() {
|
||||
if(this.isGroup) return false;
|
||||
if (this.isGroup) return false;
|
||||
|
||||
await this.client.pupPage.evaluate(async (contactId) => {
|
||||
const chat = await window.WWebJS.getChat(contactId);
|
||||
await (window.require('WAWebBlockContactAction')).blockContact({'contact':chat});
|
||||
await window
|
||||
.require('WAWebBlockContactAction')
|
||||
.blockContact({ contact: chat });
|
||||
}, this.id._serialized);
|
||||
|
||||
this.isBlocked = true;
|
||||
|
|
@ -168,11 +170,15 @@ class Contact extends Base {
|
|||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async unblock() {
|
||||
if(this.isGroup) return false;
|
||||
if (this.isGroup) return false;
|
||||
|
||||
await this.client.pupPage.evaluate(async (contactId) => {
|
||||
const contact = (window.require('WAWebCollections')).Contact.get(contactId);
|
||||
await (window.require('WAWebBlockContactAction')).unblockContact(contact);
|
||||
const contact = window
|
||||
.require('WAWebCollections')
|
||||
.Contact.get(contactId);
|
||||
await window
|
||||
.require('WAWebBlockContactAction')
|
||||
.unblockContact(contact);
|
||||
}, this.id._serialized);
|
||||
|
||||
this.isBlocked = false;
|
||||
|
|
@ -186,11 +192,12 @@ class Contact extends Base {
|
|||
async getAbout() {
|
||||
const about = await this.client.pupPage.evaluate(async (contactId) => {
|
||||
const wid = window.require('WAWebWidFactory').createWid(contactId);
|
||||
return (window.require('WAWebContactStatusBridge')).getStatus({'token':'', 'wid': wid});
|
||||
return window
|
||||
.require('WAWebContactStatusBridge')
|
||||
.getStatus({ token: '', wid: wid });
|
||||
}, this.id._serialized);
|
||||
|
||||
if (typeof about.status !== 'string')
|
||||
return null;
|
||||
if (typeof about.status !== 'string') return null;
|
||||
|
||||
return about.status;
|
||||
}
|
||||
|
|
@ -206,7 +213,7 @@ class Contact extends Base {
|
|||
/**
|
||||
* Gets the Contact's current status broadcast.
|
||||
* @returns {Promise<Broadcast>}
|
||||
*/
|
||||
*/
|
||||
async getBroadcast() {
|
||||
return await this.client.getBroadcastById(this.id._serialized);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class GroupChat extends Chat {
|
|||
get owner() {
|
||||
return this.groupMetadata.owner;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the date at which the group was created
|
||||
* @type {date}
|
||||
|
|
@ -37,7 +37,7 @@ class GroupChat extends Chat {
|
|||
return new Date(this.groupMetadata.creation * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Gets the group description
|
||||
* @type {string}
|
||||
*/
|
||||
|
|
@ -71,265 +71,440 @@ class GroupChat extends Chat {
|
|||
|
||||
/**
|
||||
* Adds a list of participants by ID to the group
|
||||
* @param {string|Array<string>} participantIds
|
||||
* @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 = {};
|
||||
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.require('WAWebWidFactory').createWid(groupId);
|
||||
const group = (window.require('WAWebCollections')).Chat.get(groupWid) || (await (window.require('WAWebCollections')).Chat.find(groupWid));
|
||||
const participantWids = participantIds.map((p) => window.require('WAWebWidFactory').createWid(p));
|
||||
!Array.isArray(participantIds) &&
|
||||
(participantIds = [participantIds]);
|
||||
const groupWid = window
|
||||
.require('WAWebWidFactory')
|
||||
.createWid(groupId);
|
||||
const group =
|
||||
window.require('WAWebCollections').Chat.get(groupWid) ||
|
||||
(await window
|
||||
.require('WAWebCollections')
|
||||
.Chat.find(groupWid));
|
||||
const participantWids = participantIds.map((p) =>
|
||||
window.require('WAWebWidFactory').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.require('WAWebGroupQueryJob')).queryAndUpdateGroupMetadataById({ 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.require('WAWebApiContact').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.require('WAWebApiContact').getPhoneNumber(pWid) : pWid;
|
||||
|
||||
participantData[pId] = {
|
||||
code: undefined,
|
||||
message: undefined,
|
||||
isInviteV4Sent: false
|
||||
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",
|
||||
};
|
||||
|
||||
if (groupParticipants.some(p => p._serialized === pId)) {
|
||||
participantData[pId].code = 409;
|
||||
participantData[pId].message = errorCodes[409];
|
||||
continue;
|
||||
await window
|
||||
.require('WAWebGroupQueryJob')
|
||||
.queryAndUpdateGroupMetadataById({ id: groupId });
|
||||
|
||||
let groupParticipants =
|
||||
group.groupMetadata?.participants.serialize();
|
||||
|
||||
if (!groupParticipants) {
|
||||
return errorCodes.isGroupEmpty;
|
||||
}
|
||||
|
||||
if (!(await (window.require('WAWebQueryExistsJob').queryWidExists)(pWid))?.wid) {
|
||||
participantData[pId].code = 404;
|
||||
participantData[pId].message = errorCodes[404];
|
||||
continue;
|
||||
if (!group.iAmAdmin()) {
|
||||
return errorCodes.iAmNotAdmin;
|
||||
}
|
||||
|
||||
const rpcResult =
|
||||
await window.WWebJS.getAddParticipantsRpcResult(groupWid, pWid);
|
||||
const { code: rpcResultCode } = rpcResult;
|
||||
groupParticipants.map(({ id }) => {
|
||||
return id.server === 'lid'
|
||||
? window.require('WAWebApiContact').getPhoneNumber(id)
|
||||
: id;
|
||||
});
|
||||
|
||||
participantData[pId].code = rpcResultCode;
|
||||
participantData[pId].message =
|
||||
errorCodes[rpcResultCode] || errorCodes.default;
|
||||
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]
|
||||
);
|
||||
};
|
||||
|
||||
if (autoSendInviteV4 && rpcResultCode === 403) {
|
||||
let userChat, isInviteV4Sent = false;
|
||||
(window.require('WAWebCollections')).Contact.gadd(pWid, { silent: true });
|
||||
for (let pWid of participantWids) {
|
||||
const pId = pWid._serialized;
|
||||
pWid =
|
||||
pWid.server === 'lid'
|
||||
? window
|
||||
.require('WAWebApiContact')
|
||||
.getPhoneNumber(pWid)
|
||||
: pWid;
|
||||
|
||||
if (rpcResult.name === 'ParticipantRequestCodeCanBeSent' &&
|
||||
(userChat = (window.require('WAWebCollections')).Chat.get(pWid) || (await (window.require('WAWebCollections')).Chat.find(pWid)))) {
|
||||
const groupName = group.formattedTitle || group.name;
|
||||
const res = await (window.require('WAWebChatSendMessages')).sendGroupInviteMessage(
|
||||
userChat,
|
||||
group.id._serialized,
|
||||
groupName,
|
||||
rpcResult.inviteV4Code,
|
||||
rpcResult.inviteV4CodeExp,
|
||||
comment,
|
||||
await window.WWebJS.getProfilePicThumbToBase64(groupWid)
|
||||
);
|
||||
isInviteV4Sent = res.messageSendResult === 'OK';
|
||||
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;
|
||||
}
|
||||
|
||||
participantData[pId].isInviteV4Sent = isInviteV4Sent;
|
||||
if (
|
||||
!(
|
||||
await window
|
||||
.require('WAWebQueryExistsJob')
|
||||
.queryWidExists(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
|
||||
.require('WAWebCollections')
|
||||
.Contact.gadd(pWid, { silent: true });
|
||||
|
||||
if (
|
||||
rpcResult.name ===
|
||||
'ParticipantRequestCodeCanBeSent' &&
|
||||
(userChat =
|
||||
window
|
||||
.require('WAWebCollections')
|
||||
.Chat.get(pWid) ||
|
||||
(await window
|
||||
.require('WAWebCollections')
|
||||
.Chat.find(pWid)))
|
||||
) {
|
||||
const groupName =
|
||||
group.formattedTitle || group.name;
|
||||
const res = await window
|
||||
.require('WAWebChatSendMessages')
|
||||
.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)),
|
||||
));
|
||||
}
|
||||
|
||||
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);
|
||||
return participantData;
|
||||
},
|
||||
this.id._serialized,
|
||||
participantIds,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a list of participants by ID to the group
|
||||
* @param {Array<string>} participantIds
|
||||
* @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 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.require('WAWebModifyParticipantsGroupAction')).removeParticipants(chat, participants);
|
||||
return { status: 200 };
|
||||
}, this.id._serialized, participantIds);
|
||||
return (
|
||||
chat.groupMetadata.participants.get(
|
||||
lid?._serialized,
|
||||
) ||
|
||||
chat.groupMetadata.participants.get(
|
||||
phone?._serialized,
|
||||
)
|
||||
);
|
||||
}),
|
||||
)
|
||||
).filter(Boolean);
|
||||
await window
|
||||
.require('WAWebModifyParticipantsGroupAction')
|
||||
.removeParticipants(chat, participants);
|
||||
return { status: 200 };
|
||||
},
|
||||
this.id._serialized,
|
||||
participantIds,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Promotes participants by IDs to admins
|
||||
* @param {Array<string>} participantIds
|
||||
* @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 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.require('WAWebModifyParticipantsGroupAction')).promoteParticipants(chat, participants);
|
||||
return { status: 200 };
|
||||
}, this.id._serialized, participantIds);
|
||||
return (
|
||||
chat.groupMetadata.participants.get(
|
||||
lid?._serialized,
|
||||
) ||
|
||||
chat.groupMetadata.participants.get(
|
||||
phone?._serialized,
|
||||
)
|
||||
);
|
||||
}),
|
||||
)
|
||||
).filter(Boolean);
|
||||
await window
|
||||
.require('WAWebModifyParticipantsGroupAction')
|
||||
.promoteParticipants(chat, participants);
|
||||
return { status: 200 };
|
||||
},
|
||||
this.id._serialized,
|
||||
participantIds,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Demotes participants by IDs to regular users
|
||||
* @param {Array<string>} participantIds
|
||||
* @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 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.require('WAWebModifyParticipantsGroupAction')).demoteParticipants(chat, participants);
|
||||
return { status: 200 };
|
||||
}, this.id._serialized, participantIds);
|
||||
return (
|
||||
chat.groupMetadata.participants.get(
|
||||
lid?._serialized,
|
||||
) ||
|
||||
chat.groupMetadata.participants.get(
|
||||
phone?._serialized,
|
||||
)
|
||||
);
|
||||
}),
|
||||
)
|
||||
).filter(Boolean);
|
||||
await window
|
||||
.require('WAWebModifyParticipantsGroupAction')
|
||||
.demoteParticipants(chat, participants);
|
||||
return { status: 200 };
|
||||
},
|
||||
this.id._serialized,
|
||||
participantIds,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the group subject
|
||||
* @param {string} 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.require('WAWebWidFactory').createWid(chatId);
|
||||
try {
|
||||
await (window.require('WAWebGroupModifyInfoJob')).setGroupSubject(chatWid, subject);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, subject);
|
||||
const success = await this.client.pupPage.evaluate(
|
||||
async (chatId, subject) => {
|
||||
const chatWid = window
|
||||
.require('WAWebWidFactory')
|
||||
.createWid(chatId);
|
||||
try {
|
||||
await window
|
||||
.require('WAWebGroupModifyInfoJob')
|
||||
.setGroupSubject(chatWid, subject);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
this.id._serialized,
|
||||
subject,
|
||||
);
|
||||
|
||||
if(!success) return false;
|
||||
if (!success) return false;
|
||||
this.name = subject;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the group description
|
||||
* @param {string} 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.require('WAWebWidFactory').createWid(chatId);
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
let descId = chat.groupMetadata.descId;
|
||||
let newId = await (window.require('WAWebMsgKey')).newId();
|
||||
try {
|
||||
await (window.require('WAWebGroupModifyInfoJob')).setGroupDescription(chatWid, description, newId, descId);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, description);
|
||||
const success = await this.client.pupPage.evaluate(
|
||||
async (chatId, description) => {
|
||||
const chatWid = window
|
||||
.require('WAWebWidFactory')
|
||||
.createWid(chatId);
|
||||
const chat = await window.WWebJS.getChat(chatId, {
|
||||
getAsModel: false,
|
||||
});
|
||||
let descId = chat.groupMetadata.descId;
|
||||
let newId = await window.require('WAWebMsgKey').newId();
|
||||
try {
|
||||
await window
|
||||
.require('WAWebGroupModifyInfoJob')
|
||||
.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;
|
||||
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
|
||||
* @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.require('WAWebSetPropertyGroupAction')).setGroupProperty(chat, 'member_add_mode', adminsOnly ? 0 : 1);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, adminsOnly);
|
||||
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
|
||||
.require('WAWebSetPropertyGroupAction')
|
||||
.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');
|
||||
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
|
||||
* @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.require('WAWebSetPropertyGroupAction')).setGroupProperty(chat, 'announcement', adminsOnly ? 1 : 0);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, adminsOnly);
|
||||
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
|
||||
.require('WAWebSetPropertyGroupAction')
|
||||
.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;
|
||||
if (!success) return false;
|
||||
|
||||
this.groupMetadata.announce = adminsOnly;
|
||||
return true;
|
||||
|
|
@ -337,27 +512,35 @@ class GroupChat extends Chat {
|
|||
|
||||
/**
|
||||
* Updates the group settings to only allow admins to edit group info (title, description, photo).
|
||||
* @param {boolean} [adminsOnly=true] Enable or disable this option
|
||||
* @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.require('WAWebSetPropertyGroupAction')).setGroupProperty(chat, 'restrict', adminsOnly ? 1 : 0);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, adminsOnly);
|
||||
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
|
||||
.require('WAWebSetPropertyGroupAction')
|
||||
.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;
|
||||
|
||||
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.
|
||||
|
|
@ -376,9 +559,13 @@ class GroupChat extends Chat {
|
|||
* @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);
|
||||
const success = await this.client.pupPage.evaluate(
|
||||
(chatid, media) => {
|
||||
return window.WWebJS.setPicture(chatid, media);
|
||||
},
|
||||
this.id._serialized,
|
||||
media,
|
||||
);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
|
@ -388,34 +575,35 @@ class GroupChat extends Chat {
|
|||
* @returns {Promise<string>} Group's invite code
|
||||
*/
|
||||
async getInviteCode() {
|
||||
const codeRes = await this.client.pupPage.evaluate(async chatId => {
|
||||
const codeRes = await this.client.pupPage.evaluate(async (chatId) => {
|
||||
try {
|
||||
return await (window.require('WAWebMexFetchGroupInviteCodeJob')).fetchMexGroupInviteCode(chatId);
|
||||
}
|
||||
catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return undefined;
|
||||
return await window
|
||||
.require('WAWebMexFetchGroupInviteCodeJob')
|
||||
.fetchMexGroupInviteCode(chatId);
|
||||
} catch (err) {
|
||||
if (err.name === 'ServerStatusCodeError') return undefined;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized);
|
||||
|
||||
return codeRes?.code
|
||||
? codeRes?.code
|
||||
: codeRes;
|
||||
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 codeRes = await this.client.pupPage.evaluate((chatId) => {
|
||||
const chatWid = window.require('WAWebWidFactory').createWid(chatId);
|
||||
return (window.require('WAWebGroupQueryJob')).resetGroupInviteCode(chatWid);
|
||||
return window
|
||||
.require('WAWebGroupQueryJob')
|
||||
.resetGroupInviteCode(chatWid);
|
||||
}, this.id._serialized);
|
||||
|
||||
return codeRes.code;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An object that handles the information about the group membership request
|
||||
* @typedef {Object} GroupMembershipRequest
|
||||
|
|
@ -425,13 +613,15 @@ class GroupChat extends Chat {
|
|||
* @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);
|
||||
return await this.client.getGroupMembershipRequests(
|
||||
this.id._serialized,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -455,7 +645,10 @@ class GroupChat extends Chat {
|
|||
* @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);
|
||||
return await this.client.approveGroupMembershipRequests(
|
||||
this.id._serialized,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -464,7 +657,10 @@ class GroupChat extends Chat {
|
|||
* @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);
|
||||
return await this.client.rejectGroupMembershipRequests(
|
||||
this.id._serialized,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -472,12 +668,13 @@ class GroupChat extends Chat {
|
|||
* @returns {Promise}
|
||||
*/
|
||||
async leave() {
|
||||
await this.client.pupPage.evaluate(async chatId => {
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
return (window.require('WAWebExitGroupAction')).sendExitGroup(chat);
|
||||
await this.client.pupPage.evaluate(async (chatId) => {
|
||||
const chat = await window.WWebJS.getChat(chatId, {
|
||||
getAsModel: false,
|
||||
});
|
||||
return window.require('WAWebExitGroupAction').sendExitGroup(chat);
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GroupChat;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class GroupNotification extends Base {
|
|||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if(data) this._patch(data);
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
|
|
@ -26,12 +26,12 @@ class GroupNotification extends Base {
|
|||
*/
|
||||
this.body = data.body || '';
|
||||
|
||||
/**
|
||||
/**
|
||||
* GroupNotification type
|
||||
* @type {GroupNotificationTypes}
|
||||
*/
|
||||
this.type = data.subtype;
|
||||
|
||||
|
||||
/**
|
||||
* Unix timestamp for when the groupNotification was created
|
||||
* @type {number}
|
||||
|
|
@ -40,17 +40,23 @@ class GroupNotification extends Base {
|
|||
|
||||
/**
|
||||
* 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;
|
||||
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;
|
||||
|
||||
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>}
|
||||
|
|
@ -85,20 +91,23 @@ class GroupNotification extends Base {
|
|||
* @returns {Promise<Array<Contact>>}
|
||||
*/
|
||||
async getRecipients() {
|
||||
return await Promise.all(this.recipientIds.map(async m => await this.client.getContactById(m)));
|
||||
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 {string|MessageMedia|Location} content
|
||||
* @param {object} options
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
async reply(content, options={}) {
|
||||
async reply(content, options = {}) {
|
||||
return this.client.sendMessage(this.chatId, content, options);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GroupNotification;
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@ class Label extends Base {
|
|||
* @param {Base} client
|
||||
* @param {object} labelData
|
||||
*/
|
||||
constructor(client, labelData){
|
||||
constructor(client, labelData) {
|
||||
super(client);
|
||||
|
||||
if(labelData) this._patch(labelData);
|
||||
if (labelData) this._patch(labelData);
|
||||
}
|
||||
|
||||
_patch(labelData){
|
||||
_patch(labelData) {
|
||||
/**
|
||||
* Label ID
|
||||
* @type {string}
|
||||
|
|
@ -41,10 +41,9 @@ class Label extends Base {
|
|||
* Get all chats that have been assigned this Label
|
||||
* @returns {Promise<Array<Chat>>}
|
||||
*/
|
||||
async getChats(){
|
||||
async getChats() {
|
||||
return this.client.getChatsByLabelId(this.id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Label;
|
||||
module.exports = Label;
|
||||
|
|
|
|||
|
|
@ -25,13 +25,12 @@ class List {
|
|||
* @type {string}
|
||||
*/
|
||||
this.buttonText = buttonText;
|
||||
|
||||
|
||||
/**
|
||||
* title of message
|
||||
* @type {string}
|
||||
*/
|
||||
this.title = title;
|
||||
|
||||
|
||||
/**
|
||||
* footer of message
|
||||
|
|
@ -44,9 +43,8 @@ class List {
|
|||
* @type {Array<any>}
|
||||
*/
|
||||
this.sections = this._format(sections);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates section array from simple array
|
||||
* @param {Array<any>} sections
|
||||
|
|
@ -55,25 +53,35 @@ class List {
|
|||
* 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';}
|
||||
_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';}
|
||||
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 : ''
|
||||
description: row.description ? row.description : '',
|
||||
};
|
||||
})
|
||||
}),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = List;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue