Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arul/email setup #37

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@

# testing
/coverage
/.history

# production
/build

# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
Expand Down
5,327 changes: 4,627 additions & 700 deletions package-lock.json

Large diffs are not rendered by default.

13 changes: 12 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "starter-react-app",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:3000",
"scripts": {
"start": "node server.js",
"dev": "react-scripts start",
Expand All @@ -28,7 +29,17 @@
]
},
"dependencies": {
"express": "^4.17.3"
"@wix/api-client": "^1.2.8",
"@wix/data": "^1.0.37",
"@wix/data-items": "^1.0.4",
"dotenv": "^16.3.1",
"email-templates": "^11.1.1",
"express": "^4.17.3",
"jsonwebtoken": "^9.0.1",
"nodemailer": "^6.9.4",
"pug": "^3.0.2",
"react-router-dom": "^6.15.0",
"remarkable": "^2.0.1"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.16.2",
Expand Down
85 changes: 84 additions & 1 deletion server.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@

const express = require('express')
const path = require("path");
const { fetchLeads, reduceCount, putLead } = require('./serverUtils/wix-data');
const { getBlogData } = require('./serverUtils/gpt-data');
const { sendEmail } = require('./serverUtils/emailer');
const app = express()
const bodyParser = require('body-parser');
var jwt = require('jsonwebtoken');

// #############################################################################
// This configures static hosting for files in /public that have the extensions
Expand All @@ -15,9 +20,87 @@ var options = {
redirect: false
}
app.use(express.static('build', options))

app.use(bodyParser.json());
const port = process.env.PORT || 3000

// Serve static files (like your bundled JavaScript and CSS)
app.use(express.static(path.join(__dirname, 'build')));

app.post("/generateBlog", async (request, response)=>{
console.log(request.body)
const body = request.body

// const content = `
// Generate an SEO-optimized blog for my company, Heyo, in the Electronics industry.
// Parameters:
// - Blog Type: Expertise
// - Blog Topic: Random Books
// - Word Limit: 50
// - Format: Markdown

// Output Format:
// 1. Blog Content
// 2. Suggested Excerpt for the Blog
// 3. Suggested Meta Tags for the Blog
// 4. Suggested Meta Description for the Blog
// 5. Focus Keyword Used in the Blog
// 6. Suggested Categories for the Blog
// `

const email = body.email;
const mobile = body.mobile;
const type = body.type;
const content = body.content.dd1;

// Arul: Remove hardcoded mobile and type
let getLeadsResponse = await fetchLeads(mobile, email, type);
if (typeof getLeadsResponse === 'number') {
if (getLeadsResponse > 0) {
const count = await reduceCount(number, type)
console.log(count)
count > -1 && await getBlogData(request, response, content);
} else {
response.status(201).send({"message": {"message": "max usage excceeded"}})
}
} else {
console.log("fire email verification link")
await sendEmail(request)
response.status(200).send({"message": {"message": "Welcome to Halo. Kindly verify your email via the email notification send to you. Once completed, Simply click on the submit button to generate your "+ type}})
}

});



app.get('/verify', async (request, response) => {
const {token} = request.query;

// Verifying the JWT token
jwt.verify(token, 'secretKey', async function(err, decoded) {
console.log(decoded)
if (err) {
console.log(err);
response.send("Email verification failed, possibly the link is invalid or expired");
}
else {
// create a new record in the DB
// add an entry and give 3 blogs and 5 logos.
let res = await putLead(request.name, request.email, request.mobile)

if(res) {
response.send({message: "Email verifified successfully"});
} else {
response.send({message: "User already exists"});
}
}
});
});

// Define a catch-all route that serves your React app's index.html
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

app.listen(port, () => {
console.log(`React app listening at http://localhost:${port}`)
})
5 changes: 5 additions & 0 deletions serverUtils/email_otp_template/html.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
h1 Hello #{firstName} #{lastName}
p.
Welcome to My App! Now your test emails will be safe. We just need to make sure your account is real.
Please, click the button below and start using your account.
a(href='https://example.com/confirmation') Confirm!
1 change: 1 addition & 0 deletions serverUtils/email_otp_template/subject.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`Hi ${firstName} ${lastName}, happy to see you at My App!`
39 changes: 39 additions & 0 deletions serverUtils/emailer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require('dotenv').config()
const nodemailer = require("nodemailer");
var jwt = require('jsonwebtoken');

var transporter = nodemailer.createTransport({
host: "live.smtp.mailtrap.io",
port: 587,
auth: {
user: "api",
pass: process.env.MAIL_TRAP_API_TOKEN
}
});

const sendEmail = async (request) => {
// 2.2 User doesn't exists
// 1. Send OTP to end user
const dataToEncrypt = {
email: "[email protected]"
}
// const basePath = "https://long-jade-sheep.cyclic.cloud/verify"
const basePath = "http://localhost:3000"
const token = jwt.sign(dataToEncrypt, "secretKey", { algorithm: 'HS256' });
const mailSendingStartTime = new Date()
const info = await transporter.sendMail({
from: '"Welcome from Halo 👻" [email protected]', // sender address
to: "[email protected]", // list of receivers
subject: "Verfication Link ✔", // Subject line
text: "Test mailer. Yo Bro!", // plain text body
html: `<a href="${basePath}/user/verify/${token}">Verify</a>`,
})
.then((r)=>{})
.catch(e=>console.error("ERR",e));
console.log(new Date() - mailSendingStartTime)
return;

//

}
module.exports = { sendEmail }
29 changes: 29 additions & 0 deletions serverUtils/gpt-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require('dotenv').config()

let bearerToken = process.env.OPEN_AI_KEY;

const getBlogData = async (req, response, content) => {
console.log(response)
return await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Authorization" : "Bearer " + bearerToken,
"Content-Type": "application/json"
},
body: JSON.stringify({
"model": "gpt-3.5-turbo-0613",
"messages": [{"role": "user", "content": content}],
"temperature": 0.7
})
}).then(async chatCompletionResponse => {
let res = await chatCompletionResponse.json();
response.send({"response": res.choices[0].message.content});
}).catch((err)=>{
response.send("error", err)
})
}

module.exports = { getBlogData }
8 changes: 8 additions & 0 deletions serverUtils/structure/ai_request_structure.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"email": "string",
"mobile": "number",
"type": "string",
"content": {
"dd1": "say, whadup doc!"
}
}
16 changes: 16 additions & 0 deletions serverUtils/wix-client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const { createClient, OAuthStrategy, ApiKeyStrategy } =require('@wix/api-client')
const { items, collections } = require('@wix/data');
const { dataItems } = require('@wix/data-items');
require('dotenv').config()


// clientId: process.env.WIX_OAUTH_CLIENT_ID,
const myWixClient = createClient({
modules: { items, dataItems, collections },
auth: ApiKeyStrategy({
siteId: process.env.WIX_SITE_ID,
apiKey: process.env.WIX_API_KEY
})
});

module.exports = { myWixClient }
70 changes: 70 additions & 0 deletions serverUtils/wix-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const { myWixClient } = require('./wix-client');


const reduceCount = async (mobile, type) => {
const leads = await myWixClient.items
.queryDataItems({ dataCollectionId: 'Leads' })
.find(
{ fields: { "mobile": mobile }}
);

const dataItemId = leads._items[0].data._id;

const dataItem = await myWixClient.dataItems.getDataItem(dataItemId, {consistentRead: false, dataCollectionId: "Leads"});

if (type === 'blog') {
dataItem.data.remaining_blog_usage_count--;
} else {
dataItem.data.remaining_logo_usage_count--;
}

const options = { dataCollectionId: "Leads", dataItem: {
data: dataItem.data
}};

await myWixClient.dataItems.removeDataItem(dataItemId, {dataCollectionId: "Leads"});
delete dataItem.data._id
await myWixClient.dataItems.saveDataItem(options);
return type === 'blog' ? dataItem.data.remaining_blog_usage_count : dataItem.data.remaining_logo_usage_count;
}

/*
@params - user mobile number
@params - email user email id
@params - type 'blog' or 'logo'
*/
async function fetchLeads(mobile, email, type) {
let leads = false;

try {
leads = await myWixClient.items
.queryDataItems({ dataCollectionId: 'Leads', consistentRead: false })
.eq("mobile", mobile ).find();
} catch(e) {
console.log(e)
}

if (leads && leads._items.length > 0) {
console.log(leads._items[0].data.remaining_blog_usage_count)
return type === 'blog' ? leads._items[0].data.remaining_blog_usage_count : leads._items[0].data.remaining_logo_usage_count
}
return false
}

async function putLead(name, email, mobile) {
let item = {
name: name,
mobile: mobile,
email_id: email,
remaining_blog_usage_count: 3,
remaining_logo_usage_count: 5
}
try {
await myWixClient.dataItems.saveDataItem({dataCollectionId: 'Leads', dataItem: {data: item}})
return true
} catch (e) {
return false
}
}

module.exports = { fetchLeads, reduceCount, putLead }
28 changes: 3 additions & 25 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
.App {
text-align: center;
}

.App-logo {
height: 40vmin;
pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}

.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
Expand All @@ -24,15 +10,7 @@
color: white;
}

.App-link {
color: #61dafb;
}

@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
.blogContent{
text-align: left;
padding: 0 25%;
}
Loading