258 lines
7.8 KiB
JavaScript
258 lines
7.8 KiB
JavaScript
/**
|
|
*
|
|
* @param {any} str
|
|
*/
|
|
function log(str) {
|
|
console.log(JSON.stringify(str, undefined, 4))
|
|
}
|
|
|
|
/**
|
|
* convert object to string
|
|
* @param {any} obj object
|
|
* @returns {Object | undefined}
|
|
*/
|
|
function obj2str(obj) {
|
|
if (Array.isArray(obj)) {
|
|
return JSON.stringify(
|
|
obj.map(function (idx) {
|
|
return obj2str(idx)
|
|
})
|
|
)
|
|
} else if (typeof obj === "object" && obj !== null) {
|
|
var elements = Object.keys(obj)
|
|
.sort()
|
|
.map(function (key) {
|
|
var val = obj2str(obj[key])
|
|
if (val) {
|
|
return key + ":" + val
|
|
}
|
|
})
|
|
|
|
var elementsCleaned = []
|
|
for (var i = 0; i < elements.length; i++) {
|
|
if (elements[i]) elementsCleaned.push(elements[i])
|
|
}
|
|
|
|
return "{" + elementsCleaned.join("|") + "}"
|
|
}
|
|
|
|
if (obj) return obj
|
|
}
|
|
var { LIGHTHOUSE_TOKEN } = require("../config")
|
|
|
|
/**
|
|
* clear SSR cache
|
|
*/
|
|
function clearSSRCache() {
|
|
var info = context.db.deleteMany("ssr", {})
|
|
context.response.header("X-SSR-Cleared", info.removed)
|
|
}
|
|
|
|
/**
|
|
* @param {{ [x: string]: any; }[]} dbObjs
|
|
*/
|
|
function calculateAverageDynamically(dbObjs) {
|
|
const sumObj = {}
|
|
let count = 0
|
|
|
|
dbObjs.forEach((/** @type {{ [x: string]: any; }} */ obj) => {
|
|
accumulate(obj, sumObj)
|
|
count++
|
|
})
|
|
|
|
/**
|
|
* @param {{ [x: string]: any; }} sourceObj
|
|
* @param {{ [x: string]: any; }} targetObj
|
|
*/
|
|
function accumulate(sourceObj, targetObj) {
|
|
for (const key in sourceObj) {
|
|
if (typeof sourceObj[key] === "number") {
|
|
targetObj[key] = (targetObj[key] || 0) + sourceObj[key]
|
|
} else if (typeof sourceObj[key] === "object" && sourceObj[key] !== null) {
|
|
targetObj[key] = targetObj[key] || {}
|
|
accumulate(sourceObj[key], targetObj[key])
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {{ [x: string]: any; }} targetObj
|
|
*/
|
|
function average(targetObj) {
|
|
for (const key in targetObj) {
|
|
if (typeof targetObj[key] === "number") {
|
|
targetObj[key] = targetObj[key] / count
|
|
} else if (typeof targetObj[key] === "object") {
|
|
average(targetObj[key])
|
|
}
|
|
}
|
|
}
|
|
|
|
average(sumObj)
|
|
return sumObj
|
|
}
|
|
|
|
/**
|
|
* @param {string} url
|
|
*/
|
|
function run(url) {
|
|
const response = context.http
|
|
.fetch(url, {
|
|
timeout: 300,
|
|
method: "GET",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
})
|
|
.body.json()
|
|
// needs enough traffic to be collected
|
|
const cruxMetrics = {
|
|
"First Contentful Paint": response?.loadingExperience?.metrics?.FIRST_CONTENTFUL_PAINT_MS?.category,
|
|
"First Input Delay": response?.loadingExperience?.metrics?.FIRST_INPUT_DELAY_MS?.category,
|
|
}
|
|
const lighthouse = response.lighthouseResult
|
|
const lighthouseMetrics = {
|
|
FCPS: lighthouse.audits["first-contentful-paint"].score * 100,
|
|
FCPV: lighthouse.audits["first-contentful-paint"].numericValue / 1000,
|
|
FMPS: lighthouse.audits["first-meaningful-paint"].score * 100,
|
|
FMPV: lighthouse.audits["first-meaningful-paint"].numericValue / 1000,
|
|
|
|
SIS: lighthouse.audits["speed-index"].score * 100,
|
|
SIV: lighthouse.audits["speed-index"].numericValue / 1000,
|
|
TTIS: lighthouse.audits["interactive"].score * 100,
|
|
TTIV: lighthouse.audits["interactive"].numericValue / 1000,
|
|
|
|
FPIDS: lighthouse.audits["max-potential-fid"].score * 100,
|
|
FPIDV: lighthouse.audits["max-potential-fid"].numericValue / 1000,
|
|
}
|
|
|
|
let dbObject = {
|
|
cruxMetrics,
|
|
lighthouseMetrics,
|
|
performance: Math.round(lighthouse.categories.performance.score * 100),
|
|
accessibility: Math.round(lighthouse.categories.accessibility.score * 100),
|
|
bestPractices: Math.round(lighthouse.categories["best-practices"].score * 100),
|
|
seo: Math.round(lighthouse.categories.seo.score * 100),
|
|
}
|
|
return dbObject
|
|
}
|
|
function setUpQuery(subPath = "/") {
|
|
const api = "https://www.googleapis.com/pagespeedonline/v5/runPagespeed"
|
|
let params = `category=performance&category=accessibility&category=best-practices&category=seo`
|
|
|
|
const parameters = {
|
|
url: encodeURIComponent(`https://allkids-erfurt.de/${subPath}`),
|
|
key: LIGHTHOUSE_TOKEN,
|
|
}
|
|
|
|
let query = `${api}?`
|
|
for (let key in parameters) {
|
|
// @ts-ignore
|
|
query += `${key}=${parameters[key]}&`
|
|
}
|
|
query += params // Append other parameters without URL encoding
|
|
return query
|
|
}
|
|
|
|
/**@param {LocalProduct} product */
|
|
function recalcRatingToProduct(product) {
|
|
let ratings = context.db.find("rating", {
|
|
filter: {
|
|
productId: product.id,
|
|
status: "approved",
|
|
},
|
|
})
|
|
|
|
let ratingSum = ratings.map((e) => e.rating).reduce((accumulator, currentValue) => accumulator + currentValue, 0)
|
|
let ratingAverage = (ratingSum || 0) / (ratings.length || 1)
|
|
if (isNaN(ratingAverage)) return
|
|
context.db.update("bigCommerceProducts", product.id, {
|
|
amountOfRatings: ratings.length,
|
|
averageRating: ratingAverage,
|
|
})
|
|
|
|
// clear ssr cache because of product update
|
|
clearSSRCache()
|
|
}
|
|
/**
|
|
*
|
|
* @param {HookContext} c
|
|
* @param {string} filename
|
|
* @param {string} locale
|
|
* @returns {string}
|
|
*/
|
|
function tpl(c, filename, locale) {
|
|
return c.tpl.execute(c.fs.readFile(filename), {
|
|
context: c,
|
|
config: config,
|
|
})
|
|
}
|
|
var config = require("../config")
|
|
function sendOperatorRatingMail() {
|
|
if (!context.data) context.data = {}
|
|
let locale = context.request().query("locale")
|
|
locale = locale ? locale : "de-DE"
|
|
let order = context.db.find("order", {
|
|
filter: {
|
|
_id: context.data.order,
|
|
},
|
|
})[0]
|
|
context.data.order = order
|
|
context.data.tibiLink = `project/${context.project().id}/collection/rating/edit/${context.data.id}` //projekt ID
|
|
context.smtp.sendMail({
|
|
to: config.operatorEmail,
|
|
from: config.operatorEmail,
|
|
fromName: config.operatorName,
|
|
subject: tpl(context, "templates/operator_rating_subject.de-DE.txt", locale),
|
|
html: tpl(context, "templates/operator_rating_body.de-DE.html", locale),
|
|
})
|
|
}
|
|
|
|
/**@param {ProductRating} currentRating */
|
|
function validateAndModifyRating(currentRating) {
|
|
// Fetch the rating object from the database
|
|
|
|
/** @type {ProductRating} */ // @ts-ignore
|
|
let oldRating = context.db.find("rating", {
|
|
filter: { orderId: currentRating.orderId, productId: currentRating.productId },
|
|
})[0]
|
|
|
|
if (oldRating && (oldRating.status != "pending" || currentRating.status != "pending")) {
|
|
//@ts-ignore
|
|
oldRating.review_date = convertDateToUTCISO(oldRating.review_date)
|
|
if (oldRating.status == "pending") {
|
|
oldRating.status = currentRating.status
|
|
if (currentRating.status == "approved") return currentRating
|
|
}
|
|
|
|
return context?.user?.auth()?.id &&
|
|
(currentRating?.status == "pending" || currentRating?.status == "rejected") &&
|
|
(oldRating?.status == "approved" || oldRating?.status == "rejected")
|
|
? currentRating
|
|
: oldRating
|
|
}
|
|
|
|
// If the status of the current rating is 'pending', or not provided
|
|
if (currentRating.status == "pending" || !currentRating.status) {
|
|
currentRating.status = "pending"
|
|
if (!currentRating.review_date) {
|
|
//@ts-ignore
|
|
currentRating.review_date = new Date().toISOString()
|
|
}
|
|
}
|
|
|
|
return currentRating
|
|
}
|
|
|
|
module.exports = {
|
|
log,
|
|
clearSSRCache,
|
|
obj2str,
|
|
run,
|
|
setUpQuery,
|
|
calculateAverageDynamically,
|
|
recalcRatingToProduct,
|
|
sendOperatorRatingMail,
|
|
validateAndModifyRating,
|
|
}
|