1
0
Fork 0
impress-2020/src/server/util.js
Emi Matchu dc954d7c3c Stop referencing the {color,species,zone}_translations tables
We're in the process of migrating away from translating these records,
because Neopets hasn't supported non-English languages in many years,
and it'll simplify our code and database lookups.

In Main DTI, we already wrote code to copy these fields onto the main
records and keep them in sync for now; now, once DTI 2020 isn't
referencing them anymore, it should be safe for the main app to drop
the tables altogether.

Note that some Prettier changes got mixed in here and that's fine!

I also wasn't suuuper careful testing these, most of them seem to be
trivially testable by just loading the homepage or doing a few basic
wardrobe actions, and the others are in Discord support log actions
that aren't enabled in development mode, so I'm just like… ehh I'll do
a couple support actions after deploy and see that they don't crash!
2024-02-03 08:05:15 -08:00

154 lines
4.4 KiB
JavaScript

import beeline from "honeycomb-beeline";
import fetch from "node-fetch";
function capitalize(str) {
return str[0].toUpperCase() + str.slice(1);
}
function getPoseFromPetState(petState) {
const { moodId, female, unconverted } = petState;
if (unconverted) {
return "UNCONVERTED";
} else if (moodId == null || female == null) {
return "UNKNOWN";
} else if (String(moodId) === "1" && String(female) === "0") {
return "HAPPY_MASC";
} else if (String(moodId) === "1" && String(female) === "1") {
return "HAPPY_FEM";
} else if (String(moodId) === "2" && String(female) === "0") {
return "SAD_MASC";
} else if (String(moodId) === "2" && String(female) === "1") {
return "SAD_FEM";
} else if (String(moodId) === "4" && String(female) === "0") {
return "SICK_MASC";
} else if (String(moodId) === "4" && String(female) === "1") {
return "SICK_FEM";
} else {
throw new Error(
`could not identify pose: ` +
`moodId=${moodId}, ` +
`female=${female}, ` +
`unconverted=${unconverted}`,
);
}
}
function getPetStateFieldsFromPose(pose) {
if (pose === "UNCONVERTED") {
return { moodId: null, female: null, unconverted: true, labeled: true };
} else if (pose === "UNKNOWN") {
return { moodId: null, female: null, unconverted: false, labeled: false };
} else if (pose === "HAPPY_MASC") {
return { moodId: "1", female: false, unconverted: false, labeled: true };
} else if (pose === "HAPPY_FEM") {
return { moodId: "1", female: true, unconverted: false, labeled: true };
} else if (pose === "SAD_MASC") {
return { moodId: "2", female: false, unconverted: false, labeled: true };
} else if (pose === "SAD_FEM") {
return { moodId: "2", female: true, unconverted: false, labeled: true };
} else if (pose === "SICK_MASC") {
return { moodId: "4", female: false, unconverted: false, labeled: true };
} else if (pose === "SICK_FEM") {
return { moodId: "4", female: true, unconverted: false, labeled: true };
} else {
throw new Error(`unexpected pose ${pose}`);
}
}
const POSE_NAMES = {
HAPPY_MASC: "Happy Masc",
SAD_MASC: "Sad Masc",
SICK_MASC: "Sick Masc",
HAPPY_FEM: "Happy Fem",
SAD_FEM: "Sad Fem",
SICK_FEM: "Sick Fem",
UNCONVERTED: "Unconverted",
UNKNOWN: "Unknown",
};
function getPoseName(pose) {
return POSE_NAMES[pose];
}
function getRestrictedZoneIds(zonesRestrict) {
const restrictedZoneIds = [];
for (const [i, bit] of Array.from(zonesRestrict).entries()) {
if (bit === "1") {
restrictedZoneIds.push(i + 1);
}
}
return restrictedZoneIds;
}
async function loadBodyName(bodyId, db) {
if (String(bodyId) === "0") {
return "All bodies";
}
const [rows] = await db.execute(
`SELECT pt.body_id, s.name AS species_name,
c.name AS color_name, c.standard FROM pet_types pt
INNER JOIN species s ON pt.species_id = s.id
INNER JOIN colors c ON c.id = pt.color_id
WHERE pt.body_id = ?
ORDER BY c.standard DESC, color_name, species_name LIMIT 1;`,
[bodyId],
);
const row = normalizeRow(rows[0]);
const speciesName = capitalize(row.speciesName);
const colorName = row.standard ? "Standard" : capitalize(row.colorName);
return `${colorName} ${speciesName}`;
}
async function logToDiscord(body) {
const span = beeline.startSpan({ name: "logToDiscord" });
try {
const res = await fetch(process.env["SUPPORT_TOOLS_DISCORD_WEBHOOK_URL"], {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!res.ok) {
const resText = await res.text();
throw new Error(
`Discord returned ${res.status} ${res.statusText}: ${resText}`,
);
}
} finally {
beeline.finishSpan(span);
}
}
function normalizeRow(row) {
const normalizedRow = {};
for (let [key, value] of Object.entries(row)) {
key = key.replace(/_([a-z])/gi, (m) => m[1].toUpperCase());
if ((key === "id" || key.endsWith("Id")) && typeof value === "number") {
value = String(value);
}
normalizedRow[key] = value;
}
return normalizedRow;
}
module.exports = {
capitalize,
getPoseFromPetState,
getPetStateFieldsFromPose,
getPoseName,
getRestrictedZoneIds,
loadBodyName,
logToDiscord,
normalizeRow,
// For Apollo's @cacheControl maxAge: time in seconds.
oneWeek: 604800,
oneDay: 86400,
oneHour: 3600,
oneMinute: 60,
};