From d9946926fa31b995b231d952190f7731936382d9 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Thu, 21 Jun 2018 08:29:35 +0200 Subject: [PATCH 01/10] prototype Zoho proxy --- package.json | 4 +++- webtask-zoho.js | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 webtask-zoho.js diff --git a/package.json b/package.json index 09a4075..04f03da 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,13 @@ "version": "0.1.0", "private": true, "scripts": { - "start": "wt serve webtask-medium.js", + "start": "wt serve webtask-zoho.js", "test": "eslint ./{src,public}/**/*.js" }, "dependencies": { + "cors": "^2.8.4", "express": "^4.16.3", + "http-proxy-middleware": "^0.18.0", "request": "^2.85.0", "webtask-tools": "^3.2.0" }, diff --git a/webtask-zoho.js b/webtask-zoho.js new file mode 100644 index 0000000..da45568 --- /dev/null +++ b/webtask-zoho.js @@ -0,0 +1,21 @@ +const express = require('express') +const Webtask = require('webtask-tools') +const cors = require('cors') +const proxy = require('http-proxy-middleware') + +const server = express() + +const config = { + target: 'https://www.zohoapis.com/crm/v2/', + changeOrigin: true, + headers: { + Authorization: 'Zoho-oauthtoken hello' + } +} + +server.use(cors()) +server.use('*', proxy(config)) + +server.listen(4430) + +module.exports = Webtask.fromExpress(server) From e0ddc2f3cf3db8c4a052ec7e27995a6c066ef89a Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Thu, 21 Jun 2018 13:11:26 +0200 Subject: [PATCH 02/10] handle CRM & Campaigns API --- webtask-zoho.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/webtask-zoho.js b/webtask-zoho.js index da45568..ce342b7 100644 --- a/webtask-zoho.js +++ b/webtask-zoho.js @@ -5,16 +5,28 @@ const proxy = require('http-proxy-middleware') const server = express() -const config = { +const onProxyReq = function (proxyReq, req) { + proxyReq.setHeader('Authorization', `Zoho-oauthtoken ${req.webtaskContext.secrets.ZOHO_TOKEN}`) +} + +const configZohoCRM = { target: 'https://www.zohoapis.com/crm/v2/', + pathRewrite: { '^/zoho/crm/': '/' }, changeOrigin: true, - headers: { - Authorization: 'Zoho-oauthtoken hello' - } + onProxyReq +} + +const configZohoCampaigns = { + target: 'https://campaigns.zoho.com/api/', + pathRewrite: { '^/zoho/campaigns/': '/' }, + changeOrigin: true, + onProxyReq } server.use(cors()) -server.use('*', proxy(config)) +// server.use('*', proxy(config)) +server.use(proxy('/zoho/crm/**', configZohoCRM)) +server.use(proxy('/zoho/campaigns/**', configZohoCampaigns)) server.listen(4430) From 701561cbdbd1c0d1b004c103e2d65f226cc0715b Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Thu, 21 Jun 2018 15:28:57 +0200 Subject: [PATCH 03/10] split up auth mechanisms --- webtask-zoho.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/webtask-zoho.js b/webtask-zoho.js index ce342b7..40a70a9 100644 --- a/webtask-zoho.js +++ b/webtask-zoho.js @@ -5,22 +5,34 @@ const proxy = require('http-proxy-middleware') const server = express() -const onProxyReq = function (proxyReq, req) { - proxyReq.setHeader('Authorization', `Zoho-oauthtoken ${req.webtaskContext.secrets.ZOHO_TOKEN}`) +const onProxyReqZohoCRM = (proxyReq, req) => { + const { ZOHO_CRM_TOKEN } = req.webtaskContext.secrets + + proxyReq.setHeader('Authorization', `Zoho-oauthtoken ${ZOHO_CRM_TOKEN}`) +} + +const onProxyReqZohoCampaigns = (proxyReq, req) => { + const { ZOHO_CAMPAIGNS_TOKEN, ZOHO_CAMPAIGNS_LIST_KEY } = req.webtaskContext.secrets + + // + // Auth via query params + // https://www.zoho.com/campaigns/newhelp/api/contact-subscribe.html + // + proxyReq.path += `?authtoken=${ZOHO_CAMPAIGNS_TOKEN}&scope=CampaignsAPI&resfmt=JSON&listkey=${ZOHO_CAMPAIGNS_LIST_KEY}&contactinfo={First Name:mac,Last Name:Last Name,Contact Email:jai@zoho.com}` // eslint-disable-line max-len } const configZohoCRM = { target: 'https://www.zohoapis.com/crm/v2/', pathRewrite: { '^/zoho/crm/': '/' }, changeOrigin: true, - onProxyReq + onProxyReq: onProxyReqZohoCRM } const configZohoCampaigns = { target: 'https://campaigns.zoho.com/api/', pathRewrite: { '^/zoho/campaigns/': '/' }, changeOrigin: true, - onProxyReq + onProxyReq: onProxyReqZohoCampaigns } server.use(cors()) From 580471f0036ac1c9866003eabf3f5af7b384a6bd Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Thu, 21 Jun 2018 16:52:16 +0200 Subject: [PATCH 04/10] create endpoint for newsletter and handle subscription --- README.md | 26 ++++++++++++++++++++++- package.json | 1 + webtask-zoho.js | 55 ++++++++++++++++++++++++++++--------------------- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index dbaf1fe..ae447eb 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ ## Tasks +### Medium + **`webtask-medium.js`**: Generic task to fetch and reconstruct items from any medium publication. Requires the Medium username appended at the end of the url, e.g. locally: @@ -23,7 +25,7 @@ When published as a web task, append the taskname followed by the Medium usernam https://TASK_URL/TASK_NAME/MEDIUM_USERNAME ``` ---- +### YouTube **`webtask-youtube.js`**: Generic task to fetch and reconstruct items from any YouTube account. For now, only fetches a playlist. YouTube API key is provided via [secret environment variable](https://webtask.io/docs/issue_parameters) `YOUTUBE_API_KEY` setup in web editor of webtask.io @@ -39,6 +41,28 @@ Add the task name when published on webtask.io: https://TASK_URL/TASK_NAME/YOUTUBE_PLAYLIST_ID ``` +### Zoho + +**`webtask-zoho.js`**: Generic task to subscribe users into lists on Zoho Campaigns & Zoho CRM. Credentials are provided via [secret environment variables](https://webtask.io/docs/issue_parameters), setup in web editor of webtask.io. + +The user input data needs to be in `json` format like so: + +``` +{Contact Email:info@oceanprotocol.com} +``` + +To subscribe a user to the newsletter, construct your request url like so, e.g. locally: + +``` +http://localhost:8080/newsletter/DATA +``` + +Add the task name when published on webtask.io: + +``` +https://TASK_URL/TASK_NAME/newsletter/DATA +``` + ## Development ```bash diff --git a/package.json b/package.json index 04f03da..d5799c0 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "test": "eslint ./{src,public}/**/*.js" }, "dependencies": { + "body-parser": "^1.18.3", "cors": "^2.8.4", "express": "^4.16.3", "http-proxy-middleware": "^0.18.0", diff --git a/webtask-zoho.js b/webtask-zoho.js index 40a70a9..8d8c49f 100644 --- a/webtask-zoho.js +++ b/webtask-zoho.js @@ -2,44 +2,53 @@ const express = require('express') const Webtask = require('webtask-tools') const cors = require('cors') const proxy = require('http-proxy-middleware') +const bodyParser = require('body-parser') +const request = require('request') const server = express() +server.use(cors()) +server.listen(4430) +server.use(bodyParser.json()) + +const apiUrlZohoCampaigns = 'https://campaigns.zoho.com/api/' +const apiUrlZohoCRM = 'https://www.zohoapis.com/crm/v2/' + +// +// Subscribe to newsletter via Zoho Campaigns API +// https://www.zoho.com/campaigns/newhelp/api/contact-subscribe.html +// +server.get('/newsletter/:data', (req, res) => { + const { ZOHO_CAMPAIGNS_TOKEN, ZOHO_CAMPAIGNS_LIST_KEY } = req.webtaskContext.secrets + const { data } = req.params + + const options = { + url: `${apiUrlZohoCampaigns}json/listsubscribe?authtoken=${ZOHO_CAMPAIGNS_TOKEN}&scope=CampaignsAPI&resfmt=JSON&listkey=${ZOHO_CAMPAIGNS_LIST_KEY}&contactinfo=${data}` // eslint-disable-line max-len + } + + request(options, (error, response, body) => { // eslint-disable-line consistent-return + if (error) { + res.send(error) + } + + res.send(body) + res.sendStatus(200) + }) +}) + const onProxyReqZohoCRM = (proxyReq, req) => { const { ZOHO_CRM_TOKEN } = req.webtaskContext.secrets proxyReq.setHeader('Authorization', `Zoho-oauthtoken ${ZOHO_CRM_TOKEN}`) } -const onProxyReqZohoCampaigns = (proxyReq, req) => { - const { ZOHO_CAMPAIGNS_TOKEN, ZOHO_CAMPAIGNS_LIST_KEY } = req.webtaskContext.secrets - - // - // Auth via query params - // https://www.zoho.com/campaigns/newhelp/api/contact-subscribe.html - // - proxyReq.path += `?authtoken=${ZOHO_CAMPAIGNS_TOKEN}&scope=CampaignsAPI&resfmt=JSON&listkey=${ZOHO_CAMPAIGNS_LIST_KEY}&contactinfo={First Name:mac,Last Name:Last Name,Contact Email:jai@zoho.com}` // eslint-disable-line max-len -} - const configZohoCRM = { - target: 'https://www.zohoapis.com/crm/v2/', + target: apiUrlZohoCRM, pathRewrite: { '^/zoho/crm/': '/' }, changeOrigin: true, onProxyReq: onProxyReqZohoCRM } -const configZohoCampaigns = { - target: 'https://campaigns.zoho.com/api/', - pathRewrite: { '^/zoho/campaigns/': '/' }, - changeOrigin: true, - onProxyReq: onProxyReqZohoCampaigns -} - -server.use(cors()) -// server.use('*', proxy(config)) server.use(proxy('/zoho/crm/**', configZohoCRM)) -server.use(proxy('/zoho/campaigns/**', configZohoCampaigns)) - -server.listen(4430) module.exports = Webtask.fromExpress(server) From 230c8ccf73b562f5fe6344fbc1f09dc4e7724262 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Thu, 21 Jun 2018 17:54:41 +0200 Subject: [PATCH 05/10] prototype CRM endpoint --- .gitignore | 1 + package.json | 1 - webtask-zoho.js | 36 ++++++++++++++++++++++++------------ 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index f846c68..a4aee7e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules package-lock.json yarn.lock +.env diff --git a/package.json b/package.json index d5799c0..3ec5c61 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "body-parser": "^1.18.3", "cors": "^2.8.4", "express": "^4.16.3", - "http-proxy-middleware": "^0.18.0", "request": "^2.85.0", "webtask-tools": "^3.2.0" }, diff --git a/webtask-zoho.js b/webtask-zoho.js index 8d8c49f..e28767f 100644 --- a/webtask-zoho.js +++ b/webtask-zoho.js @@ -1,7 +1,6 @@ const express = require('express') const Webtask = require('webtask-tools') const cors = require('cors') -const proxy = require('http-proxy-middleware') const bodyParser = require('body-parser') const request = require('request') @@ -11,6 +10,9 @@ server.use(cors()) server.listen(4430) server.use(bodyParser.json()) +// +// Zoho API urls +// const apiUrlZohoCampaigns = 'https://campaigns.zoho.com/api/' const apiUrlZohoCRM = 'https://www.zohoapis.com/crm/v2/' @@ -26,7 +28,7 @@ server.get('/newsletter/:data', (req, res) => { url: `${apiUrlZohoCampaigns}json/listsubscribe?authtoken=${ZOHO_CAMPAIGNS_TOKEN}&scope=CampaignsAPI&resfmt=JSON&listkey=${ZOHO_CAMPAIGNS_LIST_KEY}&contactinfo=${data}` // eslint-disable-line max-len } - request(options, (error, response, body) => { // eslint-disable-line consistent-return + request(options, (error, response, body) => { if (error) { res.send(error) } @@ -36,19 +38,29 @@ server.get('/newsletter/:data', (req, res) => { }) }) -const onProxyReqZohoCRM = (proxyReq, req) => { +// +// Create a new lead via Zoho CRM API +// https://www.zoho.com/crm/help/api/v2/#create-specify-records +// +server.get('/crm/:data', (req, res) => { const { ZOHO_CRM_TOKEN } = req.webtaskContext.secrets + const { data } = req.params - proxyReq.setHeader('Authorization', `Zoho-oauthtoken ${ZOHO_CRM_TOKEN}`) -} + const options = { + url: `${apiUrlZohoCRM}Leads`, // eslint-disable-line max-len + headers: { 'Authorization': `Zoho-oauthtoken ${ZOHO_CRM_TOKEN}` }, + method: 'POST', + formData: data + } -const configZohoCRM = { - target: apiUrlZohoCRM, - pathRewrite: { '^/zoho/crm/': '/' }, - changeOrigin: true, - onProxyReq: onProxyReqZohoCRM -} + request(options, (error, response, body) => { + if (error) { + res.send(error) + } -server.use(proxy('/zoho/crm/**', configZohoCRM)) + res.send(body) + res.sendStatus(200) + }) +}) module.exports = Webtask.fromExpress(server) From c95bac34a09737d80ec0e2eb456c9bf33836babc Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Thu, 21 Jun 2018 18:09:22 +0200 Subject: [PATCH 06/10] DRY --- webtask-zoho.js | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/webtask-zoho.js b/webtask-zoho.js index e28767f..4f68baa 100644 --- a/webtask-zoho.js +++ b/webtask-zoho.js @@ -11,11 +11,20 @@ server.listen(4430) server.use(bodyParser.json()) // -// Zoho API urls +// Zoho APIs // const apiUrlZohoCampaigns = 'https://campaigns.zoho.com/api/' const apiUrlZohoCRM = 'https://www.zohoapis.com/crm/v2/' +const sendRequest = (options, res) => { + request(options, (error, response, body) => { + if (error) res.send(error) + + res.send(body) + res.sendStatus(200) + }) +} + // // Subscribe to newsletter via Zoho Campaigns API // https://www.zoho.com/campaigns/newhelp/api/contact-subscribe.html @@ -27,15 +36,7 @@ server.get('/newsletter/:data', (req, res) => { const options = { url: `${apiUrlZohoCampaigns}json/listsubscribe?authtoken=${ZOHO_CAMPAIGNS_TOKEN}&scope=CampaignsAPI&resfmt=JSON&listkey=${ZOHO_CAMPAIGNS_LIST_KEY}&contactinfo=${data}` // eslint-disable-line max-len } - - request(options, (error, response, body) => { - if (error) { - res.send(error) - } - - res.send(body) - res.sendStatus(200) - }) + sendRequest(options, res) }) // @@ -52,15 +53,7 @@ server.get('/crm/:data', (req, res) => { method: 'POST', formData: data } - - request(options, (error, response, body) => { - if (error) { - res.send(error) - } - - res.send(body) - res.sendStatus(200) - }) + sendRequest(options, res) }) module.exports = Webtask.fromExpress(server) From 6bff6d4fa1bb4c11a83cd1d9c0a33b369dff7851 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Thu, 21 Jun 2018 18:42:52 +0200 Subject: [PATCH 07/10] decode newsletter data --- webtask-zoho.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webtask-zoho.js b/webtask-zoho.js index 4f68baa..c185968 100644 --- a/webtask-zoho.js +++ b/webtask-zoho.js @@ -34,7 +34,7 @@ server.get('/newsletter/:data', (req, res) => { const { data } = req.params const options = { - url: `${apiUrlZohoCampaigns}json/listsubscribe?authtoken=${ZOHO_CAMPAIGNS_TOKEN}&scope=CampaignsAPI&resfmt=JSON&listkey=${ZOHO_CAMPAIGNS_LIST_KEY}&contactinfo=${data}` // eslint-disable-line max-len + url: `${apiUrlZohoCampaigns}json/listsubscribe?authtoken=${ZOHO_CAMPAIGNS_TOKEN}&scope=CampaignsAPI&resfmt=JSON&listkey=${ZOHO_CAMPAIGNS_LIST_KEY}&contactinfo=${decodeURIComponent(data)}` // eslint-disable-line max-len } sendRequest(options, res) }) From 2ba4f1fbe6fa9a89430d19241f3aa3a1e718d3d5 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Thu, 21 Jun 2018 19:46:27 +0200 Subject: [PATCH 08/10] pass through status code --- webtask-zoho.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webtask-zoho.js b/webtask-zoho.js index c185968..6b80287 100644 --- a/webtask-zoho.js +++ b/webtask-zoho.js @@ -21,7 +21,7 @@ const sendRequest = (options, res) => { if (error) res.send(error) res.send(body) - res.sendStatus(200) + res.sendStatus(response.statusCode) }) } From 0c5bd4dcb985481e7b47cc71b9c9b4c1d558f778 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Fri, 22 Jun 2018 12:46:38 +0200 Subject: [PATCH 09/10] update documentation --- README.md | 71 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index ae447eb..2a01f1c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# Webtasks +[![banner](https://raw.githubusercontent.com/oceanprotocol/art/master/github/repo-banner%402x.png)](https://oceanprotocol.com) + +

webtasks

> 🐬 Ocean Protocol's webtasks doing automatic things for us via webtask.io @@ -7,60 +9,75 @@ [![Build Status](https://travis-ci.com/oceanprotocol/webtasks.svg?token=3psqw6c8KMDqfdGQ2x6d&branch=master)](https://travis-ci.com/oceanprotocol/webtasks) [![js ascribe](https://img.shields.io/badge/js-ascribe-39BA91.svg)](https://github.com/ascribe/javascript) +## Table of Contents + + - [Tasks](#tasks) + - [Medium](#medium) + - [YouTube](#youtube) + - [Zoho](#zoho) + - [Campaigns API](#campaigns-api) + - [Development](#development) + - [Deployment](#deployment) + - [Authors](#authors) + - [License](#license) + +--- + ## Tasks ### Medium **`webtask-medium.js`**: Generic task to fetch and reconstruct items from any medium publication. -Requires the Medium username appended at the end of the url, e.g. locally: +Requires the Medium username appended at the end of the url: -``` -http://localhost:8080/MEDIUM_USERNAME -``` +```bash +http://localhost:8080/:medium_username -When published as a web task, append the taskname followed by the Medium username at the end: - -``` -https://TASK_URL/TASK_NAME/MEDIUM_USERNAME +# when published on webtask.io +https://TASK_URL/TASK_NAME/:medium_username ``` ### YouTube -**`webtask-youtube.js`**: Generic task to fetch and reconstruct items from any YouTube account. For now, only fetches a playlist. YouTube API key is provided via [secret environment variable](https://webtask.io/docs/issue_parameters) `YOUTUBE_API_KEY` setup in web editor of webtask.io +**`webtask-youtube.js`**: Generic task to fetch and reconstruct items from any YouTube account. For now, only fetches a playlist. YouTube API key is provided via [secret environment variable](https://webtask.io/docs/issue_parameters) `YOUTUBE_API_KEY` setup in web editor of webtask.io. Construct your request url like so, e.g. locally: -``` -http://localhost:8080/YOUTUBE_PLAYLIST_ID -``` +```bash +http://localhost:8080/:youtube_playlist_id -Add the task name when published on webtask.io: - -``` -https://TASK_URL/TASK_NAME/YOUTUBE_PLAYLIST_ID +# when published on webtask.io +https://TASK_URL/TASK_NAME/:youtube_playlist_id ``` ### Zoho -**`webtask-zoho.js`**: Generic task to subscribe users into lists on Zoho Campaigns & Zoho CRM. Credentials are provided via [secret environment variables](https://webtask.io/docs/issue_parameters), setup in web editor of webtask.io. +**`webtask-zoho.js`**: Generic task to subscribe users into lists on Zoho Campaigns & Zoho CRM. -The user input data needs to be in `json` format like so: +Credentials are provided via [secret environment variables](https://webtask.io/docs/issue_parameters), setup in web editor of webtask.io: + +* `ZOHO_CAMPAIGNS_TOKEN` +* `ZOHO_CAMPAIGNS_LIST_KEY` +* `ZOHO_CRM_TOKEN` + +#### Campaigns API + +* `/newsletter/:data`: subscribes the given email address to the newsletter list on Zoho Campaigns. + +The data needs to be in `json` format in the following pattern: ``` {Contact Email:info@oceanprotocol.com} ``` -To subscribe a user to the newsletter, construct your request url like so, e.g. locally: +Construct your request url like so, e.g. locally: -``` -http://localhost:8080/newsletter/DATA -``` +```bash +http://localhost:8080/newsletter/:data -Add the task name when published on webtask.io: - -``` -https://TASK_URL/TASK_NAME/newsletter/DATA +# when published on webtask.io +https://TASK_URL/TASK_NAME/newsletter/:data ``` ## Development From 0f6b92617c23cd1ad5f575f10339eb2a2305e059 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Fri, 22 Jun 2018 13:05:58 +0200 Subject: [PATCH 10/10] lock down with CORS --- webtask-zoho.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/webtask-zoho.js b/webtask-zoho.js index 6b80287..8cc0f77 100644 --- a/webtask-zoho.js +++ b/webtask-zoho.js @@ -6,10 +6,18 @@ const request = require('request') const server = express() -server.use(cors()) server.listen(4430) server.use(bodyParser.json()) +// +// Allow requests from these domains only +// +const corsOptions = { + origin: ['https://oceanprotocol.com', /\.oceanprotocol\.com$/], + optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204 +} +server.use(cors(corsOptions)) + // // Zoho APIs // @@ -20,6 +28,8 @@ const sendRequest = (options, res) => { request(options, (error, response, body) => { if (error) res.send(error) + // just pass through whatever we get from the APIs + // as the response res.send(body) res.sendStatus(response.statusCode) })