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" }, diff --git a/whatsapp-web.js/src/businessLogic/logic.js b/whatsapp-web.js/src/businessLogic/logic.js index e7015a0..5a6ba85 100644 --- a/whatsapp-web.js/src/businessLogic/logic.js +++ b/whatsapp-web.js/src/businessLogic/logic.js @@ -2,7 +2,9 @@ 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'); +const {stripIndents} = require('common-tags'); /** * user to be sent the message to @@ -16,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. @@ -24,6 +42,8 @@ const addProduct = (id) => { // Add a product to the selected website. user.getSelectedWebsite().addProduct(product); } + + const check = ({checkFunction, callback}) => { let checkValue = checkFunction(); @@ -36,15 +56,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 *`, - ]; } @@ -97,14 +127,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* ` ]; @@ -152,14 +183,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* ` ]; @@ -178,8 +209,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; @@ -195,13 +227,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 ]; } }); @@ -244,7 +276,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; } @@ -256,12 +288,27 @@ 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 : 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; + + } + }); } }); } @@ -306,16 +353,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 *` ]; } @@ -330,15 +378,16 @@ module.exports.onGetInfo = () => { let website = user.getSelectedWebsite(); return [ - ` + stripIndents` 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.banner, + `Logo :`, + website.logo ]; } }); @@ -357,7 +406,7 @@ module.exports.onSetFirstName = () => callback : () => { user.getSelectedWebsite().firstName = input['firstName']; - + return [`First name has been set to ${user.getSelectedWebsite().firstName}`]; } }); @@ -392,12 +441,26 @@ 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 : 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().logo + ]; + } + }); + } }) @@ -412,11 +475,23 @@ module.exports.onSetLogo = () => module.exports.onSetBanner = () => { return check({ + //check if website exist checkFunction : checkSelectedWebsiteExist, callback : () => { + //check if media exist + return check({ + checkFunction : checkMediaExist, + callback : async () => { - user.getSelectedWebsite().bannerUrl = input['bannerURL']; - return [`Banner has been set to ${user.getSelectedWebsite().bannerUrl}`]; + 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().banner + ]; + } + }) } }); } @@ -535,3 +610,5 @@ module.exports.onDeployWebsite = () => { } }); } + + diff --git a/whatsapp-web.js/src/models/commands.js b/whatsapp-web.js/src/models/commands.js index 5b1a07f..6e98c41 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; + } + return input; + } + } module.exports.Command = Command; 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); + } + } diff --git a/whatsapp-web.js/src/userInteraction/messages.js b/whatsapp-web.js/src/userInteraction/messages.js index b54d477..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,15 +180,16 @@ 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 }), ]; - module.exports= onMessage = async (message, client) => { let command = null; @@ -213,13 +214,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 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');