Added required authorization for all API calls. Added template stylesheet.
This commit is contained in:
@@ -1,112 +1,95 @@
|
|||||||
unlayer.registerPropertyEditor({
|
// unlayer.registerPropertyEditor({
|
||||||
name: "my_color_picker",
|
// name: "field_name",
|
||||||
layout: "bottom",
|
// layout: "bottom",
|
||||||
Widget: unlayer.createWidget({
|
// Widget: unlayer.createWidget({
|
||||||
render(value) {
|
// render(value) {
|
||||||
return `
|
// return `
|
||||||
<input class="color-value" value=${value} />
|
// <input class="field" value=${value} />
|
||||||
<button class="red">Red</button>
|
// `;
|
||||||
<button class="green">Green</button>
|
// },
|
||||||
<button class="blue">Blue</button>
|
// mount(node, value, updateValue) {
|
||||||
`;
|
// var input = node.getElementsByClassName("field")[0];
|
||||||
},
|
// input.onchange = function (event) {
|
||||||
mount(node, value, updateValue) {
|
// updateValue(event.target.value);
|
||||||
var input = node.getElementsByClassName("color-value")[0];
|
// };
|
||||||
input.onchange = function (event) {
|
// },
|
||||||
updateValue(event.target.value);
|
// }),
|
||||||
};
|
// });
|
||||||
|
|
||||||
var redButton = node.getElementsByClassName("red")[0];
|
// unlayer.registerTool({
|
||||||
redButton.onclick = function () {
|
// type: "whatever",
|
||||||
updateValue("#f00");
|
// category: "contents",
|
||||||
};
|
// label: "Begin Repeat",
|
||||||
|
// icon: "fa-smile",
|
||||||
|
// values: {},
|
||||||
|
// options: {
|
||||||
|
// default: {
|
||||||
|
// title: null,
|
||||||
|
// },
|
||||||
|
// text: {
|
||||||
|
// title: "Field",
|
||||||
|
// position: 1,
|
||||||
|
// options: {
|
||||||
|
// field: {
|
||||||
|
// label: "Field",
|
||||||
|
// defaultValue: "",
|
||||||
|
// widget: "field_name",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// renderer: {
|
||||||
|
// Viewer: unlayer.createViewer({
|
||||||
|
// render(values) {
|
||||||
|
// console.log(values);
|
||||||
|
// return `
|
||||||
|
// <div style="display: none;">{{#each ${values.field}}}</div>
|
||||||
|
// `;
|
||||||
|
// },
|
||||||
|
// }),
|
||||||
|
// exporters: {
|
||||||
|
// web: function () {},
|
||||||
|
// email: function () {},
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
var greenButton = node.getElementsByClassName("green")[0];
|
// unlayer.registerTool({
|
||||||
greenButton.onclick = function () {
|
// type: "whatever",
|
||||||
updateValue("#0f0");
|
// category: "contents",
|
||||||
};
|
// label: "End Repeat",
|
||||||
|
// icon: "fa-smile",
|
||||||
var blueButton = node.getElementsByClassName("blue")[0];
|
// values: {},
|
||||||
blueButton.onclick = function () {
|
// options: {
|
||||||
updateValue("#00f");
|
// default: {
|
||||||
};
|
// title: null,
|
||||||
},
|
// },
|
||||||
}),
|
// text: {
|
||||||
});
|
// title: "Field",
|
||||||
|
// position: 1,
|
||||||
unlayer.registerTool({
|
// options: {
|
||||||
type: "whatever",
|
// field: {
|
||||||
category: "contents",
|
// label: "Field",
|
||||||
label: "My Tool",
|
// defaultValue: "",
|
||||||
icon: "fa-smile",
|
// widget: "field_name",
|
||||||
values: {},
|
// },
|
||||||
options: {
|
// },
|
||||||
default: {
|
// },
|
||||||
title: null,
|
// },
|
||||||
},
|
// renderer: {
|
||||||
text: {
|
// Viewer: unlayer.createViewer({
|
||||||
title: "Text",
|
// render(values) {
|
||||||
position: 1,
|
// return `
|
||||||
options: {
|
// <div style="display: none;">{{ /each }}</div>
|
||||||
color: {
|
// `;
|
||||||
label: "Color",
|
// },
|
||||||
defaultValue: "#000",
|
// }),
|
||||||
widget: "my_color_picker",
|
// exporters: {
|
||||||
},
|
// web: function () {},
|
||||||
},
|
// email: function () {},
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
renderer: {
|
// });
|
||||||
Viewer: unlayer.createViewer({
|
|
||||||
render(values) {
|
|
||||||
return `
|
|
||||||
<div style="color: ${values.color};">I am a custom tool.</div>
|
|
||||||
`;
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
exporters: {
|
|
||||||
web: function () {},
|
|
||||||
email: function () {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
unlayer.registerColumns([2, 2, 2, 2, 2, 2]);
|
unlayer.registerColumns([2, 2, 2, 2, 2, 2]);
|
||||||
unlayer.registerColumns([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
|
unlayer.registerColumns([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
|
||||||
|
|
||||||
unlayer.registerTool({
|
|
||||||
type: "whatever",
|
|
||||||
category: "contents",
|
|
||||||
label: "Begin Repeater",
|
|
||||||
icon: "fa-smile",
|
|
||||||
values: {},
|
|
||||||
options: {
|
|
||||||
default: {
|
|
||||||
title: "BeginRepeater",
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
title: "Text",
|
|
||||||
position: 1,
|
|
||||||
options: {
|
|
||||||
field: {
|
|
||||||
label: "Field",
|
|
||||||
defaultValue: "Field Name...",
|
|
||||||
widget: "my_color_picker",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
renderer: {
|
|
||||||
Viewer: unlayer.createViewer({
|
|
||||||
render(values) {
|
|
||||||
return `
|
|
||||||
<div style="color: ${values.color};">{{${values.field}}}</div>
|
|
||||||
`;
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
exporters: {
|
|
||||||
web: function () {},
|
|
||||||
email: function () {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
85
client/public/render-styles.css
Normal file
85
client/public/render-styles.css
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/* body {
|
||||||
|
font-family: "Open Sans", sans-serif;
|
||||||
|
line-height: 1.25;
|
||||||
|
} */
|
||||||
|
|
||||||
|
table {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
table caption {
|
||||||
|
font-size: 1.5em;
|
||||||
|
margin: 0.5em 0 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tr {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 0.35em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th,
|
||||||
|
table td {
|
||||||
|
padding: 0.625em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th {
|
||||||
|
font-size: 0.85em;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
table {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table caption {
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table thead {
|
||||||
|
border: none;
|
||||||
|
clip: rect(0 0 0 0);
|
||||||
|
height: 1px;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tr {
|
||||||
|
border-bottom: 3px solid #ddd;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.625em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table td {
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
display: block;
|
||||||
|
font-size: 0.8em;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
table td::before {
|
||||||
|
/*
|
||||||
|
* aria-label has no advantage, it won't be read inside a table
|
||||||
|
content: attr(aria-label);
|
||||||
|
*/
|
||||||
|
content: attr(data-label);
|
||||||
|
float: left;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
table td:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,9 +18,25 @@ import App from "./App";
|
|||||||
import { ConfigProvider } from "antd";
|
import { ConfigProvider } from "antd";
|
||||||
import enLocale from "antd/es/locale/en_US";
|
import enLocale from "antd/es/locale/en_US";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
moment.locale("en-US");
|
moment.locale("en-US");
|
||||||
|
|
||||||
|
axios.interceptors.request.use(
|
||||||
|
async (config) => {
|
||||||
|
if (!config.headers.Authorization) {
|
||||||
|
const token =
|
||||||
|
auth.currentUser && (await auth.currentUser.getIdToken(true));
|
||||||
|
if (token) {
|
||||||
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
(error) => Promise.reject(error)
|
||||||
|
);
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "production") LogRocket.init("gvfvfw/bodyshopapp");
|
if (process.env.NODE_ENV === "production") LogRocket.init("gvfvfw/bodyshopapp");
|
||||||
|
|
||||||
const httpLink = new HttpLink({
|
const httpLink = new HttpLink({
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ export default function ShopTemplateSaveButton({
|
|||||||
logImEXEvent("shop_template_update");
|
logImEXEvent("shop_template_update");
|
||||||
|
|
||||||
emailEditorRef.current.exportHtml(async (data) => {
|
emailEditorRef.current.exportHtml(async (data) => {
|
||||||
|
console.log("RAW", data.html);
|
||||||
inlineCss(data.html, {
|
inlineCss(data.html, {
|
||||||
url: `${window.location.protocol}://${window.location.host}`,
|
url: `${window.location.protocol}://${window.location.host}/`,
|
||||||
}).then(async function (inlineHtml) {
|
}).then(async function (inlineHtml) {
|
||||||
|
console.log("Inline :>> ", inlineHtml);
|
||||||
const result = await updateTemplate({
|
const result = await updateTemplate({
|
||||||
variables: {
|
variables: {
|
||||||
templateId: templateId,
|
templateId: templateId,
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ export default function ShopTemplateEditorComponent({
|
|||||||
const emailEditorRef = useRef(null);
|
const emailEditorRef = useRef(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (json && Object.keys(json).length > 0)
|
if (json && Object.keys(json).length > 0 && emailEditorRef.current) {
|
||||||
emailEditorRef.current.loadDesign(json);
|
emailEditorRef.current.loadDesign(json);
|
||||||
|
}
|
||||||
}, [json, emailEditorRef]);
|
}, [json, emailEditorRef]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -46,6 +47,12 @@ export default function ShopTemplateEditorComponent({
|
|||||||
<EmailEditor
|
<EmailEditor
|
||||||
ref={emailEditorRef}
|
ref={emailEditorRef}
|
||||||
options={{
|
options={{
|
||||||
|
// customCSS: [
|
||||||
|
// window.location.protocol +
|
||||||
|
// "//" +
|
||||||
|
// window.location.host +
|
||||||
|
// "/render-styles.css",
|
||||||
|
// ],
|
||||||
customJS: [
|
customJS: [
|
||||||
window.location.protocol +
|
window.location.protocol +
|
||||||
"//" +
|
"//" +
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ const path = require("path");
|
|||||||
const compression = require("compression");
|
const compression = require("compression");
|
||||||
const twilio = require("twilio");
|
const twilio = require("twilio");
|
||||||
global.fetch = require("node-fetch");
|
global.fetch = require("node-fetch");
|
||||||
|
var fb = require("./server/firebase/firebase-handler");
|
||||||
|
|
||||||
//var enforce = require("express-sslify");
|
//var enforce = require("express-sslify");
|
||||||
|
|
||||||
require("dotenv").config({
|
require("dotenv").config({
|
||||||
@@ -21,6 +23,7 @@ const app = express();
|
|||||||
const port = process.env.PORT || 5000;
|
const port = process.env.PORT || 5000;
|
||||||
//const port = 5000;
|
//const port = 5000;
|
||||||
|
|
||||||
|
app.use(fb.validateFirebaseIdToken);
|
||||||
app.use(compression());
|
app.use(compression());
|
||||||
app.use(bodyParser.json({ limit: "50mb" }));
|
app.use(bodyParser.json({ limit: "50mb" }));
|
||||||
app.use(bodyParser.urlencoded({ limit: "50mb", extended: true }));
|
app.use(bodyParser.urlencoded({ limit: "50mb", extended: true }));
|
||||||
@@ -77,7 +80,6 @@ app.post("/scheduling/job", scheduling.job);
|
|||||||
var renderHandlebars = require("./server/render/renderHandlebars");
|
var renderHandlebars = require("./server/render/renderHandlebars");
|
||||||
app.post("/render", renderHandlebars.render);
|
app.post("/render", renderHandlebars.render);
|
||||||
|
|
||||||
var fb = require("./server/firebase/firebase-handler");
|
|
||||||
app.post("/notifications/send", fb.sendNotification);
|
app.post("/notifications/send", fb.sendNotification);
|
||||||
|
|
||||||
//Stripe Processing
|
//Stripe Processing
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
var admin = require("firebase-admin");
|
var admin = require("firebase-admin");
|
||||||
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
require("dotenv").config({
|
require("dotenv").config({
|
||||||
path: path.resolve(
|
path: path.resolve(
|
||||||
@@ -42,3 +43,49 @@ exports.sendNotification = (req, res) => {
|
|||||||
|
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.validateFirebaseIdToken = async (req, res, next) => {
|
||||||
|
console.log("Check if request is authorized with Firebase ID token");
|
||||||
|
|
||||||
|
if (
|
||||||
|
(!req.headers.authorization ||
|
||||||
|
!req.headers.authorization.startsWith("Bearer ")) &&
|
||||||
|
!(req.cookies && req.cookies.__session)
|
||||||
|
) {
|
||||||
|
console.error("Unauthorized attempt. No authorization provided.");
|
||||||
|
res.status(403).send("Unauthorized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let idToken;
|
||||||
|
if (
|
||||||
|
req.headers.authorization &&
|
||||||
|
req.headers.authorization.startsWith("Bearer ")
|
||||||
|
) {
|
||||||
|
// console.log('Found "Authorization" header');
|
||||||
|
// Read the ID Token from the Authorization header.
|
||||||
|
idToken = req.headers.authorization.split("Bearer ")[1];
|
||||||
|
} else if (req.cookies) {
|
||||||
|
//console.log('Found "__session" cookie');
|
||||||
|
// Read the ID Token from cookie.
|
||||||
|
idToken = req.cookies.__session;
|
||||||
|
} else {
|
||||||
|
// No cookie
|
||||||
|
console.error("Unauthorized attempt. No cookie provided.");
|
||||||
|
|
||||||
|
res.status(403).send("Unauthorized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const decodedIdToken = await admin.auth().verifyIdToken(idToken);
|
||||||
|
//console.log("ID Token correctly decoded", decodedIdToken);
|
||||||
|
req.user = decodedIdToken;
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error while verifying Firebase ID token:", error);
|
||||||
|
res.status(403).send("Unauthorized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user