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!
This commit is contained in:
Emi Matchu 2024-02-03 08:05:15 -08:00
parent 4e1739cd16
commit dc954d7c3c
13 changed files with 188 additions and 477 deletions

View file

@ -23,7 +23,7 @@ if (
) {
throw new Error(
`must provide DTI_AWS_ACCESS_KEY_ID and DTI_AWS_SECRET_ACCESS_KEY ` +
`environment variables`
`environment variables`,
);
}
@ -87,7 +87,7 @@ async function handle(req, res) {
const { layerId } = req.query;
const [layerRows] = await db.execute(
`SELECT * FROM swf_assets WHERE id = ?`,
[layerId]
[layerId],
);
const layer = normalizeRow(layerRows[0]);
if (!layer) {
@ -105,7 +105,7 @@ async function handle(req, res) {
const [result] = await db.execute(
`UPDATE swf_assets SET image_manual = 1, converted_at = ?
WHERE type = ? AND remote_id = ? LIMIT 1`,
[now, assetType, remoteId]
[now, assetType, remoteId],
);
if (result.affectedRows !== 1) {
res
@ -115,30 +115,22 @@ async function handle(req, res) {
if (process.env["SUPPORT_TOOLS_DISCORD_WEBHOOK_URL"]) {
try {
const {
itemLoader,
itemTranslationLoader,
zoneTranslationLoader,
} = buildLoaders(db);
const { itemLoader, itemTranslationLoader, zoneLoader } =
buildLoaders(db);
// Copied from setLayerBodyId mutation
const itemId = await db
.execute(
`SELECT parent_id FROM parents_swf_assets
WHERE swf_asset_id = ? AND parent_type = "Item" LIMIT 1;`,
[layerId]
[layerId],
)
.then(([rows]) => normalizeRow(rows[0]).parentId);
const [
item,
itemTranslation,
zoneTranslation,
bodyName,
] = await Promise.all([
const [item, itemTranslation, zone, bodyName] = await Promise.all([
itemLoader.load(itemId),
itemTranslationLoader.load(itemId),
zoneTranslationLoader.load(layer.zoneId),
zoneLoader.load(layer.zoneId),
loadBodyName(layer.bodyId, db),
]);
@ -153,7 +145,7 @@ async function handle(req, res) {
},
fields: [
{
name: `Layer ${layerId} (${zoneTranslation.label})`,
name: `Layer ${layerId} (${zone.label})`,
value: `🎨 Uploaded new PNG for ${bodyName}`,
},
],
@ -173,7 +165,7 @@ async function handle(req, res) {
async function handleWithBeeline(req, res) {
beeline.withTrace(
{ name: "api/uploadLayerImage", operation_name: "api/uploadLayerImage" },
() => handle(req, res)
() => handle(req, res),
);
}

View file

@ -1,5 +1,4 @@
yarn run --silent mysqldump openneo_impress species species_translations colors \
color_translations zones zone_translations \
yarn run --silent mysqldump openneo_impress species colors zones \
> $(dirname $0)/../public-data-constants.sql \
&& yarn run --silent mysqldump openneo_impress alt_styles items item_translations \
parents_swf_assets pet_states pet_types swf_assets \

View file

@ -1,7 +1,6 @@
yarn run --silent mysqldump --no-data openneo_impress closet_hangers closet_lists \
colors color_translations items item_translations modeling_logs \
parents_swf_assets pet_types pet_states species species_translations \
swf_assets users zones zone_translations \
colors items item_translations modeling_logs parents_swf_assets pet_types \
pet_states species swf_assets users zones \
| \
sed 's/ AUTO_INCREMENT=[0-9]*//g' \
> $(dirname $0)/../schema-for-impress.sql \

File diff suppressed because one or more lines are too long

View file

@ -57,4 +57,4 @@ CREATE TABLE `users` (
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2024-02-01 2:00:53
-- Dump completed on 2024-02-03 7:55:56

View file

@ -79,26 +79,6 @@ CREATE TABLE `colors` (
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `color_translations`
--
DROP TABLE IF EXISTS `color_translations`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `color_translations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`color_id` int(11) DEFAULT NULL,
`locale` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_color_translations_on_color_id` (`color_id`),
KEY `index_color_translations_on_locale` (`locale`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `items`
--
@ -249,26 +229,6 @@ CREATE TABLE `species` (
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `species_translations`
--
DROP TABLE IF EXISTS `species_translations`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `species_translations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`species_id` int(11) DEFAULT NULL,
`locale` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_species_translations_on_species_id` (`species_id`),
KEY `index_species_translations_on_locale` (`locale`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `swf_assets`
--
@ -342,27 +302,6 @@ CREATE TABLE `zones` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `zone_translations`
--
DROP TABLE IF EXISTS `zone_translations`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `zone_translations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`zone_id` int(11) DEFAULT NULL,
`locale` varchar(255) DEFAULT NULL,
`label` varchar(255) DEFAULT NULL,
`plain_label` varchar(255) DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_zone_translations_on_zone_id` (`zone_id`),
KEY `index_zone_translations_on_locale` (`locale`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
@ -373,4 +312,4 @@ CREATE TABLE `zone_translations` (
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2024-02-01 2:00:51
-- Dump completed on 2024-02-03 7:55:53

View file

@ -4,7 +4,6 @@ USE openneo_impress;
GRANT SELECT ON alt_styles TO impress2020;
GRANT SELECT ON campaigns TO impress2020;
GRANT SELECT ON colors TO impress2020;
GRANT SELECT ON color_translations TO impress2020;
GRANT SELECT ON donation_features TO impress2020;
GRANT SELECT ON donations TO impress2020;
GRANT SELECT ON items TO impress2020;
@ -14,10 +13,8 @@ GRANT SELECT ON parents_swf_assets TO impress2020;
GRANT SELECT ON pet_types TO impress2020;
GRANT SELECT ON pet_states TO impress2020;
GRANT SELECT ON species TO impress2020;
GRANT SELECT ON species_translations TO impress2020;
GRANT SELECT ON swf_assets TO impress2020;
GRANT SELECT ON zones TO impress2020;
GRANT SELECT ON zone_translations TO impress2020;
-- Public data tables: write. Used in modeling and support tools.
GRANT INSERT, UPDATE ON items TO impress2020;

View file

@ -88,25 +88,6 @@ const buildColorLoader = (db) => {
return colorLoader;
};
const buildColorTranslationLoader = (db) =>
new DataLoader(async (colorIds) => {
const qs = colorIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM color_translations
WHERE color_id IN (${qs}) AND locale = "en"`,
colorIds,
);
const entities = rows.map(normalizeRow);
const entitiesByColorId = new Map(entities.map((e) => [e.colorId, e]));
return colorIds.map(
(colorId) =>
entitiesByColorId.get(String(colorId)) ||
new Error(`could not find translation for color ${colorId}`),
);
});
const buildSpeciesLoader = (db) => {
const speciesLoader = new DataLoader(async (speciesIds) => {
const qs = speciesIds.map((_) => "?").join(",");
@ -139,25 +120,6 @@ const buildSpeciesLoader = (db) => {
return speciesLoader;
};
const buildSpeciesTranslationLoader = (db) =>
new DataLoader(async (speciesIds) => {
const qs = speciesIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM species_translations
WHERE species_id IN (${qs}) AND locale = "en"`,
speciesIds,
);
const entities = rows.map(normalizeRow);
const entitiesBySpeciesId = new Map(entities.map((e) => [e.speciesId, e]));
return speciesIds.map(
(speciesId) =>
entitiesBySpeciesId.get(String(speciesId)) ||
new Error(`could not find translation for species ${speciesId}`),
);
});
const buildTradeMatchesLoader = (db) =>
new DataLoader(
async (userPairs) => {
@ -1487,24 +1449,6 @@ const buildZoneLoader = (db) => {
return zoneLoader;
};
const buildZoneTranslationLoader = (db) =>
new DataLoader(async (zoneIds) => {
const qs = zoneIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM zone_translations WHERE zone_id IN (${qs}) AND locale = "en"`,
zoneIds,
);
const entities = rows.map(normalizeRow);
const entitiesByZoneId = new Map(entities.map((e) => [e.zoneId, e]));
return zoneIds.map(
(zoneId) =>
entitiesByZoneId.get(String(zoneId)) ||
new Error(`could not find translation for zone ${zoneId}`),
);
});
function buildLoaders(db) {
const loaders = {};
loaders.loadAllPetTypes = loadAllPetTypes(db);
@ -1514,7 +1458,6 @@ function buildLoaders(db) {
loaders.closetHangersForDefaultListLoader =
buildClosetHangersForDefaultListLoader(db);
loaders.colorLoader = buildColorLoader(db);
loaders.colorTranslationLoader = buildColorTranslationLoader(db);
loaders.itemLoader = buildItemLoader(db);
loaders.itemTranslationLoader = buildItemTranslationLoader(db);
loaders.itemByNameLoader = buildItemByNameLoader(db, loaders);
@ -1563,7 +1506,6 @@ function buildLoaders(db) {
loaders.petStateByPetTypeAndAssetsLoader =
buildPetStateByPetTypeAndAssetsLoader(db, loaders);
loaders.speciesLoader = buildSpeciesLoader(db);
loaders.speciesTranslationLoader = buildSpeciesTranslationLoader(db);
loaders.tradeMatchesLoader = buildTradeMatchesLoader(db);
loaders.userLoader = buildUserLoader(db);
loaders.userByNameLoader = buildUserByNameLoader(db);
@ -1575,7 +1517,6 @@ function buildLoaders(db) {
loaders.userOutfitsLoader = buildUserOutfitsLoader(db, loaders);
loaders.userLastTradeActivityLoader = buildUserLastTradeActivityLoader(db);
loaders.zoneLoader = buildZoneLoader(db);
loaders.zoneTranslationLoader = buildZoneTranslationLoader(db);
return loaders;
}

View file

@ -104,22 +104,20 @@ const resolvers = {
setManualSpecialColor: async (
_,
{ itemId, colorId, supportSecret },
{ itemLoader, itemTranslationLoader, colorTranslationLoader, db }
{ itemLoader, itemTranslationLoader, colorLoader, db },
) => {
assertSupportSecretOrThrow(supportSecret);
const oldItem = await itemLoader.load(itemId);
const [
result,
] = await db.execute(
const [result] = await db.execute(
`UPDATE items SET manual_special_color_id = ? WHERE id = ? LIMIT 1`,
[colorId, itemId]
[colorId, itemId],
);
if (result.affectedRows !== 1) {
throw new Error(
`Expected to affect 1 item, but affected ${result.affectedRows}`
`Expected to affect 1 item, but affected ${result.affectedRows}`,
);
}
@ -127,25 +125,19 @@ const resolvers = {
if (process.env["SUPPORT_TOOLS_DISCORD_WEBHOOK_URL"]) {
try {
const [
itemTranslation,
oldColorTranslation,
newColorTranslation,
] = await Promise.all([
const [itemTranslation, oldColor, newColor] = await Promise.all([
itemTranslationLoader.load(itemId),
oldItem.manualSpecialColorId
? colorTranslationLoader.load(oldItem.manualSpecialColorId)
: Promise.resolve(null),
colorId
? colorTranslationLoader.load(colorId)
? colorLoader.load(oldItem.manualSpecialColorId)
: Promise.resolve(null),
colorId ? colorLoader.load(colorId) : Promise.resolve(null),
]);
const oldColorName = oldColorTranslation
? capitalize(oldColorTranslation.name)
const oldColorName = oldColor
? capitalize(oldColor.name)
: "Auto-detect";
const newColorName = newColorTranslation
? capitalize(newColorTranslation.name)
const newColorName = newColor
? capitalize(newColor.name)
: "Auto-detect";
await logToDiscord({
embeds: [
@ -180,22 +172,20 @@ const resolvers = {
setItemExplicitlyBodySpecific: async (
_,
{ itemId, explicitlyBodySpecific, supportSecret },
{ itemLoader, itemTranslationLoader, db }
{ itemLoader, itemTranslationLoader, db },
) => {
assertSupportSecretOrThrow(supportSecret);
const oldItem = await itemLoader.load(itemId);
const [
result,
] = await db.execute(
const [result] = await db.execute(
`UPDATE items SET explicitly_body_specific = ? WHERE id = ? LIMIT 1`,
[explicitlyBodySpecific ? 1 : 0, itemId]
[explicitlyBodySpecific ? 1 : 0, itemId],
);
if (result.affectedRows !== 1) {
throw new Error(
`Expected to affect 1 item, but affected ${result.affectedRows}`
`Expected to affect 1 item, but affected ${result.affectedRows}`,
);
}
@ -243,22 +233,20 @@ const resolvers = {
setItemIsManuallyNc: async (
_,
{ itemId, isManuallyNc, supportSecret },
{ itemLoader, itemTranslationLoader, db }
{ itemLoader, itemTranslationLoader, db },
) => {
assertSupportSecretOrThrow(supportSecret);
const oldItem = await itemLoader.load(itemId);
const [
result,
] = await db.execute(
const [result] = await db.execute(
`UPDATE items SET is_manually_nc = ? WHERE id = ? LIMIT 1`,
[isManuallyNc ? 1 : 0, itemId]
[isManuallyNc ? 1 : 0, itemId],
);
if (result.affectedRows !== 1) {
throw new Error(
`Expected to affect 1 item, but affected ${result.affectedRows}`
`Expected to affect 1 item, but affected ${result.affectedRows}`,
);
}
@ -306,20 +294,14 @@ const resolvers = {
setLayerBodyId: async (
_,
{ layerId, bodyId, supportSecret },
{
itemLoader,
itemTranslationLoader,
swfAssetLoader,
zoneTranslationLoader,
db,
}
{ itemLoader, itemTranslationLoader, swfAssetLoader, zoneLoader, db },
) => {
assertSupportSecretOrThrow(supportSecret);
const oldSwfAsset = await swfAssetLoader.load(layerId);
if (!oldSwfAsset) {
console.warn(
`Skipping setLayerBodyId for unknown layer ID: ${layerId}`
`Skipping setLayerBodyId for unknown layer ID: ${layerId}`,
);
return null;
}
@ -328,21 +310,19 @@ const resolvers = {
if (oldSwfAsset.bodyId === bodyId) {
console.info(
`Skipping setLayerBodyId for ${layerId}: no change. ` +
`(bodyId=${oldSwfAsset.bodyId})`
`(bodyId=${oldSwfAsset.bodyId})`,
);
return { id: layerId };
}
const [
result,
] = await db.execute(
const [result] = await db.execute(
`UPDATE swf_assets SET body_id = ? WHERE id = ? LIMIT 1`,
[bodyId, layerId]
[bodyId, layerId],
);
if (result.affectedRows !== 1) {
throw new Error(
`Expected to affect 1 layer, but affected ${result.affectedRows}`
`Expected to affect 1 layer, but affected ${result.affectedRows}`,
);
}
@ -354,23 +334,18 @@ const resolvers = {
.execute(
`SELECT parent_id FROM parents_swf_assets
WHERE swf_asset_id = ? AND parent_type = "Item" LIMIT 1;`,
[layerId]
[layerId],
)
.then(([rows]) => normalizeRow(rows[0]).parentId);
const [
item,
itemTranslation,
zoneTranslation,
oldBodyName,
newBodyName,
] = await Promise.all([
itemLoader.load(itemId),
itemTranslationLoader.load(itemId),
zoneTranslationLoader.load(oldSwfAsset.zoneId),
loadBodyName(oldSwfAsset.bodyId, db),
loadBodyName(bodyId, db),
]);
const [item, itemTranslation, zone, oldBodyName, newBodyName] =
await Promise.all([
itemLoader.load(itemId),
itemTranslationLoader.load(itemId),
zoneLoader.load(oldSwfAsset.zoneId),
loadBodyName(oldSwfAsset.bodyId, db),
loadBodyName(bodyId, db),
]);
await logToDiscord({
embeds: [
@ -384,7 +359,7 @@ const resolvers = {
fields: [
{
name:
`Layer ${layerId} (${zoneTranslation.label}): ` +
`Layer ${layerId} (${zone.label}): ` +
`Pet compatibility`,
value: `${oldBodyName} → **${newBodyName}**`,
},
@ -411,20 +386,20 @@ const resolvers = {
itemLoader,
itemTranslationLoader,
swfAssetLoader,
zoneTranslationLoader,
zoneLoader,
petStateLoader,
petTypeLoader,
colorTranslationLoader,
speciesTranslationLoader,
colorLoader,
speciesLoader,
db,
}
},
) => {
assertSupportSecretOrThrow(supportSecret);
const oldSwfAsset = await swfAssetLoader.load(layerId);
if (!oldSwfAsset) {
console.warn(
`Skipping setLayerKnownGlitches for unknown layer ID: ${layerId}`
`Skipping setLayerKnownGlitches for unknown layer ID: ${layerId}`,
);
return null;
}
@ -435,21 +410,19 @@ const resolvers = {
if (oldSwfAsset.knownGlitches === newKnownGlitchesString) {
console.info(
`Skipping setLayerKnownGlitches for ${layerId}: no change. ` +
`(knownGlitches=${oldSwfAsset.knownGlitches})`
`(knownGlitches=${oldSwfAsset.knownGlitches})`,
);
return { id: layerId };
}
const [
result,
] = await db.execute(
const [result] = await db.execute(
`UPDATE swf_assets SET known_glitches = ? WHERE id = ? LIMIT 1`,
[newKnownGlitchesString, layerId]
[newKnownGlitchesString, layerId],
);
if (result.affectedRows !== 1) {
throw new Error(
`Expected to affect 1 layer, but affected ${result.affectedRows}`
`Expected to affect 1 layer, but affected ${result.affectedRows}`,
);
}
@ -461,15 +434,15 @@ const resolvers = {
.execute(
`SELECT parent_type, parent_id FROM parents_swf_assets
WHERE swf_asset_id = ? LIMIT 1;`,
[layerId]
[layerId],
)
.then(([rows]) => normalizeRow(rows[0]));
if (parentType === "Item") {
const [item, itemTranslation, zoneTranslation] = await Promise.all([
const [item, itemTranslation, zone] = await Promise.all([
itemLoader.load(parentId),
itemTranslationLoader.load(parentId),
zoneTranslationLoader.load(oldSwfAsset.zoneId),
zoneLoader.load(oldSwfAsset.zoneId),
]);
await logToDiscord({
@ -484,8 +457,7 @@ const resolvers = {
fields: [
{
name:
`Layer ${layerId} (${zoneTranslation.label}): ` +
`Known glitches`,
`Layer ${layerId} (${zone.label}): ` + `Known glitches`,
value: `${oldSwfAsset.knownGlitches || "<none>"} → **${
newKnownGlitchesString || "<none>"
}**`,
@ -499,18 +471,14 @@ const resolvers = {
} else if (parentType === "PetState") {
const petState = await petStateLoader.load(parentId);
const petType = await petTypeLoader.load(petState.petTypeId);
const [
colorTranslation,
speciesTranslation,
zoneTranslation,
] = await Promise.all([
colorTranslationLoader.load(petType.colorId),
speciesTranslationLoader.load(petType.speciesId),
zoneTranslationLoader.load(oldSwfAsset.zoneId),
const [color, species, zone] = await Promise.all([
colorLoader.load(petType.colorId),
speciesLoader.load(petType.speciesId),
zoneLoader.load(oldSwfAsset.zoneId),
]);
const colorName = capitalize(colorTranslation.name);
const speciesName = capitalize(speciesTranslation.name);
const colorName = capitalize(color.name);
const speciesName = capitalize(species.name);
const pose = getPoseFromPetState(petState);
await logToDiscord({
@ -526,7 +494,7 @@ const resolvers = {
},
fields: [
{
name: `Appearance ${petState.id}, Layer ${layerId} (${zoneTranslation.label}): Known glitches`,
name: `Appearance ${petState.id}, Layer ${layerId} (${zone.label}): Known glitches`,
value: `${oldSwfAsset.knownGlitches || "<none>"} → **${
newKnownGlitchesString || "<none>"
}**`,
@ -539,7 +507,7 @@ const resolvers = {
});
} else {
console.error(
`Error building Discord support log: unexpected parent type ${parentType}`
`Error building Discord support log: unexpected parent type ${parentType}`,
);
}
} catch (e) {
@ -555,14 +523,14 @@ const resolvers = {
bulkAddLayersToItem: async (
_,
{ itemId, entries, supportSecret },
{ itemLoader, itemTranslationLoader, db }
{ itemLoader, itemTranslationLoader, db },
) => {
assertSupportSecretOrThrow(supportSecret);
const item = await itemLoader.load(itemId);
if (!item) {
console.warn(
`Skipping removeLayerFromItem for unknown item ID: ${itemId}`
`Skipping removeLayerFromItem for unknown item ID: ${itemId}`,
);
return null;
}
@ -585,7 +553,7 @@ const resolvers = {
swf_asset_id = ?
)
`,
[itemId, layerId, itemId, layerId]
[itemId, layerId, itemId, layerId],
),
]);
};
@ -629,13 +597,7 @@ const resolvers = {
removeLayerFromItem: async (
_,
{ layerId, itemId, supportSecret },
{
itemLoader,
itemTranslationLoader,
swfAssetLoader,
zoneTranslationLoader,
db,
}
{ itemLoader, itemTranslationLoader, swfAssetLoader, zoneLoader, db },
) => {
assertSupportSecretOrThrow(supportSecret);
@ -645,12 +607,12 @@ const resolvers = {
`DELETE FROM parents_swf_assets ` +
`WHERE swf_asset_id = ? AND parent_type = "Item" AND parent_id = ? ` +
`LIMIT 1`,
[layerId, itemId]
[layerId, itemId],
);
if (result.affectedRows !== 1) {
throw new Error(
`Expected to affect 1 layer, but affected ${result.affectedRows}`
`Expected to affect 1 layer, but affected ${result.affectedRows}`,
);
}
@ -658,15 +620,10 @@ const resolvers = {
if (process.env["SUPPORT_TOOLS_DISCORD_WEBHOOK_URL"]) {
try {
const [
item,
itemTranslation,
zoneTranslation,
bodyName,
] = await Promise.all([
const [item, itemTranslation, zone, bodyName] = await Promise.all([
itemLoader.load(itemId),
itemTranslationLoader.load(itemId),
zoneTranslationLoader.load(oldSwfAsset.zoneId),
zoneLoader.load(oldSwfAsset.zoneId),
loadBodyName(oldSwfAsset.bodyId, db),
]);
@ -681,7 +638,7 @@ const resolvers = {
},
fields: [
{
name: `Layer ${layerId} (${zoneTranslation.label})`,
name: `Layer ${layerId} (${zone.label})`,
value: `❌ Removed from ${bodyName}`,
},
],
@ -703,34 +660,24 @@ const resolvers = {
setPetAppearancePose: async (
_,
{ appearanceId, pose, supportSecret },
{
colorTranslationLoader,
speciesTranslationLoader,
petStateLoader,
petTypeLoader,
db,
}
{ colorLoader, speciesLoader, petStateLoader, petTypeLoader, db },
) => {
assertSupportSecretOrThrow(supportSecret);
const oldPetState = await petStateLoader.load(appearanceId);
const {
moodId,
female,
unconverted,
labeled,
} = getPetStateFieldsFromPose(pose);
const { moodId, female, unconverted, labeled } =
getPetStateFieldsFromPose(pose);
const [result] = await db.execute(
`UPDATE pet_states SET mood_id = ?, female = ?, unconverted = ?,
labeled = ? WHERE id = ? LIMIT 1`,
[moodId, female, unconverted, labeled, appearanceId]
[moodId, female, unconverted, labeled, appearanceId],
);
if (result.affectedRows !== 1) {
throw new Error(
`Expected to affect 1 layer, but affected ${result.affectedRows}`
`Expected to affect 1 layer, but affected ${result.affectedRows}`,
);
}
@ -740,14 +687,14 @@ const resolvers = {
if (process.env["SUPPORT_TOOLS_DISCORD_WEBHOOK_URL"]) {
try {
const petType = await petTypeLoader.load(oldPetState.petTypeId);
const [colorTranslation, speciesTranslation] = await Promise.all([
colorTranslationLoader.load(petType.colorId),
speciesTranslationLoader.load(petType.speciesId),
const [color, species] = await Promise.all([
colorLoader.load(petType.colorId),
speciesLoader.load(petType.speciesId),
]);
const oldPose = getPoseFromPetState(oldPetState);
const colorName = capitalize(colorTranslation.name);
const speciesName = capitalize(speciesTranslation.name);
const colorName = capitalize(color.name);
const speciesName = capitalize(species.name);
await logToDiscord({
embeds: [
@ -784,28 +731,20 @@ const resolvers = {
setPetAppearanceIsGlitched: async (
_,
{ appearanceId, isGlitched, supportSecret },
{
colorTranslationLoader,
speciesTranslationLoader,
petStateLoader,
petTypeLoader,
db,
}
{ colorLoader, speciesLoader, petStateLoader, petTypeLoader, db },
) => {
assertSupportSecretOrThrow(supportSecret);
const oldPetState = await petStateLoader.load(appearanceId);
const [
result,
] = await db.execute(
const [result] = await db.execute(
`UPDATE pet_states SET glitched = ? WHERE id = ? LIMIT 1`,
[isGlitched, appearanceId]
[isGlitched, appearanceId],
);
if (result.affectedRows !== 1) {
throw new Error(
`Expected to affect 1 layer, but affected ${result.affectedRows}`
`Expected to affect 1 layer, but affected ${result.affectedRows}`,
);
}
@ -815,13 +754,13 @@ const resolvers = {
if (process.env["SUPPORT_TOOLS_DISCORD_WEBHOOK_URL"]) {
try {
const petType = await petTypeLoader.load(oldPetState.petTypeId);
const [colorTranslation, speciesTranslation] = await Promise.all([
colorTranslationLoader.load(petType.colorId),
speciesTranslationLoader.load(petType.speciesId),
const [color, species] = await Promise.all([
colorLoader.load(petType.colorId),
speciesLoader.load(petType.speciesId),
]);
const colorName = capitalize(colorTranslation.name);
const speciesName = capitalize(speciesTranslation.name);
const colorName = capitalize(color.name);
const speciesName = capitalize(species.name);
const pose = getPoseFromPetState(oldPetState);
const oldGlitchinessState =
@ -863,7 +802,7 @@ const resolvers = {
setUsername: async (
_,
{ userId, newUsername, supportSecret },
{ userLoader, db }
{ userLoader, db },
) => {
assertSupportSecretOrThrow(supportSecret);
@ -881,18 +820,18 @@ const resolvers = {
UPDATE users SET name = ? WHERE id = ? LIMIT 1;
UPDATE openneo_id.users SET name = ? WHERE id = ? LIMIT 1;
`,
[newUsername, userId, newUsername, oldUser.remoteId]
[newUsername, userId, newUsername, oldUser.remoteId],
);
if (result1.affectedRows !== 1) {
throw new Error(
`[UPDATE 1] Expected to affect 1 user, but affected ${result1.affectedRows}`
`[UPDATE 1] Expected to affect 1 user, but affected ${result1.affectedRows}`,
);
}
if (result2.affectedRows !== 1) {
throw new Error(
`[UPDATE 2] Expected to affect 1 user, but affected ${result2.affectedRows}`
`[UPDATE 2] Expected to affect 1 user, but affected ${result2.affectedRows}`,
);
}
@ -907,7 +846,7 @@ const resolvers = {
try {
await getAuth0().users.update(
{ id: `auth0|impress-${userId}` },
{ username: newUsername }
{ username: newUsername },
);
} catch (error) {
if (error.statusCode === 404) {
@ -938,8 +877,7 @@ const resolvers = {
const auth0WarningFields = auth0Warning
? [
{
name:
"⚠ Auth0 warning, update skipped (maybe they weren't imported?)",
name: "⚠ Auth0 warning, update skipped (maybe they weren't imported?)",
value: auth0Warning.message,
},
]

View file

@ -136,14 +136,14 @@ const typeDefs = gql`
const resolvers = {
Color: {
name: async ({ id }, _, { colorTranslationLoader }) => {
name: async ({ id }, _, { colorLoader }) => {
// TODO: Add colorId=0 to the database? Pets on Neopets.com can have it.
if (id === "0") {
return "Unknown";
}
const colorTranslation = await colorTranslationLoader.load(id);
return capitalize(colorTranslation.name);
const color = await colorLoader.load(id);
return capitalize(color.name);
},
isStandard: async ({ id }, _, { colorLoader }) => {
// TODO: Add colorId=0 to the database? Pets on Neopets.com can have it.
@ -157,7 +157,7 @@ const resolvers = {
appliedToAllCompatibleSpecies: async (
{ id },
_,
{ petTypesForColorLoader }
{ petTypesForColorLoader },
) => {
const petTypes = await petTypesForColorLoader.load(id);
const speciesColorPairs = petTypes.map((petType) => ({ id: petType.id }));
@ -166,15 +166,15 @@ const resolvers = {
},
Species: {
name: async ({ id }, _, { speciesTranslationLoader }) => {
const speciesTranslation = await speciesTranslationLoader.load(id);
return capitalize(speciesTranslation.name);
name: async ({ id }, _, { speciesLoader }) => {
const species = await speciesLoader.load(id);
return capitalize(species.name);
},
canonicalAppearance: async (
{ id, species },
{ preferredColorId },
{ petTypeBySpeciesAndColorLoader, canonicalPetStateForBodyLoader }
{ petTypeBySpeciesAndColorLoader, canonicalPetStateForBodyLoader },
) => {
const petType = await petTypeBySpeciesAndColorLoader.load({
speciesId: id,
@ -221,7 +221,7 @@ const resolvers = {
withColor: async (
{ id },
{ colorId },
{ petTypeBySpeciesAndColorLoader }
{ petTypeBySpeciesAndColorLoader },
) => {
const petType = await petTypeBySpeciesAndColorLoader.load({
speciesId: id,
@ -244,7 +244,7 @@ const resolvers = {
}
throw new Error(
"HACK: We populate this when you look up a canonicalAppearance, but " +
"don't have a direct query for it yet, oops!"
"don't have a direct query for it yet, oops!",
);
},
representsAllBodies: ({ id }) => {
@ -253,7 +253,7 @@ const resolvers = {
canonicalAppearance: async (
{ id, species },
{ preferredColorId },
{ canonicalPetStateForBodyLoader }
{ canonicalPetStateForBodyLoader },
) => {
const petState = await canonicalPetStateForBodyLoader.load({
bodyId: id,
@ -331,7 +331,7 @@ const resolvers = {
canonicalAppearance: async (
{ id },
_,
{ petTypeLoader, canonicalPetStateForBodyLoader }
{ petTypeLoader, canonicalPetStateForBodyLoader },
) => {
const petType = await petTypeLoader.load(id);
@ -386,7 +386,7 @@ const resolvers = {
petAppearance: async (
_,
{ speciesId, colorId, pose },
{ petTypeBySpeciesAndColorLoader, petStatesForPetTypeLoader }
{ petTypeBySpeciesAndColorLoader, petStatesForPetTypeLoader },
) => {
const petType = await petTypeBySpeciesAndColorLoader.load({
speciesId,
@ -409,7 +409,7 @@ const resolvers = {
petAppearances: async (
_,
{ speciesId, colorId },
{ petTypeBySpeciesAndColorLoader, petStatesForPetTypeLoader }
{ petTypeBySpeciesAndColorLoader, petStatesForPetTypeLoader },
) => {
const petType = await petTypeBySpeciesAndColorLoader.load({
speciesId,
@ -421,7 +421,7 @@ const resolvers = {
speciesColorPairsThatNeedSupportLabeling: async (
_,
__,
{ db, petTypeLoader }
{ db, petTypeLoader },
) => {
const [rows] = await db.query(
`
@ -443,7 +443,7 @@ const resolvers = {
AND (unconverted = 0 OR unconverted IS NULL)
AND glitched = 0
) >= 1;
`
`,
);
const petTypes = rows.map(normalizeRow);
@ -458,61 +458,61 @@ const resolvers = {
// NOTE: This matches the colors on ItemPage, so that they always match!
const colors = { BLUE: "8", RED: "61", GREEN: "34", YELLOW: "84" };
const FALLBACK_COLOR_IDS = {
"1": colors.GREEN, // Acara
"2": colors.BLUE, // Aisha
"3": colors.YELLOW, // Blumaroo
"4": colors.YELLOW, // Bori
"5": colors.YELLOW, // Bruce
"6": colors.YELLOW, // Buzz
"7": colors.RED, // Chia
"8": colors.YELLOW, // Chomby
"9": colors.GREEN, // Cybunny
"10": colors.YELLOW, // Draik
"11": colors.RED, // Elephante
"12": colors.RED, // Eyrie
"13": colors.GREEN, // Flotsam
"14": colors.YELLOW, // Gelert
"15": colors.BLUE, // Gnorbu
"16": colors.BLUE, // Grarrl
"17": colors.GREEN, // Grundo
"18": colors.RED, // Hissi
"19": colors.GREEN, // Ixi
"20": colors.YELLOW, // Jetsam
"21": colors.GREEN, // Jubjub
"22": colors.YELLOW, // Kacheek
"23": colors.BLUE, // Kau
"24": colors.GREEN, // Kiko
"25": colors.GREEN, // Koi
"26": colors.RED, // Korbat
"27": colors.BLUE, // Kougra
"28": colors.BLUE, // Krawk
"29": colors.YELLOW, // Kyrii
"30": colors.YELLOW, // Lenny
"31": colors.YELLOW, // Lupe
"32": colors.BLUE, // Lutari
"33": colors.YELLOW, // Meerca
"34": colors.GREEN, // Moehog
"35": colors.BLUE, // Mynci
"36": colors.BLUE, // Nimmo
"37": colors.YELLOW, // Ogrin
"38": colors.RED, // Peophin
"39": colors.GREEN, // Poogle
"40": colors.RED, // Pteri
"41": colors.YELLOW, // Quiggle
"42": colors.BLUE, // Ruki
"43": colors.RED, // Scorchio
"44": colors.YELLOW, // Shoyru
"45": colors.RED, // Skeith
"46": colors.YELLOW, // Techo
"47": colors.BLUE, // Tonu
"48": colors.YELLOW, // Tuskaninny
"49": colors.GREEN, // Uni
"50": colors.RED, // Usul
"55": colors.YELLOW, // Vandagyre
"51": colors.YELLOW, // Wocky
"52": colors.RED, // Xweetok
"53": colors.RED, // Yurble
"54": colors.BLUE, // Zafara
1: colors.GREEN, // Acara
2: colors.BLUE, // Aisha
3: colors.YELLOW, // Blumaroo
4: colors.YELLOW, // Bori
5: colors.YELLOW, // Bruce
6: colors.YELLOW, // Buzz
7: colors.RED, // Chia
8: colors.YELLOW, // Chomby
9: colors.GREEN, // Cybunny
10: colors.YELLOW, // Draik
11: colors.RED, // Elephante
12: colors.RED, // Eyrie
13: colors.GREEN, // Flotsam
14: colors.YELLOW, // Gelert
15: colors.BLUE, // Gnorbu
16: colors.BLUE, // Grarrl
17: colors.GREEN, // Grundo
18: colors.RED, // Hissi
19: colors.GREEN, // Ixi
20: colors.YELLOW, // Jetsam
21: colors.GREEN, // Jubjub
22: colors.YELLOW, // Kacheek
23: colors.BLUE, // Kau
24: colors.GREEN, // Kiko
25: colors.GREEN, // Koi
26: colors.RED, // Korbat
27: colors.BLUE, // Kougra
28: colors.BLUE, // Krawk
29: colors.YELLOW, // Kyrii
30: colors.YELLOW, // Lenny
31: colors.YELLOW, // Lupe
32: colors.BLUE, // Lutari
33: colors.YELLOW, // Meerca
34: colors.GREEN, // Moehog
35: colors.BLUE, // Mynci
36: colors.BLUE, // Nimmo
37: colors.YELLOW, // Ogrin
38: colors.RED, // Peophin
39: colors.GREEN, // Poogle
40: colors.RED, // Pteri
41: colors.YELLOW, // Quiggle
42: colors.BLUE, // Ruki
43: colors.RED, // Scorchio
44: colors.YELLOW, // Shoyru
45: colors.RED, // Skeith
46: colors.YELLOW, // Techo
47: colors.BLUE, // Tonu
48: colors.YELLOW, // Tuskaninny
49: colors.GREEN, // Uni
50: colors.RED, // Usul
55: colors.YELLOW, // Vandagyre
51: colors.YELLOW, // Wocky
52: colors.RED, // Xweetok
53: colors.RED, // Yurble
54: colors.BLUE, // Zafara
};
module.exports = { typeDefs, resolvers };

View file

@ -23,9 +23,9 @@ const resolvers = {
const zone = await zoneLoader.load(id);
return zone.depth;
},
label: async ({ id }, _, { zoneTranslationLoader }) => {
const zoneTranslation = await zoneTranslationLoader.load(id);
return zoneTranslation.label;
label: async ({ id }, _, { zoneLoader }) => {
const zone = await zoneLoader.load(id);
return zone.label;
},
isCommonlyUsedByItems: async ({ id }, _, { zoneLoader }) => {
// Zone metadata marks item zones with types 2, 3, and 4. But also, in

View file

@ -29,7 +29,7 @@ function getPoseFromPetState(petState) {
`could not identify pose: ` +
`moodId=${moodId}, ` +
`female=${female}, ` +
`unconverted=${unconverted}`
`unconverted=${unconverted}`,
);
}
}
@ -87,16 +87,13 @@ async function loadBodyName(bodyId, db) {
}
const [rows] = await db.execute(
`SELECT pt.body_id, st.name AS species_name,
ct.name AS color_name, c.standard FROM pet_types pt
INNER JOIN species_translations st
ON pt.species_id = st.species_id AND st.locale = "en"
INNER JOIN color_translations ct
ON pt.color_id = ct.color_id AND ct.locale = "en"
`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, ct.name, st.name LIMIT 1;`,
[bodyId]
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);
@ -119,7 +116,7 @@ async function logToDiscord(body) {
if (!res.ok) {
const resText = await res.text();
throw new Error(
`Discord returned ${res.status} ${res.statusText}: ${resText}`
`Discord returned ${res.status} ${res.statusText}: ${resText}`,
);
}
} finally {