From 17da874c533cd34fd78e4720abac09ffc120d642 Mon Sep 17 00:00:00 2001 From: Gitbot X <69758468+gitbot-x@users.noreply.github.com> Date: Fri, 19 Apr 2024 10:25:56 +0300 Subject: [PATCH 1/9] Upon this digital stage, doth bestow the gift of automated publication through npm, thus granting unto contributors a seamless conduit, wherein their offerings may flow as a river into the vast ocean of creation. --- .github/workflows/npm-publish.yml | 60 ++++++++++++++++--------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index e8203db..c681144 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -1,33 +1,37 @@ -# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created -# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages - -name: Node.js Package +name: Publish to NPM on: - release: - types: [created] + push: + branches: + - main jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 16 - - run: npm ci - - run: npm test + test: + runs-on: ubuntu-latest + environment: Staging Environment + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 20 + - run: npm i + - run: npm test + env: + accessToken: ${{secrets.accessToken}} + graphAPIVersion: ${{secrets.graphAPIVersion}} + senderPhoneNumberId: ${{secrets.senderPhoneNumberId}} + WABA_ID: ${{secrets.WABA_ID}} - publish-npm: - needs: build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 16 - registry-url: https://registry.npmjs.org/ - - run: npm ci - - run: npm publish - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + publish-npm: + needs: test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 20 + registry-url: https://registry.npmjs.org/ + - run: npm i + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN_IN_GITHUB_ACTIONS}} \ No newline at end of file From edd22990cbde4aa0696735a165cf6315e83d6884 Mon Sep 17 00:00:00 2001 From: Gitbot X <69758468+gitbot-x@users.noreply.github.com> Date: Fri, 19 Apr 2024 10:27:57 +0300 Subject: [PATCH 2/9] test script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0bb66f5..4b3e508 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "scripts": { "prettier": "prettier --ignore-path .prettierignore --config prettier.config.js --write .", "quickpush": "cls && git status && git add * && git commit * -m \"Updated Code\" && git push", - "test": "echo \"Error: no test specified\" && exit 0", + "test": "PACKAGE_VERSION=$npm_package_version echo \"Error: no test specified\" && exit 0", "npmpublish": "npm run prettier && np" }, "dependencies": { From 33b169629491b0eee3291c870305a33e3b4caf2f Mon Sep 17 00:00:00 2001 From: Gitbot X <69758468+gitbot-x@users.noreply.github.com> Date: Fri, 19 Apr 2024 10:29:08 +0300 Subject: [PATCH 3/9] dep update --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 4b3e508..e11d780 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "npmpublish": "npm run prettier && np" }, "dependencies": { + "request": "^2.88.2", "signale": "^1.4.0", "unirest": "^0.6.0" }, From 2e7350a08ec894bcd4d227a25d55c3a9b84e708f Mon Sep 17 00:00:00 2001 From: Gitbot X <69758468+gitbot-x@users.noreply.github.com> Date: Fri, 19 Apr 2024 10:29:42 +0300 Subject: [PATCH 4/9] updated parser --- msg_parser.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/msg_parser.js b/msg_parser.js index 83fe2c4..cffac34 100644 --- a/msg_parser.js +++ b/msg_parser.js @@ -88,6 +88,8 @@ module.exports = ({ requestBody, currentWABA_ID }) => { msgType = 'ad_message'; } else if (message.type === 'text') { msgType = 'text_message'; + } else if (message.type === 'audio') { + msgType = 'audio_message'; } else if (message.type === 'sticker') { msgType = 'sticker_message'; } else if (message.type === 'image') { From cf8d861911f503de7cbbfe5dd7568651747069e2 Mon Sep 17 00:00:00 2001 From: Gitbot X <69758468+gitbot-x@users.noreply.github.com> Date: Fri, 19 Apr 2024 10:30:11 +0300 Subject: [PATCH 5/9] uploader bug --- index.js | 192 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 152 insertions(+), 40 deletions(-) diff --git a/index.js b/index.js index 217cc9d..31b8a5f 100644 --- a/index.js +++ b/index.js @@ -2,7 +2,19 @@ const unirest = require('unirest'); const signale = require('signale'); const fs = require('fs'); +const request = require('request'); const messageParser = require('./msg_parser.js'); +const { Readable } = require('stream'); + +// check if file exists +const fileExists = ({ path }) => { + try { + fs.accessSync(path, fs.constants.F_OK); + return true; + } catch (err) { + return false; + } +}; class WhatsappCloud { constructor({ @@ -146,33 +158,6 @@ class WhatsappCloud { } }; - this._uploadMedia = async ({ file_path, file_name }) => { - return new Promise((resolve, reject) => { - const mediaFile = fs.createReadStream(file_path); - // type = type || 'image'; - unirest( - 'POST', - `https://graph.facebook.com/${this.graphAPIVersion}/${this.senderPhoneNumberId}/media` - ) - .headers({ - Authorization: `Bearer ${this.accessToken}`, - }) - .field('messaging_product', 'whatsapp') - .attach('file', mediaFile) - .end((res) => { - if (res.error) { - reject(res.error); - } else { - let response = JSON.parse(res.raw_body); - resolve({ - status: 'success', - media_id: response.id, - file_name: file_name || null, - }); - } - }); - }); - }; this._retrieveMediaUrl = async ({ media_id }) => { const response = await this._fetchAssistant({ baseUrl: `https://graph.facebook.com/${this.graphAPIVersion}`, @@ -512,17 +497,42 @@ class WhatsappCloud { return response; } - async sendImage({ recipientPhone, caption, file_path, file_name, url }) { + async sendImage({ + recipientPhone, + caption, + file_path, + file_name, + url, + media_id, + mime_type, + }) { this._mustHaverecipientPhone(recipientPhone); - if (file_path && url) { + const hasFileAndUrl = file_path && url; + const hasMediaIdAndFile = media_id && file_path; + const hasMediaIdAndUrl = media_id && url; + const lacksAll = !file_path && !url && !media_id; + + if (hasFileAndUrl) { throw new Error( 'You can only send an image in your "file_path" or an image in a publicly available "url". Provide either "file_path" or "url".' ); } - if (!file_path && !url) { + if (hasMediaIdAndFile) { + throw new Error( + 'You can only send an image using a media_id or a file_path. Provide either "media_id" or "file_path".' + ); + } + + if (hasMediaIdAndUrl) { throw new Error( - 'You must send an image in your "file_path" or an image in a publicly available "url". Provide either "file_path" or "url".' + 'You can only send an image using a media_id or a url. Provide either "media_id" or "url".' + ); + } + + if (lacksAll) { + throw new Error( + 'You must have either an image in your "file_path" or an image in a publicly available "url", or a previously uploaded "media_id". Provide either "file_path" or "url" or "media_id".' ); } @@ -536,12 +546,15 @@ class WhatsappCloud { }, }; - if (file_path) { - let uploadedFile = await this._uploadMedia({ + if (media_id) { + body['image']['id'] = media_id; + } else if (file_path) { + let uploadedFile = await this.preUploadMedia({ file_path, file_name, + mime_type, }); - body['image']['id'] = uploadedFile.media_id; + body['image']['id'] = Number(uploadedFile.media_id); } else { body['image']['link'] = url; } @@ -557,7 +570,15 @@ class WhatsappCloud { body, }; } - async sendVideo({ recipientPhone, caption, file_path, file_name, url }) { + + async sendVideo({ + recipientPhone, + caption, + file_path, + file_name, + url, + mime_type, + }) { this._mustHaverecipientPhone(recipientPhone); if (file_path && url) { throw new Error( @@ -581,9 +602,10 @@ class WhatsappCloud { }, }; if (file_path) { - let uploadedFile = await this._uploadMedia({ + let uploadedFile = await this.preUploadMedia({ file_path, file_name, + mime_type, }); body['video']['id'] = uploadedFile.media_id; } else { @@ -602,7 +624,14 @@ class WhatsappCloud { }; } - async sendAudio({ recipientPhone, caption, file_path, file_name, url }) { + async sendAudio({ + recipientPhone, + caption, + file_path, + file_name, + url, + mime_type, + }) { this._mustHaverecipientPhone(recipientPhone); if (file_path && url) { throw new Error( @@ -624,9 +653,10 @@ class WhatsappCloud { audio: {}, }; if (file_path) { - let uploadedFile = await this._uploadMedia({ + let uploadedFile = await this.preUploadMedia({ file_path, file_name, + mime_type, }); body['audio']['id'] = uploadedFile.media_id; } else { @@ -645,7 +675,7 @@ class WhatsappCloud { }; } - async sendDocument({ recipientPhone, caption, file_path, url }) { + async sendDocument({ recipientPhone, caption, file_path, url, mime_type }) { this._mustHaverecipientPhone(recipientPhone); if (file_path && url) { throw new Error( @@ -674,9 +704,10 @@ class WhatsappCloud { }; if (file_path) { - let uploadedFile = await this._uploadMedia({ + let uploadedFile = await this.preUploadMedia({ file_path, file_name: caption, + mime_type, }); body['document']['id'] = uploadedFile.media_id; body['document']['filename'] = uploadedFile.file_name || ''; @@ -921,6 +952,87 @@ class WhatsappCloud { async getUserStatusPicture({ recipientPhone }) {} + async preUploadMedia({ file_path, file_name, file_buffer, mime_type }) { + return new Promise((resolve, reject) => { + let fileStream; + + if (!file_path && !file_buffer) { + return reject({ + status: 'failed', + error: 'You must provide either a file_path or a file_buffer.', + }); + } + + if (file_path) { + if (!fileExists({ path: file_path })) { + return reject({ + status: 'failed', + error: 'The file_path does not exist.', + }); + } else { + fileStream = fs.createReadStream(file_path); + } + } + + if (file_buffer) { + if (!Buffer.isBuffer(file_buffer)) { + return reject({ + status: 'failed', + error: 'The file_buffer is not a buffer.', + }); + } else { + // Convert buffer to a readable stream + fileStream = new Readable(); + fileStream.push(file_buffer); + fileStream.push(null); // Signal the end of the stream + } + } + + if (!mime_type) { + throw new Error('You must provide a "mime_type".'); + } + + const url = `https://graph.facebook.com/${this.graphAPIVersion}/${this.senderPhoneNumberId}/media`; + + const options = { + method: 'POST', + url, + headers: { + Authorization: `Bearer ${this.accessToken}`, + }, + formData: { + messaging_product: 'whatsapp', + type: mime_type, + file: { + value: fileStream, + options: { + filename: file_name, + contentType: null, + }, + }, + }, + }; + + request(options, function (error, response) { + if (error) { + reject({ + status: 'failed', + error, + }); + } else { + const data = JSON.parse(response.body); + const media_id = data.id; + + resolve({ + status: 'success', + media_id, + file_name: file_name || null, + }); + } + }); + }); + } + parseMessage(requestBody) { return messageParser({ requestBody, currentWABA_ID: this.WABA_ID }); } From 1f1b6ae86006c25d8ae0a7ae508bddff1f8d4340 Mon Sep 17 00:00:00 2001 From: Gitbot X <69758468+gitbot-x@users.noreply.github.com> Date: Fri, 19 Apr 2024 10:45:26 +0300 Subject: [PATCH 6/9] Wherefore, with nimble quill, this minuscule fault hath been rectified, a lone erratum amid the vast expanse of the written word. In this delicate dance of ink upon parchment, even the slightest misstep may disrupt the harmony of meaning. Thus, with diligent care, doth this correction emerge, a testament to the ceaseless pursuit of perfection amidst the tumult of human endeavor. --- .github/workflows/npm-publish.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index c681144..3f58ffe 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -17,9 +17,9 @@ jobs: - run: npm i - run: npm test env: - accessToken: ${{secrets.accessToken}} - graphAPIVersion: ${{secrets.graphAPIVersion}} - senderPhoneNumberId: ${{secrets.senderPhoneNumberId}} + accessToken: ${{secrets.ACCESSTOKEN}} + graphAPIVersion: ${{secrets.GRAPHAPIVERSION}} + senderPhoneNumberId: ${{secrets.SENDERPHONENUMBERID}} WABA_ID: ${{secrets.WABA_ID}} publish-npm: From 30c987cf15609eb6278cd20a1a99e7da43134014 Mon Sep 17 00:00:00 2001 From: Gitbot X <69758468+gitbot-x@users.noreply.github.com> Date: Fri, 19 Apr 2024 10:49:06 +0300 Subject: [PATCH 7/9] Thus hath the version of the node descended, from the lofty 20 to the humbler 16, echoing the cyclical nature of existence, wherein the heights of ambition yield to the wisdom of moderation --- .github/workflows/npm-publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 3f58ffe..b96a2b9 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 16 - run: npm i - run: npm test env: @@ -29,7 +29,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 16 registry-url: https://registry.npmjs.org/ - run: npm i - run: npm publish From 9721875866fc8b7aa483dbf83be33b67c355fa69 Mon Sep 17 00:00:00 2001 From: Gitbot X <69758468+gitbot-x@users.noreply.github.com> Date: Fri, 19 Apr 2024 10:51:06 +0300 Subject: [PATCH 8/9] Unto us, a child is born v1.0.15 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e11d780..e9e0cae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "whatsappcloudapi_wrapper", - "version": "1.0.14", + "version": "1.0.15", "description": "Tired of doing things wrong? This package provides you with an easy way to get started and start building on the Whatsapp Cloud API. This is an unofficial wrapper for the Whatsapp Cloud API.", "main": "index.js", "author": "Daggie Blanqx", From 9c526a90a5144e3fdcd1e31cbfdcbf1615e72f52 Mon Sep 17 00:00:00 2001 From: Gitbot X <69758468+gitbot-x@users.noreply.github.com> Date: Fri, 19 Apr 2024 10:51:58 +0300 Subject: [PATCH 9/9] Behold, the ascent to Node version twenty, a venture profound, from the realm of sixteen. Thus, in the ever-unfolding tapestry of code, doth progress march, each iteration a testament to the ceaseless quest for enlightenment. --- .github/workflows/npm-publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index b96a2b9..3f58ffe 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 20 - run: npm i - run: npm test env: @@ -29,7 +29,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 20 registry-url: https://registry.npmjs.org/ - run: npm i - run: npm publish