From 516feb51d47f760427ee12eb482c3ea7535dc56d Mon Sep 17 00:00:00 2001 From: seb Date: Sun, 27 Sep 2026 16:47:37 +0200 Subject: [PATCH] u --- API.printer.md | 4 +- scripts/migrate-printer-type-ipp.js | 105 ++++++++++++++++++++++++++++ src/providers/mssql/schema.js | 2 +- src/providers/sqlite3/schema.js | 2 +- src/store/printer/create.js | 6 +- src/store/printer/update.js | 6 +- 6 files changed, 115 insertions(+), 10 deletions(-) create mode 100644 scripts/migrate-printer-type-ipp.js diff --git a/API.printer.md b/API.printer.md index ff95967..52b023c 100644 --- a/API.printer.md +++ b/API.printer.md @@ -15,7 +15,7 @@ Creates a new printer for the user's selected company. | `googleAuthId` | `number` | The id of the Google auth user. | | `input` | `object` | Printer input. | | `input.address` | `string` | Printer address (network IP/host/path). | -| `input.type` | `string` | Printer type ("esc/pos" or "zpl"). | +| `input.type` | `string` | Printer type ("esc/pos", "zpl", or "ipp"). | | `[input.model]` | `string` | Optional printer model name. | | `[input.serial]` | `string` | Optional printer serial number. | | `[input.sort]` | `number` | Optional sort order (auto-increments if omitted). | @@ -149,7 +149,7 @@ Updates a printer for the user's selected company. | `id` | `number` | The printer ID to update. | | `input` | `object` | Update payload. | | `[input.address]` | `string` | The printer address. | -| `[input.type]` | `string` | The printer type ("esc/pos" or "zpl"). | +| `[input.type]` | `string` | The printer type ("esc/pos", "zpl", or "ipp"). | | `[input.model]` | `string|null` | The printer model. | | `[input.serial]` | `string|null` | The printer serial. | | `[input.sort]` | `number` | The sort order. | diff --git a/scripts/migrate-printer-type-ipp.js b/scripts/migrate-printer-type-ipp.js new file mode 100644 index 0000000..a0cc4d1 --- /dev/null +++ b/scripts/migrate-printer-type-ipp.js @@ -0,0 +1,105 @@ +import 'dotenv/config'; +import Database from 'better-sqlite3'; +import { MssqlProvider } from '../src/providers/mssql/index.js'; + +async function migrateSqlite(sqlitePath) { + console.log(`Migrating SQLite database at: ${sqlitePath}`); + const db = new Database(sqlitePath); + + const row = db.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'printer'").get(); + if (!row) { + console.log('Printer table does not exist in SQLite.'); + db.close(); + return; + } + + if (row.sql.includes("'ipp'")) { + console.log("SQLite printer table already includes 'ipp' in CHECK constraint."); + db.close(); + return; + } + + db.pragma('foreign_keys = OFF'); + db.exec(` + BEGIN TRANSACTION; + CREATE TABLE printer_new ( + id INTEGER PRIMARY KEY, + company_id INTEGER NOT NULL, + address TEXT NOT NULL, + type TEXT NOT NULL CHECK (type IN ('esc/pos', 'zpl', 'ipp')), + model TEXT, + serial TEXT, + sort INTEGER NOT NULL DEFAULT 0, + "desc" TEXT, + FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE + ); + INSERT INTO printer_new (id, company_id, address, type, model, serial, sort, "desc") + SELECT id, company_id, address, type, model, serial, sort, "desc" + FROM printer; + DROP TABLE printer; + ALTER TABLE printer_new RENAME TO printer; + COMMIT; + `); + db.pragma('foreign_keys = ON'); + + const fkErrors = db.pragma('foreign_key_check'); + if (fkErrors.length > 0) { + console.error('Foreign key check failed after SQLite migration:', fkErrors); + } else { + console.log('SQLite migration completed successfully.'); + } + + const updatedRow = db.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'printer'").get(); + console.log('Updated SQLite printer table SQL:', updatedRow?.sql); + db.close(); +} + +async function migrateMssql() { + console.log('Migrating MSSQL database...'); + const config = { + server: process.env.MSSQL_SERVER, + database: process.env.MSSQL_DATABASE, + user: process.env.MSSQL_USER, + password: process.env.MSSQL_PASSWORD, + options: { + encrypt: false, + trustServerCertificate: true, + }, + }; + + try { + const provider = new MssqlProvider(config); + const pool = await provider.ensurePool(); + const tableRes = await pool.request().query(` + SELECT * FROM sys.tables WHERE name = 'printer' + `); + if (tableRes.recordset.length === 0) { + console.log('Printer table does not exist in MSSQL.'); + await provider.close(); + return; + } + + // Drop old CK_printer_type constraint if exists and add new one + await pool.request().query(` + IF EXISTS (SELECT * FROM sys.check_constraints WHERE name = 'CK_printer_type') + BEGIN + ALTER TABLE printer DROP CONSTRAINT CK_printer_type; + END + ALTER TABLE printer ADD CONSTRAINT CK_printer_type CHECK (type IN ('esc/pos', 'zpl', 'ipp')); + `); + console.log('MSSQL migration completed successfully.'); + await provider.close(); + } catch (err) { + console.warn('MSSQL migration skipped/failed (possibly server not running):', err.message); + } +} + +async function run() { + await migrateSqlite('/home/seb/src/dashback/data/dash.db'); + await migrateMssql(); +} + +run().catch((err) => { + console.error('Migration failed:', err); + process.exit(1); +}); diff --git a/src/providers/mssql/schema.js b/src/providers/mssql/schema.js index 70d9ca3..dd3051e 100644 --- a/src/providers/mssql/schema.js +++ b/src/providers/mssql/schema.js @@ -800,7 +800,7 @@ BEGIN sort INT NOT NULL CONSTRAINT DF_printer_sort DEFAULT 0, [desc] NVARCHAR(MAX) NULL, CONSTRAINT FK_printer_company FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE, - CONSTRAINT CK_printer_type CHECK (type IN ('esc/pos', 'zpl')) + CONSTRAINT CK_printer_type CHECK (type IN ('esc/pos', 'zpl', 'ipp')) ); END `; diff --git a/src/providers/sqlite3/schema.js b/src/providers/sqlite3/schema.js index 56dc4d2..366cec1 100644 --- a/src/providers/sqlite3/schema.js +++ b/src/providers/sqlite3/schema.js @@ -553,7 +553,7 @@ CREATE TABLE IF NOT EXISTS printer ( id INTEGER PRIMARY KEY, company_id INTEGER NOT NULL, address TEXT NOT NULL, - type TEXT NOT NULL CHECK (type IN ('esc/pos', 'zpl')), + type TEXT NOT NULL CHECK (type IN ('esc/pos', 'zpl', 'ipp')), model TEXT, serial TEXT, sort INTEGER NOT NULL DEFAULT 0, diff --git a/src/store/printer/create.js b/src/store/printer/create.js index 8538349..49a28a0 100644 --- a/src/store/printer/create.js +++ b/src/store/printer/create.js @@ -9,7 +9,7 @@ import { import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js'; import makeRunner from '../runner.js'; -const VALID_TYPES = new Set(['esc/pos', 'zpl']); +const VALID_TYPES = new Set(['esc/pos', 'zpl', 'ipp']); function shape(row) { return { @@ -42,7 +42,7 @@ export default function create(provider) { * @param {number} googleAuthId - The id of the Google auth user. * @param {object} input - Printer input. * @param {string} input.address - Printer address (network IP/host/path). - * @param {string} input.type - Printer type ("esc/pos" or "zpl"). + * @param {string} input.type - Printer type ("esc/pos", "zpl", or "ipp"). * @param {string} [input.model] - Optional printer model name. * @param {string} [input.serial] - Optional printer serial number. * @param {number} [input.sort] - Optional sort order (auto-increments if omitted). @@ -67,7 +67,7 @@ export default function create(provider) { const type = typeof input.type === 'string' ? input.type.trim() : ''; if (!type || !VALID_TYPES.has(type)) { - throw new Error('Invalid printer type: must be "esc/pos" or "zpl"'); + throw new Error('Invalid printer type: must be "esc/pos", "zpl", or "ipp"'); } const runner = makeRunner(provider, tx); diff --git a/src/store/printer/update.js b/src/store/printer/update.js index 51d6e33..d1a3745 100644 --- a/src/store/printer/update.js +++ b/src/store/printer/update.js @@ -9,7 +9,7 @@ import { import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js'; import makeRunner from '../runner.js'; -const VALID_TYPES = new Set(['esc/pos', 'zpl']); +const VALID_TYPES = new Set(['esc/pos', 'zpl', 'ipp']); function shape(row) { return { @@ -43,7 +43,7 @@ export default function update(provider) { * @param {number} id - The printer ID to update. * @param {object} input - Update payload. * @param {string} [input.address] - The printer address. - * @param {string} [input.type] - The printer type ("esc/pos" or "zpl"). + * @param {string} [input.type] - The printer type ("esc/pos", "zpl", or "ipp"). * @param {string|null} [input.model] - The printer model. * @param {string|null} [input.serial] - The printer serial. * @param {number} [input.sort] - The sort order. @@ -80,7 +80,7 @@ export default function update(provider) { if (input.type !== undefined) { const cleaned = typeof input.type === 'string' ? input.type.trim() : ''; if (!cleaned || !VALID_TYPES.has(cleaned)) { - throw new Error('Invalid printer type: must be "esc/pos" or "zpl"'); + throw new Error('Invalid printer type: must be "esc/pos", "zpl", or "ipp"'); } type = cleaned; }