Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions src/auth/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
const whatsapp = require('whatsapp-web.js');
const { Client } = require('whatsapp-web.js');
const qrcode = require('qrcode-terminal');
const fs = require('fs');
const path = require('path');

const FILE_NAME = 'session.json';

class Session extends whatsapp.Client {
/**
* Starting point for interacting with the WhatsApp Web API.
* @param {string} SESSION_FILE_PATH - Path to `session.json` file.
* @see https://docs.wwebjs.dev/Client.html
* @extends {Client}
*/
class Session extends Client {
constructor() {
super({
puppeteer: {
Expand All @@ -16,22 +22,36 @@ class Session extends whatsapp.Client {
this.SESSION_FILE_PATH = path.join(__dirname, FILE_NAME);
}

/**
* Checks if the `session.json` file already exists.
* @returns {boolean} - `True` if exists, `False` if not.
*/
get exists() {
return fs.existsSync(this.SESSION_FILE_PATH);
}

/**
* Throws the QR-Code to authenticate the session. When the QR-Code is read, the session file is written.
*/
create() {
this.on('qr', (qr) => {
qrcode.generate(qr, { small: true });
});
this.on('authenticated', this.save);
}

/**
* Writes the session in a .json file (`this.SESSION_FILE_PATH`)
* @param {object} session - The session file returned in the authentication.
*/
save(session) {
fs.writeFileSync(this.SESSION_FILE_PATH, JSON.stringify(session));
console.log('⚠ The current session has been saved ⚠');
}

/**
* Loads the saved session file.
*/
load() {
if (!this.exists) {
throw Error(`session data does not exist in ${this.SESSION_FILE_PATH}`);
Expand All @@ -44,6 +64,9 @@ class Session extends whatsapp.Client {
console.log('⚠ The previous session was loaded ⚠');
}

/**
* Starts the session.
*/
start() {
this.on('ready', () => {
console.log('Client is ready!');
Expand Down
28 changes: 28 additions & 0 deletions src/build/Commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,21 @@ function isFunction(object) {
return typeof object === 'function';
}

/**
* Commands wrapper
* @param {object} commands - Object that contains the commands.
* @param {object} commands.* - A command. The key and value must be, respectively, the command name and a callback function for the command.
*/
class Commands {
constructor() {
this.commands = {};
}

/**
* Sets a command in Commands instance.
* @param {string} name - Command's name.
* @param {function} callback - Callback to command.
*/
set(name, callback) {
if (!isFunction(callback)) {
throw new Error(`${callback} must be a function`);
Expand All @@ -15,11 +25,29 @@ class Commands {
this.commands[name] = callback;
}

/**
* Checks if a command is set in Commands instance.
* @param {string} cmd - The command's name.
* @returns {boolean} `True` if the command is set in Commands instance, `False` if not.
*/
has(cmd) {
const availableCommands = Object.keys(this.commands);
return availableCommands.includes(cmd);
}

/**
* Calls (executes) a command.
* @param {string} cmd - The command's name to be called.
* @param {object} data - The data extracted from the message that called the command.
* @param {string} data.command - The command's name extracted from the message.
* @param {string[]} data.args - The args extracted from the message.
* @param {object} data.kwargs - The kwargs extracted from the message.
* @param {string} data.text - The text extracted from the message. This text NOT includes command's name, args and kwargs.
* @param {Message} message - The message that called the command.
* @param {Session} client - The whatsapp web session.
* @see https://docs.wwebjs.dev/Message.html
* @see https://docs.wwebjs.dev/Client.html
*/
async call(cmd, data, message, client) {
if (!this.has(cmd)) {
throw new Error(`${cmd} is not registered`);
Expand Down
35 changes: 35 additions & 0 deletions src/utils/Parse.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,56 @@
/**
* Extract useful data from a given string (usually the content of a message).
* @example
* const messageContent = '!command --arg1 --kwarg=1 any text here'
* const data = new Parse(messageContent)
* data.command // command
* data.args // ['arg1']
* data.kwargs // { kwarg: 1 }
* data.text // 'any text here'
* @param {string} text - Text to be parsed.
*/
class Parse {
constructor(text) {
/** The original text. */
this.rawText = text.trim();

/**
* A collection of regular expressions used in the extraction of data from the `this.rawText`.
* @property {string} REGEXP.command - Regular expression for commands. Ex: !command
* @property {string[]} REGEXP.args - Regular expression for args. Ex: --arg1
* @property {object} REGEXP.kwargs - Regular expression for kwargs. Ex: --kwarg=1
*/
this.REGEXP = {
command: /^!([^\s]+)/,
args: /--([\S]+)(?=\s|$)/g,
kwargs: /--([a-zA-Z0-9_-]+)="?([a-z0-9\.]+)"?/g, // eslint-disable-line
};
}

/**
* Gets the command extracted from the `this.rawText`.
* @returns {string}
*/
get command() {
const matches = this.rawText.match(this.REGEXP.command);
return matches ? matches[1] : '';
}

/**
* Gets the args extracted from `this.rawText`.
* @returns {string[]}
*/
get args() {
const matchesIter = this.rawText.matchAll(this.REGEXP.args);
const matchesArray = [...matchesIter];
const matches = matchesArray.map((elem) => elem[1]);
return matches;
}

/**
* Gets the kwargs extracted from `this.rawText`.
* @returns {object}
*/
get kwargs() {
const obj = {};
const matchesIter = this.rawText.matchAll(this.REGEXP.kwargs);
Expand All @@ -32,6 +63,10 @@ class Parse {
return obj;
}

/**
* Gets the text extracted from `this.rawText`.
* @returns {string}
*/
get text() {
return this.rawText
.replace(this.REGEXP.command, '')
Expand Down
43 changes: 26 additions & 17 deletions src/utils/chattools.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
/**
* Get serialized number
* @param {Array<Object>} idList - An array containing objects about user identification.
* @return {Array<String>} - Contains serialized phone numbers
* Get serialized phone number from a given array of users.
* @param {Contact[]} users - Whatsapp users.
* @see https://docs.wwebjs.dev/Contact.html
* @returns {string[]} - Serialized phone numbers.
*/
function getSerialList(idList) {
function getSerialList(users) {
// eslint-disable-next-line no-underscore-dangle
const serialList = idList.map((id) => id.id._serialized);
const serialList = users.map((u) => u.id._serialized);
return serialList;
}

/**
* Get serialized number of all members in group
* @param {Object} chat - Object that represents the current chat
* @return {Array<String>} - Contains serialized phone numbers of all members
* Get serialized phone number of all members from a given group.
* @param {Chat} chat - A whatsapp chat.
* @see https://docs.wwebjs.dev/Chat.html
* @returns {string[]} - Serialized phone numbers of all members.
*/
async function getMembersList(chat) {
const members = await chat.participants;
Expand All @@ -21,9 +23,10 @@ async function getMembersList(chat) {
}

/**
* Get serialized number of all administrators in group
* @param {Object} chat - Object that represents the current chat
* @return {Array<String>} - Contains serialized phone numbers of all administrators
* Get serialized phone number of all administrators from a given group.
* @param {Chat} chat - A whatsapp chat.
* @see https://docs.wwebjs.dev/Chat.html
* @returns {string[]} - Serialized phone numbers of all administrators.
*/
async function getAdmsList(chat) {
const members = await chat.participants;
Expand All @@ -33,9 +36,10 @@ async function getAdmsList(chat) {
}

/**
* Check if a message if from an adm
* @param {Object} message - Object that represents the current message
* @return {Boolean}
* Checks if a message is from an ADM.
* @param {Message} message - Message to check if is from an ADM.
* @see https://docs.wwebjs.dev/Message.html
* @returns {boolean}
*/
async function isAdm(message) {
const chat = await message.getChat();
Expand All @@ -44,12 +48,17 @@ async function isAdm(message) {
return admList.includes(author);
}

function userID(targetNumber) {
if (typeof targetNumber !== 'string') {
/**
* Get a whatsapp user id for a given phone number.
* @param {string} phoneNumber
* @returns {string}
*/
function userID(phoneNumber) {
if (typeof phoneNumber !== 'string') {
throw new Error('you must pass the number as a string');
}

const target = targetNumber.replace(/\D/g, '');
const target = phoneNumber.replace(/\D/g, '');
const regexp = /\d+/;
const matches = target.match(regexp);
const pattern = matches[0];
Expand Down
9 changes: 8 additions & 1 deletion src/utils/search.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
const googleIt = require('google-it');

async function google(query, target = '', limit = null) {
/**
* Searchs for a given string in google.
* @param {string} query Text that must be searched.
* @param {string} [target=''] Target site to search in.
* @param {number} [limit=0] Max number of results that must be returned.
* @returns {object[]} Array of results found.
*/
async function google(query, target = '', limit = 0) {
const result = await googleIt({
query,
includeSites: target,
Expand Down
23 changes: 18 additions & 5 deletions src/utils/time.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
/**
* Suspends (waits) execution of the current thread for a given number of seconds.
* @param {number} seconds
* @returns {Promise}
*/
function sleep(seconds) {
return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
}

function timer(sec = 0, min = 0, hour = 0, day = 0) {
const secsInMS = sec * 1000;
const minsInMS = min * 60 * 1000;
const hoursInMS = hour * 60 * 60 * 1000;
const daysInMS = day * 24 * 60 * 60 * 1000;
/**
* Converts a given set of seconds, minutes, hours and days in miliseconds.
* @param {number} [secs=0]
* @param {number} [mins=0]
* @param {number} [hours=0]
* @param {number} [days=0]
* @returns {number} Total time in miliseconds.
*/
function timer(secs = 0, mins = 0, hours = 0, days = 0) {
const secsInMS = secs * 1000;
const minsInMS = mins * 60 * 1000;
const hoursInMS = hours * 60 * 60 * 1000;
const daysInMS = days * 24 * 60 * 60 * 1000;
const timeInMS = secsInMS + minsInMS + hoursInMS + daysInMS;
return timeInMS;
}
Expand Down