From 8aa0130ea391083862b77544b9162c2e8b6d1a2f Mon Sep 17 00:00:00 2001 From: "Alex Pooley (@zuedev)" Date: Sat, 18 Jul 2026 14:20:06 +0100 Subject: add more population commands --- 174bg/discord-bot/commands/pocketbase.js | 341 ++++++++++++++++++++++++++----- 1 file changed, 291 insertions(+), 50 deletions(-) diff --git a/174bg/discord-bot/commands/pocketbase.js b/174bg/discord-bot/commands/pocketbase.js index 8b97822..91b35c3 100644 --- a/174bg/discord-bot/commands/pocketbase.js +++ b/174bg/discord-bot/commands/pocketbase.js @@ -16,6 +16,21 @@ export default { .setName("uex_items") .setDescription("Populates the uex_items collection with data from the bot's UEX cache.") ) + .addSubcommand((subcommand) => + subcommand + .setName("uex_space_stations") + .setDescription("Populates the uex_space_stations collection with data from the bot's UEX cache.") + ) + .addSubcommand((subcommand) => + subcommand + .setName("uex_points_of_interest") + .setDescription("Populates the uex_points_of_interest collection with data from the bot's UEX cache.") + ) + .addSubcommand((subcommand) => + subcommand + .setName("inventory_locations") + .setDescription("Populates the inventory_locations collection with data from the bot's UEX cache.") + ) ), execute: async (interaction) => { // only zuedev can run any of these commands @@ -28,64 +43,290 @@ export default { const subcommand = interaction.options.getSubcommand(); if (subcommandGroup === "populate") { - if (subcommand === "uex_items") { - const pb = new PocketBase(process.env.POCKETBASE_URL); - pb.authStore.save(process.env.POCKETBASE_AUTH_TOKEN, null); + switch (subcommand) { + case "uex_items": + populateUexItems(interaction); + break; + case "uex_space_stations": + populateUexSpaceStations(interaction); + break; + case "uex_points_of_interest": + populateUexPointsOfInterest(interaction); + break; + case "inventory_locations": + populateInventoryLocations(interaction); + break; + } + } + }, +}; + +async function populateUexItems(interaction) { + const pb = new PocketBase(process.env.POCKETBASE_URL); + pb.authStore.save(process.env.POCKETBASE_AUTH_TOKEN, null); + + const items = uex.items ?? []; - interaction.reply({ - content: `Populating uex_items collection with ${uex.items.length} items...`, + interaction.reply({ + content: `Populating uex_items collection with ${items.length} items...`, + ephemeral: true, + }); + + let ops = 0; + let failed = 0; + let updates = 0; + let creates = 0; + + for (const item of items) { + try { + // does it already exist? + const existingItem = await pb.collection("uex_items").getFullList({ + filter: `id="${item.id}"`, + }); + + if (existingItem.length > 0) { + // compare times to see if we need to update + // example pocketbase: "2026-07-18 12:30:02.405Z" + // example uex: 1746219762 + if (new Date(existingItem[0].updated).getTime() < item.updated * 1000) { + await pb.collection("uex_items").update(existingItem[0].id, { + name: item.name, + }); + updates++; + } + } else { + await pb.collection("uex_items").create({ + id: item.id, + name: item.name, + }); + creates++; + } + ops++; + + // update the interaction every 1000 operations to avoid timeout + if (ops % 1000 === 0) { + interaction.editReply({ + content: `Populating uex_items collection with ${items.length} items... (${ops} processed, ${updates} updated, ${creates} created, ${failed} failed)`, ephemeral: true, }); + } + } catch (error) { + console.error(`Failed to create item ${item.name}:`, error); + failed++; + } + } + + interaction.editReply({ + content: `Successfully populated uex_items collection with ${items.length} items. (${ops} processed, ${updates} updated, ${creates} created, ${failed} failed)`, + ephemeral: true, + }); +} + +async function populateUexSpaceStations(interaction) { + const pb = new PocketBase(process.env.POCKETBASE_URL); + pb.authStore.save(process.env.POCKETBASE_AUTH_TOKEN, null); + + const stations = uex.space_stations ?? []; + + interaction.reply({ + content: `Populating uex_space_stations collection with ${stations.length} stations...`, + ephemeral: true, + }); + + let ops = 0; + let failed = 0; + let updates = 0; + let creates = 0; - let ops = 0; - let failed = 0; - let updates = 0; - let creates = 0; - - for (const item of uex.items) { - try { - // does it already exist? - const existingItem = await pb.collection("uex_items").getFullList({ - filter: `id="${item.id}"`, - }); - - if (existingItem.length > 0) { - // compare times to see if we need to update - // example pocketbase: "2026-07-18 12:30:02.405Z" - // example uex: 1746219762 - if (new Date(existingItem[0].updated).getTime() < item.updated * 1000) { - await pb.collection("uex_items").update(existingItem[0].id, { - name: item.name, - }); - updates++; - } - } else { - await pb.collection("uex_items").create({ - id: item.id, - name: item.name, - }); - creates++; - } - ops++; - - // update the interaction every 1000 operations to avoid timeout - if (ops % 1000 === 0) { - interaction.editReply({ - content: `Populating uex_items collection with ${uex.items.length} items... (${ops} processed, ${updates} updated, ${creates} created, ${failed} failed)`, - ephemeral: true, - }); - } - } catch (error) { - console.error(`Failed to create item ${item.name}:`, error); - failed++; - } + for (const station of stations) { + try { + // does it already exist? + const existingStation = await pb.collection("uex_space_stations").getFullList({ + filter: `id="${station.id}"`, + }); + + if (existingStation.length > 0) { + // compare times to see if we need to update + // example pocketbase: "2026-07-18 12:30:02.405Z" + // example uex: 1746219762 + if (new Date(existingStation[0].updated).getTime() < station.updated * 1000) { + await pb.collection("uex_space_stations").update(existingStation[0].id, { + name: station.name, + }); + updates++; } + } else { + await pb.collection("uex_space_stations").create({ + id: station.id, + name: station.name, + }); + creates++; + } + ops++; + // update the interaction every 1000 operations to avoid timeout + if (ops % 1000 === 0) { interaction.editReply({ - content: `Successfully populated uex_items collection with ${uex.items.length} items. (${ops} processed, ${updates} updated, ${creates} created, ${failed} failed)`, + content: `Populating uex_space_stations collection with ${stations.length} stations... (${ops} processed, ${updates} updated, ${creates} created, ${failed} failed)`, ephemeral: true, }); } + } catch (error) { + console.error(`Failed to create space station ${station.name}:`, error); + failed++; } - }, -}; + } + + interaction.editReply({ + content: `Successfully populated uex_space_stations collection with ${stations.length} stations. (${ops} processed, ${updates} updated, ${creates} created, ${failed} failed)`, + ephemeral: true, + }); +} + +async function populateUexPointsOfInterest(interaction) { + const pb = new PocketBase(process.env.POCKETBASE_URL); + pb.authStore.save(process.env.POCKETBASE_AUTH_TOKEN, null); + + const pointsOfInterest = uex.points_of_interest ?? []; + + interaction.reply({ + content: `Populating uex_points_of_interest collection with ${pointsOfInterest.length} points of interest...`, + ephemeral: true, + }); + + let ops = 0; + let failed = 0; + let updates = 0; + let creates = 0; + + for (const point of pointsOfInterest) { + try { + // does it already exist? + const existingPoint = await pb.collection("uex_points_of_interest").getFullList({ + filter: `name="${point.name}"`, + }); + + if (existingPoint.length > 0) { + await pb.collection("uex_points_of_interest").update(existingPoint[0].id, { + name: point.name, + }); + updates++; + } else { + await pb.collection("uex_points_of_interest").create({ + id: point.id, + name: point.name, + }); + creates++; + } + ops++; + + // update the interaction every 1000 operations to avoid timeout + if (ops % 1000 === 0) { + interaction.editReply({ + content: `Populating uex_points_of_interest collection with ${pointsOfInterest.length} points of interest... (${ops} processed, ${updates} updated, ${creates} created, ${failed} failed)`, + ephemeral: true, + }); + } + } catch (error) { + console.error(`Failed to create point of interest ${point.name}:`, error); + failed++; + } + } + + interaction.editReply({ + content: `Successfully populated uex_points_of_interest collection with ${pointsOfInterest.length} points of interest. (${ops} processed, ${updates} updated, ${creates} created, ${failed} failed)`, + ephemeral: true, + }); +} + +async function populateInventoryLocations(interaction) { + const pb = new PocketBase(process.env.POCKETBASE_URL); + pb.authStore.save(process.env.POCKETBASE_AUTH_TOKEN, null); + + const stations = uex.space_stations ?? []; + const pointsOfInterest = uex.points_of_interest ?? []; + + // merge + dedupe by name (case-insensitive) + const locationMap = new Map(); + + for (const station of stations) { + if (!station?.name) continue; + const key = station.name.trim().toLowerCase(); + locationMap.set(key, { + id: station.id, + name: station.name, + updated: station.updated ?? 0, + }); + } + + for (const point of pointsOfInterest) { + if (!point?.name) continue; + const key = point.name.trim().toLowerCase(); + const existing = locationMap.get(key); + + // keep whichever has the newest timestamp when duplicates exist + if (!existing || (point.updated ?? 0) > (existing.updated ?? 0)) { + locationMap.set(key, { + id: point.id, + name: point.name, + updated: point.updated ?? 0, + }); + } + } + + const locations = Array.from(locationMap.values()); + + interaction.reply({ + content: `Populating inventory_locations collection with ${locations.length} locations...`, + ephemeral: true, + }); + + let ops = 0; + let failed = 0; + let updates = 0; + let creates = 0; + + for (const location of locations) { + try { + const safeName = String(location.name).replaceAll('"', '\\"'); + + const existingLocation = await pb.collection("inventory_locations").getFullList({ + filter: `name="${safeName}"`, + }); + + if (existingLocation.length > 0) { + const pbUpdated = new Date(existingLocation[0].updated).getTime(); + const uexUpdated = (location.updated ?? 0) * 1000; + + if (pbUpdated < uexUpdated) { + await pb.collection("inventory_locations").update(existingLocation[0].name, { + name: location.name, + }); + updates++; + } + } else { + await pb.collection("inventory_locations").create({ + name: location.name, + }); + creates++; + } + + ops++; + + if (ops % 1000 === 0) { + interaction.editReply({ + content: `Populating inventory_locations collection with ${locations.length} locations... (${ops} processed, ${updates} updated, ${creates} created, ${failed} failed)`, + ephemeral: true, + }); + } + } catch (error) { + console.error(`Failed to create inventory location ${location?.name}:`, error); + failed++; + } + } + + interaction.editReply({ + content: `Successfully populated inventory_locations collection with ${locations.length} locations. (${ops} processed, ${updates} updated, ${creates} created, ${failed} failed)`, + ephemeral: true, + }); +} \ No newline at end of file -- cgit v1.2.3