how to make a newsletter button - node.js

Need some quick guidance regarding the newsletter button in react webpage. I wanna make a newsletter button that accepts, emails from users and stores them in a spreadsheet. Basically, I need some code guidance such that when someone enters their email and clicks submit button. They will get the template email like 'Thanks for subscribing to our newsletter and company email and we get their email in the spreadsheet.

In order for this to work you would have your React.js frontend that would get the e-mail address from the user and send a request to your backend service containing that e-mail address.
This could look similar to this.
import { useState } from "react";
import "./styles.css";
function isValidEmailAddress(email) {
// validate here
return true;
}
export default function App() {
const [address, setAddress] = useState("");
async function subscribeNewsletter() {
if (isValidEmailAddress(address)) {
try {
const response = await fetch("https://your-backend/subscription", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
email: address
})
});
// check if request was successful (codes 200-299)
// in this implementation we expect code "201 Created"
if (!response.ok) {
const parsed = JSON.parse(response.body);
// show error message received from backend
alert(parsed.msg);
} else {
alert("Subscribed.");
}
} catch (error) {
alert("Subscription failed");
}
}
}
return (
<div className="App">
<input onChange={(e) => setAddress(e.target.value)} value={address} />
<button onClick={() => subscribeNewsletter()}>Subscribe</button>
</div>
);
}
See CodeSandbox for a minimal working demo of the frontend.
Within your backend you have to handle the request to the /subscription endpoint. In a handler you will probably validate the email address again and then write it into a database or spreadsheet (if you really want to use spreadsheets which I would not recommend).
Last but not least you need to send the welcome email. The easiest way to do this is to use a 3rd party API or you use something like SMTP JS to send an email. What you will need in that case is a SMTP server. Have a look on this thread for more details.
The backend service could then look similar to this.
Note: this is not a perfect implementation but a skeleton that should help you getting started.
import express from "express";
// create app
var app = express();
// middleware to parse json
app.use(express.json())
app.get('/', function (req, res) {
// serve your react application
res.sendFile("index.html");
});
app.post("/subscription", function (req, res) {
const emailAddress = req.body.email;
if (!isValidEmailAddress(emailAddress)) {
// malformed email address
res.status(400).send({
msg: "email address is invalid"
})
}
insertNewSubscriber(emailAddress);
sendWelcomeEmail(emailAddress);
// resource subsription has been created
res.status(201).send();
});
// listen for request on port 3000
const port = 3000;
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
function isValidEmailAddress(email) {
// validate here
return true;
}
function insertNewSubscriber(email) {
// write to database/ file/ spreadsheet etc.
}
function sendWelcomeEmail(email) {
// send email e.g. using 3rd party API
}

Related

"Sign in with Apple" redirects to a blank white page on PWA

I've implemented "Sign in with Apple" on my site. When I try it on my phone, it redirects me to a blank white page with the same URL as the redirect_uri I've configured.
I can't find any info on why this is happening. What's a possible fix?
UPDATE
It seems as if Apple JS SDK is creating a FORM HTML DOM element, sets the POST URL of the FORM to point to the redirect_uri, and finally programmatically clicks form.submit(). This for some reason causes the page to navigate to the redirect_uri and show the POST response as a new page.
I figured this out by tracking the Apple JS SDK in the debugger.
Here is my code
//---- Frontend ----
AppleID.auth.init({
clientId : '<client_id>',
scope : 'email',
redirectURI : 'mySite.com/apple_auth',
state : 'origin:web',
nonce : Date.now(),
//usePopup : true //not using this one. When false or undefined, Apple will make a POST request to the defined redirect_uri
})
// Listen for authorization success.
document.addEventListener('AppleIDSignInOnSuccess', (event) => {
// Handle successful response.
console.log(event.detail.data);
});
// Listen for authorization failures.
document.addEventListener('AppleIDSignInOnFailure', (event) => {
// Handle error.
console.log(event.detail.error);
});
//...
myButton.onClick = ()=>{
try {
var res = await AppleID.auth.signIn()
} catch(err) {
var x = 0
}
}
//---- Backend ----
var appleSignin = require("apple-signin-auth")
app.express.post('/apple_auth', async (req, res)=>{
var body = req.body
try {
const appleRes = await appleSignin.verifyIdToken(
body.id_token, // We need to pass the token that we wish to decode.
{
audience: '<client_id', // client id - The same one we used on the frontend, this is the secret key used for encoding and decoding the token.
ignoreExpiration: true, // Token will not expire unless you manually do so.
}
)
//do something with the Apple response
} catch (err) {
// Token is not verified
console.error(err)
}
})
From the documentation...
The HTTP body contains the result parameters with a content-type of application/x-www-form-urlencoded.
Make sure you've configured the urlencoded() body-parsing middleware in your Express app.
app.use(express.urlencoded());
Make sure you check for errors and actually send a response from your /apple_auth Express route
const { code, id_token, state, user, error } = req.body;
if (error) {
return res.status(500).send(error);
}
try {
const appleRes = await appleSignin.verifyIdToken(id_token, {
audience: "<client_id>",
ignoreExpiration: true,
});
// do something with the Apple response, then send a response
res.send(appleRes.sub);
} catch (err) {
console.error(err);
res.sendStatus(500); // send a 500 response status
}

how to get stripe-signature in your stripe webhook header

This is the first time I'm integrating stripe checkout but I keep getting stripe-signature as undefined.
For my backend I am using firebase cloud functions (without express) and for my frontend I am using react-stripe-checkout.
Is there some kind of header I need to send in order to receive that on the backend?
The only header I am sending now is:
'Content-Type': 'application/json',
backend code:
// #ts-ignore
const stripe = new Stripe('sk_test_123');
export const stripeHook = functions.https.onRequest(async (request, response) => {
cors(request, response, async () => {
const sig = request.headers['stripe-signature']; // this is always undefined
// let sig = request.get('stripe-signature'); //also tried streaming
const endpointSecret = 'whsec_123';
let event;
try {
event = stripe.webhooks.constructEvent(request.rawBody.toString('utf8'), sig, endpointSecret);
} catch (err) {
console.log(err)
response.send({status: 'error'});
return;
}
// Handle Type of webhook
const intent:any = event.data.object;
switch (event.type) {
case 'payment_intent.succeeded':
console.log("Succeeded:", intent.id);
break;
case 'payment_intent.payment_failed':
const message = intent.last_payment_error && intent.last_payment_error.message;
console.log('Failed:', intent.id, message);
break;
}
response.send({status: 'success'});
})
})
fronend code:
import React, {useState, useEffect} from 'react';
import StripeCheckout from 'react-stripe-checkout';
import { ToastContainer, toast } from "react-toastify";
import 'react-toastify/dist/ReactToastify.css';
import api from '../../services/apiMiddleware';
function Assessment(props: any) {
const [product] = React.useState({
name: "Subscription",
price: 99.99,
description: "Monthly Subscription"
});
const handleToken = async (token: string) => {
const response = await api.post(
"stripeHook",
{ token, product }
);
if (response.status === "success") {
toast("Success! Check email for details", { type: "success" });
} else {
toast("Something went wrong", { type: "error" });
}
}
return (
<div>
<div className="paymentButtonTextWrapper">
<ToastContainer />
<div className="paymentButtonWrapper">
<StripeCheckout
// #ts-ignore
token={handleToken}
stripeKey="pk_test_123"
/>
</div>
</div>
</div>
)
}
You're confusing a webhook and the route on your server that charges the token. They're entirely separate things.
Your frontend code uses (a deprecated Stripe Checkout integration, the StripeCheckout React component there is an old library using an old version of Stripe) to create a Token object representing the customer's card details. The intention then is that you POST that token to your backend and your backend route will call the Stripe API to create a charge : https://stripe.com/docs/payments/accept-a-payment-charges#web-create-charge
The actual code in your backend that you POST to though seems to not be that, it's a webhook endpoint. That's a separate concept, Stripe would send a request to you when a payment succeeds and will include that signature header. But here the request you are processing is coming from your own frontend code, it's not a weboook and it has no Stripe signature.

Restrict access to a private content of Strapi via socket with public user

The project is about an online quiz system that has questions. I need to send questions by socket to a user if the user has Authenticated JWT. So far I have not implemented any authentication method to other pages, where I receive and submit the JWT.
In Strapi Admin Panel I have added the question content type as only visible or requestable by authorized users. But when it comes to the socket (not the HTTP request),
Strapi does not give any warnings or errors for the user which should not see them, neither warns me anyhow. The magic line of code which requests a question is:
socket.emit('hello', {message: await strapi.services.question.findOne()});
I have used a code from the bug report, they have figured out how to communicate with a client-side using socket.io. We have to write our custom code in the bootstrap.js file of the headless CMS.
An asynchronous bootstrap function that runs before your application
gets started.
This allows you to set up your data model, run jobs, or
perform some special logic.
See more details here:
https://strapi.io/documentation/v3.x/concepts/configurations.html#bootstrap
Here is my bootstrap.js file:
'use strict';
module.exports = async () => {
process.nextTick(() =>{
var io = require('socket.io')(strapi.server);
io.on('connection', async function(socket) {
console.log(`a user connected`)
// send message on user connection REQUESTING Questions Collection
socket.emit('hello', {message: await strapi.services.question.findOne()});
// listen for user diconnect
socket.on('disconnect', () =>{
console.log('a user disconnected')
});
});
strapi.io = io; // register socket io inside strapi main object to use it globally anywhere
})
};
Here is my client side on React frontend:
import React, { useState, useEffect } from "react";
import socketIOClient from "socket.io-client";
const ENDPOINT = "http://localhost:1337";
function App() {
const [response, setResponse] = useState();
useEffect(() => {
const socket = socketIOClient(ENDPOINT);
socket.on('hello', (msg, cb) => {
console.log('SOCKET HI')
console.log(msg.message)
setResponse('sinav icerigi: ' + JSON.stringify(msg.message))
});
}, []);
return (
<>
<p>
Response is:
</p>
<p>
{response}
</p>
</>
);
}
export default App;
The question: Need you to show me the way I could safely receive and use JWT authentication using Strapi's functions as much as possible.
Strapi settings of Public User:

Handle login using Google Authentication in system with client and server running on different port reactJS and nodeJS

Currently I'm working in proj using different port at client and server. I'm confusing about handling event in Client whenever login successful in Server. I don't know how to process to login at Client too. I'm using PassPortJS.
I added a button to handle onClick event in client, than start calling server to Authentication with Google by:
let gg_window = window.open("http://localhost:7000/authentication/google/auth", "_self");
I also config my google app for Authentication as below (Client running on port 9000, server in port 7000)
Google Authentication configuration
In Server:
I made an endpoint to handle URL as:
router.get('/google/auth',
passport.authenticate('google', {
scope:
'https://www.googleapis.com/auth/plus.me https://www.google.com/m8/feeds https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile'
})
);
router.get('/google/auth/redirect',
passport.authenticate('google'),
(req, res) => {
const token = jwt.sign(JSON.stringify(req.user), SECRET);
res.redirect("http://localhost:9000/google/auth/success?username=" + req.user.username + "&token=" + token);
});
I can get token, username... and redirect to client is ok
In Client
I'm using Redux-Saga, normal login with username and password is implemented before.
What should I do now? Thanks for any helping.
I'd implemented this feature by this way:
In Client:
Made an component to handle end-point "/google/auth/success" as:
<Route
component={ConfirmAccount}
path="/google/auth/success"
/>
In ConfirmAccountView, I've made a view to confirm UserName which inputted by user. Then have a button to confirm Account.
I made useEffect() of Hook to handle this View and save data to localStorage like:
useEffect(() => {
if (isLoggedIn === true) {
localStorage.setItem("authorize_token", authorization_token)
localStorage.setItem("user", username)
history.push('/profile')
}
if (error) {
NotificationManager.error(`${error}`, "Login Failed")
}
if (localStorage.getItem("authorize_token")) {
history.push('/profile')
}
}, [isLoggedIn, error]);
I also made a connect function to get state and post action to reducer:
const mapStateToProps = createStructuredSelector({
isLoggedIn: isLoggedIn(),
authorization: authorization(),
error: displayError()
});
const mapDispatchToProps = dispatch => {
return {
loginSuccessWithGG: username => {
dispatch(loginSuccessWithGG(username)); // Action dispatch for signin
}
}
};
export default connect(mapStateToProps, mapDispatchToProps)(ConfirmAccount);
In Redux-Saga, I made an action to dispatch action SignInSuccessful to reducer, then Reducer will set state isLoggedIn to True.
It's worked now.

Nextjs api and authentication

I'm in the process of building an application for stripe payments. This application generates a form that passes the data to the Stripe api via nextjs api. I just need to build in some basic authentication so only those submitting their payments via my form have access to the api. How would I go about adding some basic auth to my api without requiring users to login? Would I do this via env variable? I'm fairly new to the nextjs/vercel world and come from the python/django/react realm, so maybe my thoughts on this are backwards... I'm planning on hosting the api on vercel and the react form on a php site. So the react form will essentially push data to the vercel app api.
(The reason I'm not building the api in php is because I don't know php and because I'm attempting to build something with as little footprint in the current php site as possible.) Any help or guidance on this would be much appreciated!
My pages/api/customers.js file
import Stripe from 'stripe'
const stripe = new Stripe(process.env.SECRET_KEY)
export default async (req, res) => {
if (req.method === 'POST') {
try {
const { email, name, address, phone, source } = req.body
// Check for customer
const customerExist = await stripe.customers.list(
{
email: email,
limit: 0
})
// console.log('customerExist', customerExist.data[0])
if (customerExist.data.length < 1) {
const customer = await stripe.customers.create({
email,
name,
address,
phone,
source
})
res.status(200).send(customer.id)
} else {
res.status(200).send(customerExist.data[0].id)
}
} catch (err) {
res.status(500).json({ statusCode: 500, message: err.message })
}
} else {
res.setHeader('Allow', 'POST')
res.status(405).end('Method Not Allowed')
}
}
Part of my checkout form
// Function to check/create a user account via api
const checkUserAccount = async (billingDetails, source) => {
try {
const customer = await axios.post('/api/customers', {
email: billingDetails.email,
name: billingDetails.name,
phone: billingDetails.phone,
address: billingDetails.address,
source: source
})
return customer.data
} catch (err) {
console.log(err)
}
}
UPDATE:
Alright, so I added a "TOKEN" to my .env file and now require my api to receive that specific token.
I added this to my checkout form:
...
axios.defaults.headers.common.Authorization = process.env.AUTH_TOKEN
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
...
and then added this to the api:
if (req.method === 'POST' && req.headers.authorization === process.env.AUTH_TOKEN)...
Since I'm not using a login/logout system, I'm hoping this is enough. Thoughts or feedback are more than welcome.

Resources