From 75073e5e03043ae3417da27f955387081915b879 Mon Sep 17 00:00:00 2001 From: Mohammed Ashab Uddin Date: Thu, 6 Aug 2020 13:03:28 +0400 Subject: [PATCH 1/7] commands can now get media as input --- whatsapp-web.js/src/models/commands.js | 59 ++++++++++++++++++++++---- whatsapp-web.js/test/test_command.js | 22 +++++----- 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/whatsapp-web.js/src/models/commands.js b/whatsapp-web.js/src/models/commands.js index 5b1a07f..59711e5 100644 --- a/whatsapp-web.js/src/models/commands.js +++ b/whatsapp-web.js/src/models/commands.js @@ -1,12 +1,15 @@ +const fs = require('fs'); + class Command{ /** * - * @param {{string, function()}} param0 + * @param {{string, function(),boolean}} param0 */ - constructor({command,callback}){ + constructor({command,callback, requireMedia = false}){ this.command = command; this.callback = callback; + this.requireMedia = requireMedia; this.requireInput = false; this.inputPos = []; this._requireInput(); @@ -30,7 +33,7 @@ class Command{ let splitCommand = this.command.split(' '); - let splitMsg = this._getInputMessage(message); + let splitMsg = this._getSplitMessage(message); //check the number of words both has @@ -70,6 +73,12 @@ class Command{ * then the command requires input */ _requireInput(){ + if(this.requireMedia) + { + this.requireInput = true; + return; + } + let msg = this.command; let matched = msg.match(/[<>]/g); @@ -79,14 +88,28 @@ class Command{ /** * returns an array of string representing the inputs of the command - * @param {string} message + * @param {import("whatsapp-web.js").Message} message */ - getInput(message){ + async getInput(message){ + + if(this.requireMedia){ + + return await this._getInputMedia(message); + }else{ + + return this._getInputMessage(message.body); + } + } + + /** + * + * @param {string} msgString + */ + _getInputMessage(msgString){ - let splitMsg = this._getInputMessage(message); - let splitCommand = this.command.split(' '); let input = {}; - let debug = ''; + let splitMsg = this._getSplitMessage(msgString); + let splitCommand = this.command.split(' '); for(let i = 0; i < splitMsg.length; i++){ if(splitCommand[i].startsWith('<')){ let key = splitCommand[i].slice(1, splitCommand[i].length-1); @@ -94,9 +117,14 @@ class Command{ } } return input; + } - _getInputMessage(msg){ + /** + * + * @param {string} msg + */ + _getSplitMessage(msg){ let split = msg.split(/['"]/g); if(split.length > 1) { @@ -109,6 +137,19 @@ class Command{ return msg.split(' '); } + /** + * + * @param {import("whatsapp-web.js").Message} message + */ + async _getInputMedia(message){ + let input = {}; + if(message.hasMedia){ + let media = await message.downloadMedia(); + input['media'] = media.data; + } + return input; + } + } module.exports.Command = Command; diff --git a/whatsapp-web.js/test/test_command.js b/whatsapp-web.js/test/test_command.js index df1577e..b582631 100644 --- a/whatsapp-web.js/test/test_command.js +++ b/whatsapp-web.js/test/test_command.js @@ -135,7 +135,7 @@ describe('Command', () => { expect(a.equals(message)).to.false; }); - it('Test : getInput() with 1 input', () => { + it('Test : _getInputMessage() with 1 input', () => { let message = 'wg create p12' @@ -146,10 +146,10 @@ describe('Command', () => { } }); - expect(a.getInput(message)['id']).to.equal('p12'); + expect(a._getInputMessage(message)['id']).to.equal('p12'); }); - it('Test : getInput() with 2 input', () => { + it('Test : _getInputMessage() with 2 input', () => { let message = 'wg create p12 pikachu' @@ -160,31 +160,31 @@ describe('Command', () => { } }); - expect(a.getInput(message)['id']).to.equal('p12'); - expect(a.getInput(message)['name']).to.equal('pikachu'); + expect(a._getInputMessage(message)['id']).to.equal('p12'); + expect(a._getInputMessage(message)['name']).to.equal('pikachu'); }); - it('Test : _getInputMessage() with a sentence', () => { + it('Test : _getSplitMessage() with a sentence', () => { let a = new Command({command : 'wg website desc '}); - let b = a._getInputMessage(`wg website desc "Hello everynyan, how are you"`); + let b = a._getSplitMessage(`wg website desc "Hello everynyan, how are you"`); expect(b[0]).to.equal('wg'); expect(b[1]).to.equal('website'); expect(b[2]).to.equal('desc'); expect(b[3]).to.equal('Hello everynyan, how are you'); }) - it('Test : _getInputMessage() with multiple sentence input', () => { + it('Test : _getSplitMessage() with multiple sentence input', () => { let a = new Command({command : 'wg website desc '}); - let b = a._getInputMessage(`wg website desc "Hello everynyan, how are you" "I am fine thank you"`); + let b = a._getSplitMessage(`wg website desc "Hello everynyan, how are you" "I am fine thank you"`); expect(b[0]).to.equal('wg'); expect(b[1]).to.equal('website'); expect(b[2]).to.equal('desc'); expect(b[3]).to.equal('Hello everynyan, how are you'); expect(b[4]).to.equal('I am fine thank you'); }) - it('Test : _getInputMessage() with single word', () => { + it('Test : _getSplitMessage() with single word', () => { let a = new Command({command : 'wg website desc '}); - let b = a._getInputMessage(`wg website desc Hello`); + let b = a._getSplitMessage(`wg website desc Hello`); expect(b[0]).to.equal('wg'); expect(b[1]).to.equal('website'); expect(b[2]).to.equal('desc'); From e4df23516f058e7b7ebf33ca6a5b66c54c0795ea Mon Sep 17 00:00:00 2001 From: Mohammed Ashab Uddin Date: Thu, 6 Aug 2020 13:05:02 +0400 Subject: [PATCH 2/7] getInput needs await and message as parameter --- whatsapp-web.js/src/userInteraction/messages.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/whatsapp-web.js/src/userInteraction/messages.js b/whatsapp-web.js/src/userInteraction/messages.js index b54d477..b7d76df 100644 --- a/whatsapp-web.js/src/userInteraction/messages.js +++ b/whatsapp-web.js/src/userInteraction/messages.js @@ -188,7 +188,6 @@ const commands = [ ]; - module.exports= onMessage = async (message, client) => { let command = null; @@ -213,13 +212,12 @@ module.exports= onMessage = async (message, client) => { let input = {}; //check if the command requires input if(command.requireInput){ - input = command.getInput(message.body); + input = await command.getInput(message); } //determine the user logic.setUser(message.id.remote); //determine the input logic.setInput(input); - //call callback function in the command //await is used, so that if a command is an async function //the program will wait until it is finished From 574b568f9411d1cb4b9b18b3e1e5c836982eddf1 Mon Sep 17 00:00:00 2001 From: Mohammed Ashab Uddin Date: Thu, 6 Aug 2020 13:05:43 +0400 Subject: [PATCH 3/7] added base64 decoding method --- whatsapp-web.js/src/businessLogic/logic.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/whatsapp-web.js/src/businessLogic/logic.js b/whatsapp-web.js/src/businessLogic/logic.js index e7015a0..ccdf346 100644 --- a/whatsapp-web.js/src/businessLogic/logic.js +++ b/whatsapp-web.js/src/businessLogic/logic.js @@ -2,6 +2,7 @@ const { Website } = require("../models/website"); const { data } = require("../models/data"); const { Product } = require('../models/product'); const { User } = require('../models/user'); +const fs = require('fs'); const request = require('request'); /** @@ -24,6 +25,7 @@ const addProduct = (id) => { // Add a product to the selected website. user.getSelectedWebsite().addProduct(product); } + const check = ({checkFunction, callback}) => { let checkValue = checkFunction(); @@ -357,7 +359,7 @@ module.exports.onSetFirstName = () => callback : () => { user.getSelectedWebsite().firstName = input['firstName']; - + return [`First name has been set to ${user.getSelectedWebsite().firstName}`]; } }); @@ -535,3 +537,12 @@ module.exports.onDeployWebsite = () => { } }); } + + +const base64_decode = async (base64str, file) => { + + var bitmap = await Buffer.from(base64str, 'base64'); + await fs.writeFileSync(file, bitmap); + console.log('****** File created from base64 encoded string ******'); + +} From 117e0949d679bd5efe6d112088bef24af6ed23ea Mon Sep 17 00:00:00 2001 From: Mohammed Ashab Uddin Date: Thu, 6 Aug 2020 14:07:28 +0400 Subject: [PATCH 4/7] added common-tags --- whatsapp-web.js/package-lock.json | 5 +++++ whatsapp-web.js/package.json | 1 + 2 files changed, 6 insertions(+) diff --git a/whatsapp-web.js/package-lock.json b/whatsapp-web.js/package-lock.json index d73b936..e9cedbe 100644 --- a/whatsapp-web.js/package-lock.json +++ b/whatsapp-web.js/package-lock.json @@ -334,6 +334,11 @@ "delayed-stream": "~1.0.0" } }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", diff --git a/whatsapp-web.js/package.json b/whatsapp-web.js/package.json index b5f9c49..bf48a35 100644 --- a/whatsapp-web.js/package.json +++ b/whatsapp-web.js/package.json @@ -11,6 +11,7 @@ "author": "", "license": "ISC", "dependencies": { + "common-tags": "^1.8.0", "request": "^2.88.2", "whatsapp-web.js": "^1.7.0" }, From 54d3e68d873431326aee4181b7b3ef24a5b785a6 Mon Sep 17 00:00:00 2001 From: Mohammed Ashab Uddin Date: Thu, 6 Aug 2020 14:07:52 +0400 Subject: [PATCH 5/7] modified to use images --- whatsapp-web.js/src/businessLogic/logic.js | 116 ++++++++++++------ whatsapp-web.js/src/models/commands.js | 2 +- .../src/userInteraction/messages.js | 12 +- 3 files changed, 89 insertions(+), 41 deletions(-) diff --git a/whatsapp-web.js/src/businessLogic/logic.js b/whatsapp-web.js/src/businessLogic/logic.js index ccdf346..ad1779d 100644 --- a/whatsapp-web.js/src/businessLogic/logic.js +++ b/whatsapp-web.js/src/businessLogic/logic.js @@ -4,6 +4,7 @@ const { Product } = require('../models/product'); const { User } = require('../models/user'); const fs = require('fs'); const request = require('request'); +const {stripIndents} = require('common-tags'); /** * user to be sent the message to @@ -26,6 +27,7 @@ const addProduct = (id) => { user.getSelectedWebsite().addProduct(product); } + const check = ({checkFunction, callback}) => { let checkValue = checkFunction(); @@ -38,15 +40,25 @@ const check = ({checkFunction, callback}) => { return checkValue; } +const checkMediaExist = () => { + if(input['media'] == undefined){ + return [ + `A media should be attached with the message`, + `Please attach an image or file with the caption being the command` + ]; + } + + return ''; +} + const checkSelectedWebsiteExist= () => { if(user.getSelectedWebsite() == null) { return [ - `A website should be selected or created - To create website, please use the following command : `, + `A website should be selected or created `, + `To create website, please use the following command : `, `*wg create *`, - ]; } @@ -99,14 +111,15 @@ module.exports.onCreateProduct = () => { //mesage to be sent to the user let message = [ `The product has been created with the id : ${selectedId}` , - ` + //use stripIndents to strip the indentation + stripIndents` This product has been selected. Now you can make change to the product with the following commands : 1. wg product info 2. wg product name 3. wg product cost 4. wg product desc - 5. wg product image + 5. wg product image *with an image attached* ` ]; @@ -154,14 +167,14 @@ module.exports.onSelectProduct = () => { return [ `The product has been selected with the id : ${user.getSelectedWebsite().getSelectedProduct().id}` , - ` + stripIndents` This product has been selected. Now you can make change to the product with the following commands : 1. wg product info 2. wg product name 3. wg product cost 4. wg product desc - 5. wg product image + 5. wg product image *with an image attached* ` ]; @@ -180,8 +193,9 @@ module.exports.onGetAllProducts = () => { for(let p of user.getSelectedWebsite().getAllProduct()) { - let m = 'Product id: ' + p.id + '\nProduct Name : ' + p.name + '\nProduct description : '+ p.desc + '\nProduct Cost: ' + p.cost + '\nProduct Image : '+ p.image; + let m = 'Product id: ' + p.id + '\nProduct Name : ' + p.name + '\nProduct description : '+ p.desc + '\nProduct Cost: ' + p.cost + '\nProduct Image : '; message.push(m); + message.push(p.image); } return message; @@ -197,13 +211,13 @@ module.exports.onGetProductInfo = () => { callback : () => { let selected_product = user.getSelectedWebsite().getSelectedProduct(); return [ - ` + stripIndents` Product id: ${selected_product.id} Product Name : ${selected_product.name} Product description : ${selected_product.desc } Product Cost: ${selected_product.cost} - Product Image : ${selected_product.image} - ` + Product Image :`, + selected_product.image ]; } }); @@ -246,7 +260,7 @@ module.exports.onSetProductDesc = () => { let selected_product = user.getSelectedWebsite().getSelectedProduct(); selected_product.setDesc(input['product-desc']); let message = [ - 'The product cost has been set to '+ selected_product.desc + 'The product desc has been set to '+ selected_product.desc ]; return message; } @@ -258,12 +272,21 @@ module.exports.onSetProductImage = () => { return check({ checkFunction : checkSelectedProductExist, callback : () => { - let selected_product = user.getSelectedWebsite().getSelectedProduct(); - selected_product.setImage(input['product-image']); - let message = [ - 'The product cost has been set to '+ selected_product.image - ]; - return message; + + return check({ + checkFunction : checkMediaExist, + callback : () => { + + let selected_product = user.getSelectedWebsite().getSelectedProduct(); + selected_product.setImage(input['media']); + let message = [ + 'The product image has been set to the following image', + selected_product.image + ]; + return message; + + } + }); } }); } @@ -308,16 +331,17 @@ module.exports.onCreateWebsite = () => user.addWebsite(new Website(input['company_name'])); return [ - `welcome to building your own website!`, - `We would like you add the following details:`, - `wg website firstname **`, - `wg website lastname **`, - `wg website companyname **`, - `wg website logo **`, - `wg website banner **`, - `wg website description **`, - `wg website email **`, - `For adding information use *wg website *`, + stripIndents` + welcome to building your own website! + We would like you add the following details: + wg website firstname ** + wg website lastname ** + wg website companyname ** + wg website logo ** + wg website banner ** + wg website description ** + wg website email ** + For adding information use *wg website *` ]; } @@ -332,7 +356,7 @@ module.exports.onGetInfo = () => { let website = user.getSelectedWebsite(); return [ - ` + stripIndents` First Name : ${website.firstName} Last Name : ${website.lastName} Company Name (id) : ${website.companyName } @@ -394,12 +418,24 @@ module.exports.onSetLastName = () => module.exports.onSetLogo = () => { - check({ + return check({ + //check if website exist checkFunction : checkSelectedWebsiteExist, callback: () => { - user.getSelectedWebsite().logoUrl = input['url']; - - return [`Logo has been set to ${user.getSelectedWebsite().logoUrl}`]; + + return check({ + //check if media exist + checkFunction: checkMediaExist, + callback : () => { + user.getSelectedWebsite().logoUrl = input['media']; + + return [ + `Logo has been set to the following logo`, + user.getSelectedWebsite().logoUrl + ]; + } + }); + } }) @@ -414,11 +450,21 @@ module.exports.onSetLogo = () => module.exports.onSetBanner = () => { return check({ + //check if website exist checkFunction : checkSelectedWebsiteExist, callback : () => { + //check if media exist + return check({ + checkFunction : checkMediaExist, + callback :() => { - user.getSelectedWebsite().bannerUrl = input['bannerURL']; - return [`Banner has been set to ${user.getSelectedWebsite().bannerUrl}`]; + user.getSelectedWebsite().bannerUrl = input['media']; + return [ + `Banner has been set to the following banner`, + user.getSelectedWebsite().bannerUrl + ]; + } + }) } }); } diff --git a/whatsapp-web.js/src/models/commands.js b/whatsapp-web.js/src/models/commands.js index 59711e5..6e98c41 100644 --- a/whatsapp-web.js/src/models/commands.js +++ b/whatsapp-web.js/src/models/commands.js @@ -145,7 +145,7 @@ class Command{ let input = {}; if(message.hasMedia){ let media = await message.downloadMedia(); - input['media'] = media.data; + input['media'] = media; } return input; } diff --git a/whatsapp-web.js/src/userInteraction/messages.js b/whatsapp-web.js/src/userInteraction/messages.js index b7d76df..5e123cc 100644 --- a/whatsapp-web.js/src/userInteraction/messages.js +++ b/whatsapp-web.js/src/userInteraction/messages.js @@ -87,11 +87,11 @@ const commands = [ //inputs the logo of the company to website using url of logo new Command({ //User command + command: 'wg website logo', - command: 'wg website logo ', - //function to be executed - callback : logic.onSetLogo + callback : logic.onSetLogo, + requireMedia : true }), @@ -180,10 +180,12 @@ const commands = [ }), new Command({ //User command - command: 'wg product image ', + command: 'wg product image', //function to be executed - callback : logic.onSetProductImage + callback : logic.onSetProductImage, + + requireMedia: true }), ]; From c5329eda936b6fa5364ab7cba30768bc04493eaf Mon Sep 17 00:00:00 2001 From: Mohammed Ashab Uddin Date: Thu, 6 Aug 2020 14:09:51 +0400 Subject: [PATCH 6/7] modified onGetInfo to display images --- whatsapp-web.js/src/businessLogic/logic.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/whatsapp-web.js/src/businessLogic/logic.js b/whatsapp-web.js/src/businessLogic/logic.js index ad1779d..853d66b 100644 --- a/whatsapp-web.js/src/businessLogic/logic.js +++ b/whatsapp-web.js/src/businessLogic/logic.js @@ -360,11 +360,12 @@ module.exports.onGetInfo = () => { First Name : ${website.firstName} Last Name : ${website.lastName} Company Name (id) : ${website.companyName } - Logo : ${website.logo} - Banner : ${website.bannerUrl} Description : ${website.desc} Email : ${website.email} - ` + Banner :`, + website.bannerUrl, + `Logo :`, + website.logo ]; } }); From 65c76ac732893da251847aa1b30961fe26d7066b Mon Sep 17 00:00:00 2001 From: Mohammed Ashab Uddin Date: Fri, 7 Aug 2020 09:15:21 +0400 Subject: [PATCH 7/7] able to save images --- whatsapp-web.js/src/businessLogic/logic.js | 51 +++++++++++++++------- whatsapp-web.js/src/models/product.js | 1 + whatsapp-web.js/src/models/website.js | 23 ++++++++++ 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/whatsapp-web.js/src/businessLogic/logic.js b/whatsapp-web.js/src/businessLogic/logic.js index 853d66b..5a6ba85 100644 --- a/whatsapp-web.js/src/businessLogic/logic.js +++ b/whatsapp-web.js/src/businessLogic/logic.js @@ -18,6 +18,22 @@ let user = null; */ let input = null; + +const base64_decode = async (base64str, file) => { + + var bitmap = await Buffer.from(base64str, 'base64'); + await fs.writeFileSync(file, bitmap); + console.log('****** File created from base64 encoded string ******'); + +} + + +const saveImage = async (messageMedia, fileName) => { + let file = `../website-generator/public/images/${fileName}.jpg`; + await base64_decode(messageMedia.data, file); + return file; +} + const addProduct = (id) => { // Create a product and select it. @@ -275,14 +291,20 @@ module.exports.onSetProductImage = () => { return check({ checkFunction : checkMediaExist, - callback : () => { + callback : async () => { let selected_product = user.getSelectedWebsite().getSelectedProduct(); selected_product.setImage(input['media']); + //filename to be set + let filename = `${user.id.slice(3,10)}${user.getSelectedWebsite().companyName}${selected_product.id}`; + //url for the image that are saved + selected_product.imageUrl = await saveImage(input['media'], filename); + let message = [ 'The product image has been set to the following image', selected_product.image ]; + return message; } @@ -363,7 +385,7 @@ module.exports.onGetInfo = () => { Description : ${website.desc} Email : ${website.email} Banner :`, - website.bannerUrl, + website.banner, `Logo :`, website.logo ]; @@ -427,12 +449,14 @@ module.exports.onSetLogo = () => return check({ //check if media exist checkFunction: checkMediaExist, - callback : () => { - user.getSelectedWebsite().logoUrl = input['media']; - + callback : async () => { + + user.getSelectedWebsite().logo = input['media']; + user.getSelectedWebsite().logoUrl = await saveImage(input['media'], `${user.id.slice(3,10)}${user.getSelectedWebsite().companyName}logo`); + return [ `Logo has been set to the following logo`, - user.getSelectedWebsite().logoUrl + user.getSelectedWebsite().logo ]; } }); @@ -457,12 +481,14 @@ module.exports.onSetBanner = () => //check if media exist return check({ checkFunction : checkMediaExist, - callback :() => { + callback : async () => { - user.getSelectedWebsite().bannerUrl = input['media']; + user.getSelectedWebsite().banner = input['media']; + user.getSelectedWebsite().bannerUrl = await saveImage(input['media'], `${user.id.slice(3,10)}${user.getSelectedWebsite().companyName}banner`); + return [ `Banner has been set to the following banner`, - user.getSelectedWebsite().bannerUrl + user.getSelectedWebsite().banner ]; } }) @@ -586,10 +612,3 @@ module.exports.onDeployWebsite = () => { } -const base64_decode = async (base64str, file) => { - - var bitmap = await Buffer.from(base64str, 'base64'); - await fs.writeFileSync(file, bitmap); - console.log('****** File created from base64 encoded string ******'); - -} diff --git a/whatsapp-web.js/src/models/product.js b/whatsapp-web.js/src/models/product.js index ebbefca..b139390 100644 --- a/whatsapp-web.js/src/models/product.js +++ b/whatsapp-web.js/src/models/product.js @@ -7,6 +7,7 @@ class Product { this.desc = desc; this.cost = cost; this.image = image; + this.imageUrl = ''; } /** diff --git a/whatsapp-web.js/src/models/website.js b/whatsapp-web.js/src/models/website.js index a19ca55..bf525a2 100644 --- a/whatsapp-web.js/src/models/website.js +++ b/whatsapp-web.js/src/models/website.js @@ -10,6 +10,8 @@ class Website { this.firstName = ''; this.lastName = ''; this.companyName = companyName; + this.logo = ''; + this.banner = ''; this.logoUrl = ''; this.bannerUrl = ''; this.desc = ''; @@ -66,6 +68,27 @@ class Website { return this.getProduct(this.products.selectedData); } + toJson(){ + let j = {}; + j["firstName"] = this.firstName; + j["lastName"] = this.lastName; + j["companyName"] = this.companyName; + j["logoUrl"] = this.logoUrl; + j["bannerUrl"] = this.bannerUrl; + j["email"] = this.email; + j["description"] = this.desc; + + let csv = ''; + for (let prod of this.products.getAllData().values()) + { + let m = [prod.id, prod.name, prod.desc, prod.cost, prod.imageUrl].join(','); + csv += `${m}\n`; + } + j['csv'] = csv; + + return JSON.stringify(j); + } + }