cleanup
This commit is contained in:
@@ -1,138 +0,0 @@
|
||||
const { frontendBase, jwtSecret, logoPath, noReplyEmail, operatorEmail, serverBaseURL } = require("../config")
|
||||
const { getCustomerById } = require("../lib/bigcommerceRestAPI")
|
||||
const { createNewsletterSubscriber, checkIfNewsletterSubscriber } = require("../lib/omnisendRestApi")
|
||||
const { cryptchaCheck } = require("../lib/utils")
|
||||
;(function () {
|
||||
const operation = context.data.operation
|
||||
if (operation === "requestPasswordReset") {
|
||||
cryptchaCheck()
|
||||
requestPasswordReset()
|
||||
} else if (operation === "checkUsernameTaken") {
|
||||
const username = context.data.username
|
||||
const user = context.db.find("bigCommerceCustomer", {
|
||||
filter: { username: username.toLowerCase() },
|
||||
})[0]
|
||||
|
||||
throw {
|
||||
status: 200,
|
||||
data: !!user,
|
||||
}
|
||||
} else if (operation === "reportRecord") {
|
||||
const customerId = context.data.customerId
|
||||
if (!customerId) {
|
||||
throw {
|
||||
status: 400,
|
||||
message: "customerId is required",
|
||||
}
|
||||
}
|
||||
const recordTitle = context.data.record
|
||||
|
||||
context.smtp.sendMail({
|
||||
to: operatorEmail,
|
||||
from: noReplyEmail,
|
||||
fromName: "BinKrassDuFass",
|
||||
replyTo: noReplyEmail,
|
||||
subject: "Record Reported",
|
||||
plain: "Record reported, customer ID: " + customerId + ", record: " + recordTitle,
|
||||
})
|
||||
throw {
|
||||
status: 200,
|
||||
message: "Record reported",
|
||||
}
|
||||
} else if (operation === "subscribeToNewsletter") {
|
||||
if (!context.data.email) {
|
||||
throw {
|
||||
status: 400,
|
||||
message: "Email is required",
|
||||
}
|
||||
}
|
||||
createNewsletterSubscriber(context.data.email?.toLowerCase())
|
||||
throw {
|
||||
status: 200,
|
||||
message: "Newsletter subscriber created",
|
||||
}
|
||||
} else if (operation === "checkIfNewsletterSubscriber") {
|
||||
const email = context.data.email
|
||||
const isSubscriber = checkIfNewsletterSubscriber(email.toLowerCase())
|
||||
throw {
|
||||
status: 200,
|
||||
data: isSubscriber,
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} tibiId
|
||||
* @param {string} bigCommerceId
|
||||
* @param {string} key
|
||||
* @returns {string}
|
||||
*/
|
||||
function buildPwResetToken(tibiId, bigCommerceId, key) {
|
||||
return context.jwt.create(
|
||||
{
|
||||
tibiId: tibiId,
|
||||
bigCommerceId: bigCommerceId,
|
||||
check: key,
|
||||
},
|
||||
{
|
||||
secret: jwtSecret,
|
||||
validityDuration: 60 * 60 * 24 * 90, // 90 days
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function requestPasswordReset() {
|
||||
const random256BitString = Math.random().toString(36).substring(2, 34)
|
||||
const email = context.data.email
|
||||
if (!email) {
|
||||
throw {
|
||||
status: 400,
|
||||
message: "Email is required",
|
||||
}
|
||||
}
|
||||
let customer = context.db.find("bigCommerceCustomer", {
|
||||
filter: { email: email?.toLowerCase() },
|
||||
})[0]
|
||||
if (!customer) {
|
||||
const customerBigCommerce = getCustomerById(null, email)
|
||||
if (!customerBigCommerce) {
|
||||
throw {
|
||||
status: 404,
|
||||
message: "Customer not found",
|
||||
}
|
||||
}
|
||||
const username = customerBigCommerce.form_fields.find((field) => field.name === "username")?.value
|
||||
customer = context.db.create("bigCommerceCustomer", {
|
||||
bigCommerceId: customerBigCommerce.id,
|
||||
email: customerBigCommerce.email.toLowerCase(),
|
||||
username: username ? username?.toLowerCase() : Math.random().toString(36).substring(2, 15),
|
||||
})
|
||||
}
|
||||
|
||||
const pwResetToken = buildPwResetToken(customer.id, customer.bigCommerceId, random256BitString)
|
||||
const store = {
|
||||
logo: `${serverBaseURL}${logoPath}`,
|
||||
frontendBase,
|
||||
pwReset: `${frontendBase}profile/reset-password?token=${pwResetToken}`,
|
||||
}
|
||||
const html = context.tpl.execute(context.fs.readFile("templates/requestPWReset.html"), {
|
||||
store,
|
||||
})
|
||||
|
||||
context.smtp.sendMail({
|
||||
to: email,
|
||||
from: operatorEmail,
|
||||
fromName: "BinKrassDuFass",
|
||||
replyTo: noReplyEmail,
|
||||
subject: "Passwort Zurücksetzen",
|
||||
html,
|
||||
})
|
||||
context.db.update("bigCommerceCustomer", customer.id, {
|
||||
currentToken: random256BitString,
|
||||
})
|
||||
throw {
|
||||
status: 200,
|
||||
message: "Password reset email sent",
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
const { validateFields } = require("./validateFields")
|
||||
;(function () {
|
||||
if (context?.data?.formular?.honey) {
|
||||
throw { status: 400, error: "Bot detection" }
|
||||
}
|
||||
delete context.data.formular.honey
|
||||
/**
|
||||
* @type {Array<[string, FormObj]>}
|
||||
*/
|
||||
let values = Object.entries(context?.data?.formular)
|
||||
let validation = validateFields(values)
|
||||
if (validation.length) {
|
||||
throw { status: 400, error: validation }
|
||||
}
|
||||
})()
|
||||
@@ -1,79 +0,0 @@
|
||||
;(function () {
|
||||
/** @type {FormObj} */
|
||||
let formular = context?.data?.formular
|
||||
|
||||
/** @type {TempFormBefore | TempFormAfter} */
|
||||
let tempForm = {}
|
||||
|
||||
let formTitle = `${formular.formTitle}`
|
||||
delete formular.formTitle
|
||||
delete formular["agreement"]
|
||||
delete formular["honey"]
|
||||
|
||||
formular?.formRows?.forEach(
|
||||
/** @param {string} rowName */
|
||||
(rowName) => {
|
||||
tempForm[rowName] = {}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* @param {[string, any]} e
|
||||
* @returns {any}
|
||||
*/
|
||||
let getValue = (e) => {
|
||||
if (e[0].includes("numberLabel")) return e[1][0]
|
||||
return e[1]
|
||||
}
|
||||
|
||||
/** @type {TempFormIndices} */
|
||||
let indices = {}
|
||||
|
||||
Object.entries(formular).forEach((e) => {
|
||||
if (e[0] === "formRows") return
|
||||
|
||||
let key = e[0].split("_")
|
||||
let newKey = key[key.length - 1]
|
||||
|
||||
// @ts-ignore
|
||||
let rowName = formular?.formRows[Number(key[key.length - 2])]
|
||||
let index = isNaN(Number(key[key.length - 3])) ? 100 : Number(key[key.length - 3])
|
||||
|
||||
if (!rowName) return
|
||||
if (!tempForm[rowName]) tempForm[rowName] = {}
|
||||
|
||||
// @ts-ignore
|
||||
if (tempForm[rowName][newKey]) {
|
||||
// @ts-ignore
|
||||
tempForm[rowName][newKey][0] += "\\" + getValue(e)
|
||||
} else {
|
||||
// @ts-ignore
|
||||
tempForm[rowName][newKey] = [getValue(e), newKey[0] === "n", newKey.includes("invalid")]
|
||||
indices[rowName] = { ...indices[rowName], [newKey]: index }
|
||||
}
|
||||
})
|
||||
|
||||
// Now iterate over tempForm to sort fields in each row
|
||||
Object.entries(tempForm).forEach(([rowName, fields]) => {
|
||||
tempForm[rowName] = Object.entries(fields)
|
||||
.sort((a, b) => indices[rowName][a[0]] - indices[rowName][b[0]])
|
||||
.reduce((acc, [key, val]) => ({ ...acc, [key]: val }), {})
|
||||
})
|
||||
|
||||
Object.keys(tempForm).forEach((row) => {
|
||||
tempForm[row] = Object.entries(tempForm[row])
|
||||
})
|
||||
|
||||
// @ts-ignore
|
||||
delete tempForm[undefined]
|
||||
context.smtp.sendMail({
|
||||
to: "allkids.erfurt@gmail.com",
|
||||
from: "mail@webmakers.de",
|
||||
subject: "AllKids " + formTitle,
|
||||
html: context.tpl.execute(context.fs.readFile("templates/form_mail.html"), {
|
||||
context: context,
|
||||
formularRows: Object.entries(tempForm),
|
||||
formTitle: formTitle,
|
||||
}),
|
||||
})
|
||||
})()
|
||||
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
* @param {Array<[string, FormObj]>} fieldsArray
|
||||
* @returns {(string | (() => void))[][]}
|
||||
*/
|
||||
function validateFields(fieldsArray) {
|
||||
/**@type {(string | (() => void))[][]} */
|
||||
const errors = []
|
||||
/**@type {number} */
|
||||
let selectedGroup
|
||||
|
||||
const numberRegex = /^[+]?([.]\d+|\d+([.]\d+)?)$/
|
||||
const emailRegex =
|
||||
/(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/
|
||||
const dateRegex = /^\d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])$/
|
||||
const timeRegex = /^\d{1,2}:\d{2}-\d{1,2}:\d{2}$/
|
||||
const phoneRegex = /^\s*(?:\+?(\d{1,3}))?[-. (]*(\d{3})[-. )]*(\d{3})[-. ]*(\d{4})(?: *x(\d+))?\s*$/
|
||||
|
||||
const wholeBlockInvalid = () => {
|
||||
const blockContainer = document.getElementsByClassName("blockContainer")[0]
|
||||
blockContainer.classList.add("invalidBlocks")
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {any} field
|
||||
* @param {HTMLElement} element
|
||||
*/
|
||||
const validateNumber = (value, field, element) => {
|
||||
if (!numberRegex.test(`${value}`)) {
|
||||
errors.push(["block", () => element.classList.add("border-red")])
|
||||
}
|
||||
}
|
||||
|
||||
fieldsArray.forEach(([field, value]) => {
|
||||
if (field === "blockGroups" || field.includes("numberLabel")) {
|
||||
if (!field.includes("numberLabel")) return
|
||||
// @ts-ignore
|
||||
const [elementValue, element, group] = value
|
||||
|
||||
if (!elementValue) return
|
||||
|
||||
if (selectedGroup !== undefined) {
|
||||
if (group !== selectedGroup) {
|
||||
errors.push(["block", wholeBlockInvalid])
|
||||
} else {
|
||||
validateNumber(elementValue, field, element)
|
||||
}
|
||||
} else {
|
||||
selectedGroup = group
|
||||
validateNumber(elementValue, field, element)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
errors.push(["Eingabe ist erforderlich.", field])
|
||||
} else if (field.includes("number_")) {
|
||||
if (!numberRegex.test(`${value}`)) {
|
||||
errors.push(["Ungültiger numerischer Wert.", field])
|
||||
}
|
||||
} else if (field.includes("agreement_")) {
|
||||
if (value !== true) errors.push(["Bitte das Kontrollkästchen anklicken.", field])
|
||||
} else if (field.includes("Email_")) {
|
||||
if (!emailRegex.test(value)) errors.push(["Ungültiges E-Mail-Format.", field])
|
||||
} else if (field.includes("date_")) {
|
||||
if (!dateRegex.test(value)) errors.push(["Ungültiges Datumsformat.", field])
|
||||
} else if (field.includes("times_")) {
|
||||
if (!timeRegex.test(value)) errors.push(["Ungültiges Zeitformat.", field])
|
||||
} else if (field.includes("Telefon_")) {
|
||||
if (!phoneRegex.test(value)) errors.push(["Ungültiges Telefonnummernformat.", field])
|
||||
}
|
||||
})
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
validateFields,
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
var { setUpQuery, calculateAverageDynamically, run } = require("../lib/utils")
|
||||
;(function () {
|
||||
let subPaths = context.db.find("lighthouseSubpath")
|
||||
let urls = []
|
||||
for (let i = 0; i < subPaths.length; i++) {
|
||||
urls.push(setUpQuery(subPaths[i].lighthouseSubpath))
|
||||
}
|
||||
let dbObjs = []
|
||||
urls.forEach((url) => {
|
||||
console.log("URL:", url)
|
||||
dbObjs.push(run(url))
|
||||
})
|
||||
let dbObject = calculateAverageDynamically(dbObjs)
|
||||
dbObject.analyzedPaths = [...subPaths].map((subPath) => subPath.lighthouseSubpath)
|
||||
return { data: dbObject }
|
||||
})()
|
||||
@@ -1,160 +0,0 @@
|
||||
const { jwtSecret, jwtValidityDuration } = require("../config")
|
||||
const { validateCredentials, getCustomerById } = require("../lib/bigcommerceRestAPI")
|
||||
const { getRefreshToken, createTibiCustomer } = require("../lib/utils")
|
||||
|
||||
;(function () {
|
||||
function deleteRefreshTokenCookie() {
|
||||
context.cookie.set("bkdfRefreshToken", "", {
|
||||
maxAge: -1,
|
||||
httpOnly: true,
|
||||
path: "/api",
|
||||
})
|
||||
}
|
||||
|
||||
if (context.request().query("logout")) {
|
||||
deleteRefreshTokenCookie()
|
||||
throw {
|
||||
status: 200,
|
||||
message: "ok",
|
||||
log: false,
|
||||
}
|
||||
}
|
||||
context.data.email = context?.data?.email?.toLowerCase()
|
||||
const { email, password } = context.data
|
||||
let bigCommerceId
|
||||
|
||||
if (!email || !password) {
|
||||
const rT = getRefreshToken()
|
||||
console.log(JSON.stringify(rT), "refreshtoken")
|
||||
|
||||
if (rT) {
|
||||
/** @type {JWTRefreshClaims} */ // @ts-ignore
|
||||
const refreshClaims = rT.claims
|
||||
|
||||
if (!rT.valid) {
|
||||
throw {
|
||||
status: 403,
|
||||
error: "token: " + rT.error,
|
||||
log: false,
|
||||
}
|
||||
}
|
||||
|
||||
bigCommerceId = refreshClaims && refreshClaims.bigCommerceId
|
||||
if (!bigCommerceId) {
|
||||
deleteRefreshTokenCookie()
|
||||
throw {
|
||||
status: 403,
|
||||
error: "token: inavlid claims",
|
||||
log: false,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
deleteRefreshTokenCookie()
|
||||
throw {
|
||||
status: 403,
|
||||
error: "missing email and/or password",
|
||||
log: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {Customer[]} */ // @ts-ignore
|
||||
let [customer] = context.db.find("bigCommerceCustomer", {
|
||||
filter: bigCommerceId
|
||||
? { bigCommerceId }
|
||||
: {
|
||||
email,
|
||||
},
|
||||
})
|
||||
|
||||
if (!customer) {
|
||||
if (!bigCommerceId && email) {
|
||||
const customerByEmail = getCustomerById(undefined, email, true)
|
||||
if (customerByEmail) {
|
||||
createTibiCustomer(customerByEmail)
|
||||
;[customer] = context.db.find("bigCommerceCustomer", {
|
||||
filter: bigCommerceId
|
||||
? { bigCommerceId }
|
||||
: {
|
||||
email,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
deleteRefreshTokenCookie()
|
||||
throw {
|
||||
status: 403,
|
||||
error: "login failed",
|
||||
log: false,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
deleteRefreshTokenCookie()
|
||||
throw {
|
||||
status: 403,
|
||||
error: "login failed",
|
||||
log: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bigCommerceId) {
|
||||
// login via username/password
|
||||
const validate = validateCredentials(email, password)
|
||||
const passwordOK = validate.is_valid
|
||||
if (!passwordOK) {
|
||||
deleteRefreshTokenCookie()
|
||||
throw {
|
||||
status: 403,
|
||||
error: "login failed",
|
||||
log: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (customer.locked) {
|
||||
deleteRefreshTokenCookie()
|
||||
throw {
|
||||
status: 403,
|
||||
error: "customer locked",
|
||||
log: false,
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {JWTLoginClaims} */
|
||||
const loginClaims = {
|
||||
tibiId: customer.id,
|
||||
bigCommerceId: customer.bigCommerceId,
|
||||
email: customer.email,
|
||||
}
|
||||
|
||||
const token = context.jwt.create(loginClaims, {
|
||||
secret: jwtSecret,
|
||||
validityDuration: jwtValidityDuration,
|
||||
})
|
||||
|
||||
const refreshTokenMaxAge = 60 * 60 * 24 // 24h
|
||||
/** @type {JWTRefreshClaims} */
|
||||
const refreshClaims = {
|
||||
tibiId: customer.id,
|
||||
bigCommerceId: customer.bigCommerceId,
|
||||
r: 1,
|
||||
}
|
||||
const nextRefreshToken = context.jwt.create(refreshClaims, {
|
||||
secret: jwtSecret,
|
||||
validityDuration: refreshTokenMaxAge,
|
||||
})
|
||||
|
||||
context.cookie.set("bkdfRefreshToken", nextRefreshToken, {
|
||||
maxAge: refreshTokenMaxAge - 60 * 60, // 1h earlier expire
|
||||
httpOnly: true,
|
||||
path: "/api",
|
||||
})
|
||||
|
||||
throw {
|
||||
status: 200,
|
||||
customer,
|
||||
created: new Date(),
|
||||
token,
|
||||
log: false,
|
||||
}
|
||||
})()
|
||||
@@ -1,25 +0,0 @@
|
||||
const { withAccount } = require("../lib/utils")
|
||||
;(function () {
|
||||
if (context.user.auth()) return {}
|
||||
withAccount((login) => {
|
||||
const id = context.request().param("id")
|
||||
const user = context.db.find("bigCommerceCustomer", {
|
||||
filter: {
|
||||
$or: [
|
||||
{
|
||||
"personalRecords.recording": id,
|
||||
},
|
||||
{
|
||||
"personalRecords.thumbnail": id,
|
||||
},
|
||||
],
|
||||
},
|
||||
})[0]
|
||||
if (login.tibiId !== user.id) {
|
||||
return {
|
||||
status: 403,
|
||||
message: "You are not authorized to delete this media",
|
||||
}
|
||||
}
|
||||
})
|
||||
})()
|
||||
@@ -1,205 +0,0 @@
|
||||
const utils = require("../lib/utils")
|
||||
|
||||
const { release } = require("../config-client")
|
||||
|
||||
const { ssrValidatePath } = require("../config")
|
||||
const { ssrRequest, ssrRequestBigCommerce } = require("../lib/ssr-server")
|
||||
;(function () {
|
||||
var request = context.request()
|
||||
|
||||
var trackingCall = request.header("x-ssr-skip")
|
||||
if (trackingCall) {
|
||||
// skip tracking
|
||||
// no cache header
|
||||
context.response.header("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||
throw {
|
||||
status: parseInt(trackingCall),
|
||||
html: "",
|
||||
log: false,
|
||||
}
|
||||
}
|
||||
|
||||
let url = request.query("url") || request.header("x-ssr-url") || "/"
|
||||
const noCache = request.query("noCache")
|
||||
|
||||
const trace_id = context.debug.sentryTraceId()
|
||||
/**
|
||||
* @param {string} content
|
||||
*/
|
||||
function addSentryTrace(content) {
|
||||
return content.replace("</head>", '<meta name="sentry-trace" content="' + trace_id + '" /></head>')
|
||||
}
|
||||
|
||||
context.response.header("sentry-trace", trace_id)
|
||||
const auth = context.user.auth()
|
||||
if (auth && auth.role == 0) {
|
||||
} else if (url) {
|
||||
/** @type {Date} */ // @ts-ignore
|
||||
context.ssrCacheValidUntil = null
|
||||
|
||||
var comment = ""
|
||||
|
||||
url = url.split("?")[0]
|
||||
comment += "url: " + url
|
||||
|
||||
if (url && url.length > 1) {
|
||||
url = url.replace(/\/$/, "")
|
||||
}
|
||||
if (url == "/index" || !url) {
|
||||
url = "/" // see .htaccess
|
||||
}
|
||||
|
||||
function useCache(/** @type {string} */ _url) {
|
||||
var cache =
|
||||
!noCache &&
|
||||
context.db.find("ssr", {
|
||||
filter: {
|
||||
path: _url,
|
||||
},
|
||||
})
|
||||
|
||||
if (cache && cache.length) {
|
||||
// check that entry is still allowed to be published
|
||||
const validUntil = cache[0].validUntil ? new Date(cache[0].validUntil.unixMilli()) : null
|
||||
|
||||
if (!validUntil || validUntil > new Date()) {
|
||||
// use cache
|
||||
context.response.header("X-SSR-Cache", "true")
|
||||
throw {
|
||||
status: 200,
|
||||
log: false,
|
||||
html: addSentryTrace(cache[0].content),
|
||||
}
|
||||
} else {
|
||||
// cache is invalid, delete it
|
||||
context.response.header("X-SSR-Cache", "invalid")
|
||||
context.db.delete("ssr", cache[0].id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// validate url
|
||||
var status = 200
|
||||
|
||||
var pNorender = false
|
||||
var pNotfound = false
|
||||
|
||||
const pR = ssrValidatePath(url)
|
||||
if (pR === -1) {
|
||||
// pNotfound = true
|
||||
// comment += ", notFound"
|
||||
} else if (!pR) {
|
||||
pNorender = true
|
||||
comment += ", noRender"
|
||||
} else if (typeof pR === "string") {
|
||||
url = pR
|
||||
comment += ", cache url: " + url
|
||||
}
|
||||
|
||||
if (noCache) {
|
||||
comment += ", noCache"
|
||||
}
|
||||
|
||||
if (!pNorender && !pNotfound) {
|
||||
// check if we have a cache
|
||||
useCache(url)
|
||||
}
|
||||
|
||||
let head = ""
|
||||
let html = ""
|
||||
let error = ""
|
||||
|
||||
comment += ", path: " + url
|
||||
|
||||
var cacheIt = false
|
||||
if (pNorender) {
|
||||
html = "<!-- NO SSR RENDERING -->"
|
||||
} else if (pNotfound) {
|
||||
status = 404
|
||||
html = "404 NOT FOUND"
|
||||
} else {
|
||||
// @ts-ignore
|
||||
context.ssrCache = {}
|
||||
// @ts-ignore
|
||||
context.ssrRequest = ssrRequest
|
||||
// @ts-ignore
|
||||
context.ssrRequestBigCommerce = ssrRequestBigCommerce
|
||||
|
||||
try {
|
||||
// if error, output plain html without prerendering
|
||||
// @ts-ignore
|
||||
const app = require("../lib/app.server")
|
||||
|
||||
const rendered = app.default.render({
|
||||
url: url,
|
||||
})
|
||||
head = rendered.head
|
||||
html = rendered.html
|
||||
|
||||
head +=
|
||||
"\n\n" +
|
||||
"<script>window.__SSR_CACHE__ = " +
|
||||
// @ts-ignore
|
||||
JSON.stringify(context.ssrCache) +
|
||||
"</script>"
|
||||
|
||||
// status from webapp
|
||||
// @ts-ignore
|
||||
if (context.is404) {
|
||||
status = 404
|
||||
} else {
|
||||
cacheIt = true
|
||||
}
|
||||
} catch (/** @type {any} */ e) {
|
||||
utils.log(e.message)
|
||||
utils.log(e.stack)
|
||||
error = "error: " + e.message + "\n\n" + e.stack
|
||||
|
||||
// utils.log(e)
|
||||
// for (var property in e) {
|
||||
// utils.log(property + ": " + e[property])
|
||||
// }
|
||||
// error = JSON.stringify(e)
|
||||
}
|
||||
}
|
||||
|
||||
var tpl = context.fs.readFile("templates/spa.html")
|
||||
tpl = tpl.replace("<!--HEAD-->", head)
|
||||
tpl = tpl.replace("<!--HTML-->", html)
|
||||
tpl = tpl.replace("<!--SSR.ERROR-->", error ? "<!--" + error + "-->" : "")
|
||||
tpl = tpl.replace("<!--SSR.COMMENT-->", comment ? "<!--" + comment + "-->" : "")
|
||||
|
||||
if (cacheIt && !noCache) {
|
||||
// save cache
|
||||
const existing = context.db.find("ssr", {
|
||||
filter: {
|
||||
path: url,
|
||||
},
|
||||
})
|
||||
if (existing && existing.length) {
|
||||
context.db.delete("ssr", existing[0].id)
|
||||
}
|
||||
|
||||
context.db.create("ssr", {
|
||||
path: url,
|
||||
content: tpl,
|
||||
// @ts-ignore
|
||||
validUntil: context.ssrCacheValidUntil,
|
||||
})
|
||||
}
|
||||
|
||||
throw {
|
||||
status: status,
|
||||
log: false,
|
||||
html: addSentryTrace(tpl),
|
||||
}
|
||||
} else {
|
||||
// only admins are allowed
|
||||
throw {
|
||||
status: 403,
|
||||
message: "invalid auth",
|
||||
auth: auth,
|
||||
release: release,
|
||||
}
|
||||
}
|
||||
})()
|
||||
@@ -1,25 +0,0 @@
|
||||
const { release } = require("../config-client")
|
||||
var utils = require("../lib/utils")
|
||||
|
||||
;(function () {
|
||||
if (context.request().query("clear")) {
|
||||
console.log("CLEARING SSR CACHE")
|
||||
var removed = utils.clearSSRCache()
|
||||
var stats = {
|
||||
status: 200,
|
||||
message: "ok",
|
||||
removed: removed,
|
||||
release: release,
|
||||
}
|
||||
|
||||
utils.log(stats)
|
||||
|
||||
throw stats
|
||||
}
|
||||
|
||||
throw {
|
||||
status: 500,
|
||||
message: "ssr is only a dummy collection",
|
||||
release: release,
|
||||
}
|
||||
})()
|
||||
@@ -1,25 +0,0 @@
|
||||
const { bigcommerceApiOAuth, serverBaseURL, bigcommerceStoreHash } = require("../config.js")
|
||||
const { deletePrintfulWebhook } = require("../lib/printfulRestAPI.js")
|
||||
;(function () {
|
||||
const data = context.data
|
||||
if (context?.user?.auth()?.id) {
|
||||
const webhook = context.db.find("webhook", {
|
||||
filter: {
|
||||
_id: context.request().param("id"),
|
||||
},
|
||||
})[0]
|
||||
|
||||
if (webhook.type === "printful") {
|
||||
deletePrintfulWebhook(webhook.scope)
|
||||
} else {
|
||||
let url = `https://api.bigcommerce.com/stores/${bigcommerceStoreHash}/v3/hooks/${webhook.webhookId}`
|
||||
|
||||
let options = {
|
||||
method: "DELETE",
|
||||
headers: { "Content-Type": "application/json", "X-Auth-Token": bigcommerceApiOAuth },
|
||||
}
|
||||
|
||||
const response = context.http.fetch(url, options).body.json()
|
||||
}
|
||||
}
|
||||
})()
|
||||
@@ -1,266 +0,0 @@
|
||||
const { bigcommerceApiOAuth, serverBaseURL, bigcommerceStoreHash } = require("../config.js")
|
||||
let { clearSSRCache, createTibiCustomer, updateTibiCustomer } = require("../lib/utils")
|
||||
const {
|
||||
getProductImages,
|
||||
getOrderProductsById,
|
||||
getProductById,
|
||||
getCustomerById,
|
||||
getOrderById,
|
||||
createInternalOrderObject,
|
||||
} = require("../lib/bigcommerceRestAPI.js")
|
||||
const { createPrintfulWebhook, getPrintfulOrderShipments } = require("../lib/printfulRestAPI.js")
|
||||
const { postPurchase } = require("../lib/facebookRestAPI.js")
|
||||
;(function () {
|
||||
const data = context.data
|
||||
if (context?.user?.auth()?.id) {
|
||||
if (context.data.type === "printful") {
|
||||
createPrintfulWebhook(context.data.scope)
|
||||
return
|
||||
} else {
|
||||
let url = `https://api.bigcommerce.com/stores/${bigcommerceStoreHash}/v3/hooks`
|
||||
|
||||
let options = {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", "X-Auth-Token": bigcommerceApiOAuth },
|
||||
body: JSON.stringify({
|
||||
scope: context?.data?.scope,
|
||||
destination: `${serverBaseURL}webhook`,
|
||||
is_active: context?.data?.active,
|
||||
events_history_enabled: true,
|
||||
headers: { token: "super_secure_and_extremely_secret_big_commerce_webhook_token_123" },
|
||||
}),
|
||||
}
|
||||
|
||||
const response = context.http.fetch(url, options).body.json()
|
||||
const hookResponse = {
|
||||
data: context.data,
|
||||
}
|
||||
// @ts-ignore
|
||||
hookResponse.data.webhookId = response.data.id
|
||||
return hookResponse
|
||||
}
|
||||
}
|
||||
if (data) {
|
||||
if (data?.type === "order_updated") {
|
||||
const bigCommerceOrderId = data?.data?.order?.external_id
|
||||
const order = context.db.find("bigCommerceOrder", {
|
||||
filter: {
|
||||
bigCommerceId: Number(bigCommerceOrderId),
|
||||
},
|
||||
})[0]
|
||||
if (order) {
|
||||
context.db.update("bigCommerceOrder", order.id, {
|
||||
status: data?.data?.order?.status,
|
||||
statusSetAt: new Date().toISOString(),
|
||||
})
|
||||
}
|
||||
throw {
|
||||
status: 200,
|
||||
data: {
|
||||
message: "",
|
||||
},
|
||||
}
|
||||
} else if (data?.type == "shipment_sent") {
|
||||
const bigCommerceOrderId = data?.data?.order?.external_id
|
||||
|
||||
const printfulOrderShipments = getPrintfulOrderShipments(Number(bigCommerceOrderId))
|
||||
|
||||
const order = context.db.find("bigCommerceOrder", {
|
||||
filter: {
|
||||
bigCommerceId: Number(bigCommerceOrderId),
|
||||
},
|
||||
})[0]
|
||||
if (order) {
|
||||
context.db.update("bigCommerceOrder", order.id, {
|
||||
shipments: (printfulOrderShipments || []).map((shipped) => {
|
||||
return {
|
||||
trackingUrl: shipped.tracking_url,
|
||||
trackingNumber: data?.data?.shipment?.tracking_number,
|
||||
carrier: shipped.carrier,
|
||||
sentAt: new Date(),
|
||||
}
|
||||
}),
|
||||
})
|
||||
}
|
||||
throw {
|
||||
status: 200,
|
||||
data: {
|
||||
message: "",
|
||||
},
|
||||
}
|
||||
} else if (data?.scope?.includes("product")) {
|
||||
if (data.scope.includes("product/deleted")) {
|
||||
handleProductDeleted(data.data.id)
|
||||
clearSSRCache()
|
||||
} else {
|
||||
const product = getProductById(data?.data?.id)
|
||||
const productImage = getProductImages(data?.data?.id)
|
||||
|
||||
if (data.scope.includes("product/created") && product?.id) {
|
||||
handleProductCreateOrUpdate(product, productImage)
|
||||
}
|
||||
if (data.scope.includes("product/updated") && product?.id) {
|
||||
handleProductCreateOrUpdate(product, productImage)
|
||||
}
|
||||
clearSSRCache()
|
||||
}
|
||||
throw {
|
||||
status: 200,
|
||||
data: {
|
||||
message: "",
|
||||
},
|
||||
}
|
||||
} else if (data?.scope?.includes("order")) {
|
||||
if (data.scope.includes("order/statusUpdated")) {
|
||||
if (data.data.status.new_status_id == 11) {
|
||||
const internalOrderReference = createInternalOrderObject(data.data.id)
|
||||
// make sure the order doesn't already exist
|
||||
const orderExists = context.db.find("bigCommerceOrder", {
|
||||
filter: {
|
||||
bigCommerceId: Number(data.data.id),
|
||||
},
|
||||
})
|
||||
if (!orderExists.length) context.db.create("bigCommerceOrder", internalOrderReference)
|
||||
else context.db.update("bigCommerceOrder", orderExists[0].id, internalOrderReference)
|
||||
/*
|
||||
not necessary for now, as bigcommerce itself takes care of it
|
||||
try {
|
||||
if (!orderExists) {
|
||||
postPurchase(internalOrderReference.cost.replace(",", "."))
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}*/
|
||||
} else {
|
||||
const order = context.db.find("bigCommerceOrder", {
|
||||
filter: {
|
||||
bigCommerceId: data.data.id,
|
||||
},
|
||||
})[0]
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {any} orderStatus
|
||||
* @returns {PrintfulStates | false}
|
||||
*/
|
||||
function mapOrderStatusToPrintful(orderStatus) {
|
||||
switch (orderStatus.new_status_id) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 7:
|
||||
case 11:
|
||||
return "draft" // Unvollständig
|
||||
case 6:
|
||||
return "failed" // Abgelehnt
|
||||
case 10:
|
||||
return "fulfilled" // Versandt, Versand ausstehend, Abgeschlossen
|
||||
case 3:
|
||||
return "partial" // Teilweise Versandt, Teilweise erstattet
|
||||
case 12:
|
||||
case 13:
|
||||
return "onhold" // Manuelle Überprüfung erforderlich, Umstritten (closest match)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
if (order && mapOrderStatusToPrintful(data.data.status) !== false) {
|
||||
context.db.update("bigCommerceOrder", order.id, {
|
||||
status: mapOrderStatusToPrintful(data.data.status),
|
||||
statusSetAt: new Date().toISOString(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
throw {
|
||||
status: 200,
|
||||
data: {
|
||||
message: "",
|
||||
},
|
||||
}
|
||||
} else if (data?.scope?.includes("customer")) {
|
||||
let internalCustomer
|
||||
if (data.data?.id)
|
||||
/** @type {Customer} */
|
||||
internalCustomer =
|
||||
context.db.find("bigCommerceCustomer", {
|
||||
filter: {
|
||||
bigCommerceId: data.data.id,
|
||||
},
|
||||
})?.[0] || null
|
||||
|
||||
if (data.scope.includes("customer/deleted") && !!internalCustomer) {
|
||||
context.db.delete("bigCommerceCustomer", internalCustomer.id)
|
||||
} else {
|
||||
const customer = getCustomerById(data?.data?.id)
|
||||
|
||||
if (!internalCustomer && customer?.id) {
|
||||
createTibiCustomer(customer)
|
||||
} else if (data.scope.includes("customer/updated") && !!internalCustomer) {
|
||||
updateTibiCustomer(customer, internalCustomer)
|
||||
}
|
||||
}
|
||||
throw {
|
||||
status: 200,
|
||||
data: {
|
||||
message: "",
|
||||
},
|
||||
}
|
||||
} else
|
||||
throw {
|
||||
status: 403,
|
||||
error: "Forbidden",
|
||||
}
|
||||
} else
|
||||
throw {
|
||||
status: 403,
|
||||
error: "Forbidden",
|
||||
}
|
||||
})()
|
||||
|
||||
/**
|
||||
* Handles both product creation and update by checking if the product exists and then
|
||||
* creating or updating the record accordingly.
|
||||
*
|
||||
* @param {V2OrderProductsResponseBase} [product] The product data.
|
||||
* @param { ProductImage[]} [productImage] The product image data.
|
||||
*/
|
||||
function handleProductCreateOrUpdate(product, productImage) {
|
||||
const internalProduct =
|
||||
context.db.find("bigCommerceProduct", {
|
||||
filter: {
|
||||
bigCommerceId: Number(product?.id),
|
||||
},
|
||||
})?.[0] || null
|
||||
if (internalProduct) {
|
||||
// If the product exists, update it.
|
||||
context.db.update("bigCommerceProduct", internalProduct.id || "", {
|
||||
productName: product?.name_customer || product?.name,
|
||||
bigCommerceSKU: product?.sku,
|
||||
previewImage: productImage?.[0]?.url_thumbnail,
|
||||
bigCommerceId: Number(product?.id),
|
||||
})
|
||||
} else {
|
||||
// If the product does not exist, create it.
|
||||
context.db.create("bigCommerceProduct", {
|
||||
productName: product?.name_customer || product?.name,
|
||||
bigCommerceSKU: product?.sku,
|
||||
previewImage: productImage?.[0]?.url_thumbnail,
|
||||
bigCommerceId: Number(product?.id),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles product deletion by removing the product record if it exists.
|
||||
* @param { V2OrderProductsResponseBase } [id] The product data to delete.
|
||||
*/
|
||||
function handleProductDeleted(id) {
|
||||
const internalProduct = context.db.find("bigCommerceProduct", {
|
||||
filter: {
|
||||
bigCommerceId: Number(id),
|
||||
},
|
||||
})[0]
|
||||
if (internalProduct) {
|
||||
context.db.delete("bigCommerceProduct", internalProduct.id || "")
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
const { bigcommerceApiOAuth, serverBaseURL, bigcommerceStoreHash } = require("../config.js")
|
||||
;(function () {
|
||||
const data = context.data
|
||||
if (context?.user?.auth()?.id) {
|
||||
if (context.data.type === "printful") {
|
||||
throw {
|
||||
status: 500,
|
||||
message: "Printful webhooks update are not supported",
|
||||
}
|
||||
} else {
|
||||
let url = `https://api.bigcommerce.com/stores/${bigcommerceStoreHash}/v3/hooks/${context.data.webhookId}`
|
||||
|
||||
let options = {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json", "X-Auth-Token": bigcommerceApiOAuth },
|
||||
body: JSON.stringify({
|
||||
scope: context?.data?.scope,
|
||||
destination: `${serverBaseURL}webhook`,
|
||||
is_active: context?.data?.active,
|
||||
events_history_enabled: true,
|
||||
headers: { token: "super_secure_and_extremely_secret_big_commerce_webhook_token_123" },
|
||||
}),
|
||||
}
|
||||
|
||||
const response = context.http.fetch(url, options).body.json()
|
||||
}
|
||||
}
|
||||
})()
|
||||
Reference in New Issue
Block a user