// The printers you've added. // // Access codes are stored here but never handed back to the browser: every // read returns `codeSet` instead, and saving with a blank code keeps the one // already stored. const db = require('./db'); // Which AMS types can say how much filament is left. An AMS lite only knows // full or empty, so its reading is never used as a weight. const AMS_TYPES = { none: false, ams_lite: false, ams: true, ams_2_pro: true, ams_ht: true }; const clean = (value, max) => { const s = String(value ?? '').trim(); return s ? s.slice(0, max) : null; }; function publicPrinter(row) { if (!row) return null; const { access_code: accessCode, ...rest } = row; return { ...rest, codeSet: Boolean(accessCode) }; } function fields(data) { return { nickname: clean(data.nickname, 60), model: clean(data.model, 40), host: clean(data.host, 255), serial: clean(data.serial, 40), ams_type: Object.prototype.hasOwnProperty.call(AMS_TYPES, data.ams_type) ? data.ams_type : null, }; } async function list() { const { rows } = await db.query('SELECT * FROM printers ORDER BY id'); return rows.map(publicPrinter); } // Server-side only: includes the access code, for connecting. async function listWithCodes() { const { rows } = await db.query('SELECT * FROM printers ORDER BY id'); return rows; } async function get(id, { withCode = false } = {}) { const { rows: [row] } = await db.query('SELECT * FROM printers WHERE id = $1', [id]); if (!row) return null; return withCode ? row : publicPrinter(row); } async function create(data) { const f = fields(data); const { rows: [row] } = await db.query( `INSERT INTO printers (nickname, model, host, serial, access_code, ams_type) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *`, [f.nickname, f.model, f.host, f.serial, clean(data.access_code, 64), f.ams_type]); return publicPrinter(row); } // Only the fields sent are changed; a blank access code keeps the stored one. async function update(id, data) { const f = fields(data); const has = (key) => Object.prototype.hasOwnProperty.call(data, key); const { rows: [row] } = await db.query( `UPDATE printers SET nickname = CASE WHEN $2::boolean THEN $3 ELSE nickname END, model = CASE WHEN $4::boolean THEN $5 ELSE model END, host = CASE WHEN $6::boolean THEN $7 ELSE host END, serial = CASE WHEN $8::boolean THEN $9 ELSE serial END, ams_type = CASE WHEN $10::boolean THEN $11 ELSE ams_type END, access_code = COALESCE($12, access_code), date_modified = now() WHERE id = $1 RETURNING *`, [id, has('nickname'), f.nickname, has('model'), f.model, has('host'), f.host, has('serial'), f.serial, has('ams_type'), f.ams_type, clean(data.access_code, 64)]); return publicPrinter(row); } // Removing a printer also marks its spools as no longer loaded anywhere. async function remove(id) { const { rows: [row] } = await db.query('DELETE FROM printers WHERE id = $1 RETURNING serial', [id]); if (!row) return false; if (row.serial) { await db.query('UPDATE filament_spools SET ams_slot = NULL WHERE printer_serial = $1', [row.serial]); } return true; } const measures = (amsType) => Boolean(AMS_TYPES[amsType]); module.exports = { AMS_TYPES, list, listWithCodes, get, create, update, remove, measures, publicPrinter };