Basic functionality done
This commit is contained in:
parent
568332e502
commit
d02c580d1b
1
globals.d.ts
vendored
Normal file
1
globals.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
declare module 'net-snmp'
|
172
package-lock.json
generated
172
package-lock.json
generated
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "ifms-healthtracker",
|
||||
"name": "ifms-printer-manager",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ifms-healthtracker",
|
||||
"name": "ifms-printer-manager",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
|
@ -25,6 +25,7 @@
|
|||
"nodemon": "^2.0.22",
|
||||
"prisma": "^4.15.0",
|
||||
"rimraf": "^5.0.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsx": "^3.12.7",
|
||||
"typescript": "^5.1.3"
|
||||
}
|
||||
|
@ -48,6 +49,18 @@
|
|||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@cspotcode/source-map-support": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "0.3.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild-kit/cjs-loader": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild-kit/cjs-loader/-/cjs-loader-2.4.2.tgz",
|
||||
|
@ -447,6 +460,31 @@
|
|||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
|
||||
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.9",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
|
||||
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.0.3",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
|
@ -489,6 +527,30 @@
|
|||
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.15.0-28.8fbc245156db7124f997f4cecdd8d1219e360944.tgz",
|
||||
"integrity": "sha512-sVOig4tjGxxlYaFcXgE71f/rtFhzyYrfyfNFUsxCIEJyVKU9rdOWIlIwQ2NQ7PntvGnn+x0XuFo4OC1jvPJKzg=="
|
||||
},
|
||||
"node_modules/@tsconfig/node10": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
|
||||
"integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@tsconfig/node12": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
|
||||
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@tsconfig/node14": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
|
||||
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@tsconfig/node16": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
|
||||
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/asn1": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/asn1/-/asn1-0.2.0.tgz",
|
||||
|
@ -620,6 +682,27 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.9.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz",
|
||||
"integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-walk": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
|
||||
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
||||
|
@ -657,6 +740,12 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/arg": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
||||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
|
@ -896,6 +985,12 @@
|
|||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
||||
},
|
||||
"node_modules/create-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cron-validate": {
|
||||
"version": "1.4.5",
|
||||
"resolved": "https://registry.npmjs.org/cron-validate/-/cron-validate-1.4.5.tgz",
|
||||
|
@ -949,6 +1044,15 @@
|
|||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.1.4",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.1.4.tgz",
|
||||
|
@ -1703,6 +1807,12 @@
|
|||
"node": "14 || >=16.14"
|
||||
}
|
||||
},
|
||||
"node_modules/make-error": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
|
@ -2427,6 +2537,49 @@
|
|||
"nodetouch": "bin/nodetouch.js"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-node": {
|
||||
"version": "10.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
|
||||
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@cspotcode/source-map-support": "^0.8.0",
|
||||
"@tsconfig/node10": "^1.0.7",
|
||||
"@tsconfig/node12": "^1.0.7",
|
||||
"@tsconfig/node14": "^1.0.0",
|
||||
"@tsconfig/node16": "^1.0.2",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn-walk": "^8.1.1",
|
||||
"arg": "^4.1.0",
|
||||
"create-require": "^1.1.0",
|
||||
"diff": "^4.0.1",
|
||||
"make-error": "^1.1.1",
|
||||
"v8-compile-cache-lib": "^3.0.1",
|
||||
"yn": "3.1.1"
|
||||
},
|
||||
"bin": {
|
||||
"ts-node": "dist/bin.js",
|
||||
"ts-node-cwd": "dist/bin-cwd.js",
|
||||
"ts-node-esm": "dist/bin-esm.js",
|
||||
"ts-node-script": "dist/bin-script.js",
|
||||
"ts-node-transpile-only": "dist/bin-transpile.js",
|
||||
"ts-script": "dist/bin-script-deprecated.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/core": ">=1.2.50",
|
||||
"@swc/wasm": ">=1.2.50",
|
||||
"@types/node": "*",
|
||||
"typescript": ">=2.7"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@swc/core": {
|
||||
"optional": true
|
||||
},
|
||||
"@swc/wasm": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tsx": {
|
||||
"version": "3.12.7",
|
||||
"resolved": "https://registry.npmjs.org/tsx/-/tsx-3.12.7.tgz",
|
||||
|
@ -2499,6 +2652,12 @@
|
|||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/v8-compile-cache-lib": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
|
@ -2618,6 +2777,15 @@
|
|||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/yn": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
||||
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/yup": {
|
||||
"version": "0.32.9",
|
||||
"resolved": "https://registry.npmjs.org/yup/-/yup-0.32.9.tgz",
|
||||
|
|
10
package.json
10
package.json
|
@ -5,10 +5,13 @@
|
|||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"clean": "rimraf ./dist",
|
||||
"build": "npm run clean && tsc",
|
||||
"clean": "rimraf ./dist ./public",
|
||||
"build:server": "npm run clean && tsc",
|
||||
"build:web": "cd web && npm run build",
|
||||
"build": "npm run build:server && npm run build:web",
|
||||
"start": "NODE_ENV=production node dist",
|
||||
"dev": "nodemon --ext js,ts,mts,mjs,json,prisma --exec \"tsx src/index.ts\""
|
||||
"dev": "nodemon --ext js,ts,mts,mjs,json,prisma --exec \"tsx src/index.ts\"",
|
||||
"devLegacy": "NODE_OPTIONS=\"--loader ts-node/esm\" node ./src/index.ts"
|
||||
},
|
||||
"prisma": {
|
||||
"seed": "tsx prisma/seed.ts"
|
||||
|
@ -23,6 +26,7 @@
|
|||
"nodemon": "^2.0.22",
|
||||
"prisma": "^4.15.0",
|
||||
"rimraf": "^5.0.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsx": "^3.12.7",
|
||||
"typescript": "^5.1.3"
|
||||
},
|
||||
|
|
|
@ -23,7 +23,7 @@ CREATE TABLE "Printer" (
|
|||
"serialNumber" TEXT,
|
||||
"hostname" TEXT,
|
||||
"ip" TEXT NOT NULL,
|
||||
"model" TEXT,
|
||||
"model" TEXT NOT NULL,
|
||||
"blackTonerModel" TEXT,
|
||||
"cyanTonerModel" TEXT,
|
||||
"magentaTonerModel" TEXT,
|
||||
|
@ -54,5 +54,8 @@ CREATE UNIQUE INDEX "User_username_key" ON "User"("username");
|
|||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Printer_serialNumber_key" ON "Printer"("serialNumber");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Printer_ip_key" ON "Printer"("ip");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PrinterStatus" ADD CONSTRAINT "PrinterStatus_printerId_fkey" FOREIGN KEY ("printerId") REFERENCES "Printer"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
5
prisma/migrations/20230620191614_cascade/migration.sql
Normal file
5
prisma/migrations/20230620191614_cascade/migration.sql
Normal file
|
@ -0,0 +1,5 @@
|
|||
-- DropForeignKey
|
||||
ALTER TABLE "PrinterStatus" DROP CONSTRAINT "PrinterStatus_printerId_fkey";
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PrinterStatus" ADD CONSTRAINT "PrinterStatus_printerId_fkey" FOREIGN KEY ("printerId") REFERENCES "Printer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@ -38,8 +38,8 @@ model Printer {
|
|||
|
||||
serialNumber String? @unique
|
||||
hostname String?
|
||||
ip String
|
||||
model String?
|
||||
ip String @unique
|
||||
model String
|
||||
|
||||
blackTonerModel String?
|
||||
cyanTonerModel String?
|
||||
|
@ -49,7 +49,7 @@ model Printer {
|
|||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @default(now()) @updatedAt
|
||||
|
||||
PrinterStatus PrinterStatus[]
|
||||
status PrinterStatus[]
|
||||
}
|
||||
|
||||
model PrinterStatus {
|
||||
|
@ -65,5 +65,5 @@ model PrinterStatus {
|
|||
createdAt DateTime @default(now())
|
||||
|
||||
printerId Int
|
||||
printer Printer @relation(fields: [printerId], references: [id])
|
||||
printer Printer @relation(fields: [printerId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import { Request, Response, Router } from 'express'
|
|||
|
||||
import { hasRolesMiddleware } from '../middlewares/hasRolesMiddleware.js'
|
||||
import { prisma } from '../prisma.js'
|
||||
import { PrinterStatusService } from '../services/PrinterStatusService.js'
|
||||
|
||||
const router = Router()
|
||||
|
||||
|
@ -21,7 +22,7 @@ class PrinterController {
|
|||
const printer = await prisma.printer.findUnique({
|
||||
where: { id: Number(id) },
|
||||
include: {
|
||||
PrinterStatus: {
|
||||
status: {
|
||||
where: {
|
||||
createdAt: {
|
||||
gte
|
||||
|
@ -35,27 +36,44 @@ class PrinterController {
|
|||
}
|
||||
|
||||
static async create(req: Request, res: Response) {
|
||||
const { friendlyName, ip, location } = req.body
|
||||
const { friendlyName, ip } = req.body
|
||||
|
||||
try {
|
||||
const model = await PrinterStatusService.getPrinterModel(ip)
|
||||
const printer = await prisma.printer.create({
|
||||
data: { friendlyName, ip, location }
|
||||
data: { friendlyName, ip, model }
|
||||
})
|
||||
|
||||
// Run snmp here
|
||||
new PrinterStatusService(printer)
|
||||
|
||||
res.json(printer)
|
||||
} catch (e) {
|
||||
res
|
||||
.status(400)
|
||||
.json({ error: 'Este endereço não é de uma impressora suportada.' })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
static async edit(req: Request, res: Response) {
|
||||
const { id } = req.params
|
||||
const { friendlyName, ip, location } = req.body
|
||||
const { friendlyName, ip } = req.body
|
||||
|
||||
// Verify if printer exists
|
||||
const printerExists = await prisma.printer.findUnique({
|
||||
where: { id: Number(id) }
|
||||
})
|
||||
|
||||
if (printerExists) {
|
||||
const printer = await prisma.printer.update({
|
||||
where: { id: Number(id) },
|
||||
data: { friendlyName, ip, location }
|
||||
data: { friendlyName, ip }
|
||||
})
|
||||
|
||||
res.json(printer)
|
||||
} else {
|
||||
res.status(400).json({ error: 'Printer not found' })
|
||||
}
|
||||
}
|
||||
|
||||
static async delete(req: Request, res: Response) {
|
||||
|
@ -70,7 +88,9 @@ class PrinterController {
|
|||
router.use(hasRolesMiddleware(['ADMIN', 'INSPECTOR']))
|
||||
|
||||
router.get('/', PrinterController.index)
|
||||
router.post('/', PrinterController.create)
|
||||
router.get('/:id', PrinterController.show)
|
||||
router.put('/:id', PrinterController.edit)
|
||||
router.delete('/:id', PrinterController.delete)
|
||||
|
||||
export default router
|
||||
|
|
20
src/controllers/PrinterStatusController.ts
Normal file
20
src/controllers/PrinterStatusController.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { Router, Request, Response } from 'express'
|
||||
import { prisma } from '../prisma.js'
|
||||
import { PrinterStatusService } from '../services/PrinterStatusService.js'
|
||||
|
||||
const router = Router()
|
||||
|
||||
class PrinterStatusController {
|
||||
static async update(req: Request, res: Response) {
|
||||
const printers = await prisma.printer.findMany()
|
||||
|
||||
printers.forEach(async printer => {
|
||||
new PrinterStatusService(printer)
|
||||
})
|
||||
|
||||
res.json({ message: 'Updating printer status' })
|
||||
}
|
||||
}
|
||||
|
||||
router.get('/update', PrinterStatusController.update)
|
||||
export default router
|
|
@ -1,6 +1,5 @@
|
|||
import 'dotenv/config'
|
||||
import * as path from 'node:path'
|
||||
import * as process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
import { app } from './server.js'
|
||||
|
@ -13,7 +12,7 @@ app.listen(PORT, () => {
|
|||
console.log(
|
||||
`Running in ${
|
||||
process.env.NODE_ENV == 'production' ? 'PRODUCTION' : 'DEVELOPMENT'
|
||||
} mode. Server listening on port ${PORT}`
|
||||
} mode. \nServer listening http://127.0.0.1:${PORT}`
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -24,8 +23,9 @@ const bree = new Bree({
|
|||
logger: false,
|
||||
jobs: [
|
||||
{
|
||||
name: 'printerStatus',
|
||||
interval: '2s'
|
||||
name: 'updatePrinterStatus',
|
||||
interval: process.env.UPDATE_INTERVAL || '10m',
|
||||
timeout: 0
|
||||
}
|
||||
]
|
||||
})
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
export function snmpUpdate() {
|
||||
console.log('snmpUpdate!!!!!')
|
||||
}
|
||||
|
||||
snmpUpdate()
|
14
src/jobs/updatePrinterStatus.ts
Normal file
14
src/jobs/updatePrinterStatus.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { prisma } from '../prisma.js'
|
||||
import { PrinterStatusService } from '../services/PrinterStatusService.js'
|
||||
|
||||
function updatePrinterStatus() {
|
||||
console.log(`Updating printer status ${new Date().toISOString()}`)
|
||||
|
||||
prisma.printer.findMany().then(printers => {
|
||||
printers.forEach(async printer => {
|
||||
new PrinterStatusService(printer)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
updatePrinterStatus()
|
109
src/repositories/ObjectIDRepository.ts
Normal file
109
src/repositories/ObjectIDRepository.ts
Normal file
|
@ -0,0 +1,109 @@
|
|||
export type PrinterObjectIds = {
|
||||
model: string
|
||||
objectIds: {
|
||||
model: string
|
||||
serialNumber: string
|
||||
counter: string
|
||||
location: string
|
||||
toners: {
|
||||
black: {
|
||||
current: string
|
||||
max: string
|
||||
model: string
|
||||
}
|
||||
cyan?: {
|
||||
current: string
|
||||
max: string
|
||||
model: string
|
||||
}
|
||||
magenta?: {
|
||||
current: string
|
||||
max: string
|
||||
model: string
|
||||
}
|
||||
yellow?: {
|
||||
current: string
|
||||
max: string
|
||||
model: string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const objectIds: PrinterObjectIds[] = [
|
||||
{
|
||||
model: 'ECOSYS M3655idn',
|
||||
objectIds: {
|
||||
model: '1.3.6.1.2.1.25.3.2.1.3.1',
|
||||
serialNumber: '1.3.6.1.2.1.43.5.1.1.17.1',
|
||||
counter: '1.3.6.1.4.1.1347.43.10.1.1.12.1.1',
|
||||
location: '1.3.6.1.2.1.1.6.0',
|
||||
toners: {
|
||||
black: {
|
||||
current: '1.3.6.1.2.1.43.11.1.1.9.1.1',
|
||||
max: '1.3.6.1.2.1.43.11.1.1.8.1.1',
|
||||
model: '1.3.6.1.2.1.43.11.1.1.6.1.1'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
model: 'ECOSYS P6235cdn',
|
||||
objectIds: {
|
||||
model: '1.3.6.1.2.1.25.3.2.1.3.1',
|
||||
serialNumber: '1.3.6.1.2.1.43.5.1.1.17.1',
|
||||
counter: '1.3.6.1.4.1.1347.43.10.1.1.12.1.1',
|
||||
location: '1.3.6.1.2.1.1.6.0',
|
||||
toners: {
|
||||
black: {
|
||||
current: '1.3.6.1.2.1.43.11.1.1.9.1.4',
|
||||
max: '1.3.6.1.2.1.43.11.1.1.8.1.4',
|
||||
model: '1.3.6.1.2.1.43.11.1.1.6.1.4'
|
||||
},
|
||||
cyan: {
|
||||
current: '1.3.6.1.2.1.43.11.1.1.9.1.1',
|
||||
max: '1.3.6.1.2.1.43.11.1.1.8.1.1',
|
||||
model: '1.3.6.1.2.1.43.11.1.1.6.1.1'
|
||||
},
|
||||
magenta: {
|
||||
current: '1.3.6.1.2.1.43.11.1.1.9.1.2',
|
||||
max: '1.3.6.1.2.1.43.11.1.1.8.1.2',
|
||||
model: '1.3.6.1.2.1.43.11.1.1.6.1.2'
|
||||
},
|
||||
yellow: {
|
||||
current: '1.3.6.1.2.1.43.11.1.1.9.1.3',
|
||||
max: '1.3.6.1.2.1.43.11.1.1.8.1.3',
|
||||
model: '1.3.6.1.2.1.43.11.1.1.6.1.3'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
model: 'ECOSYS M2040dn',
|
||||
objectIds: {
|
||||
model: '1.3.6.1.2.1.25.3.2.1.3.1',
|
||||
serialNumber: '1.3.6.1.2.1.43.5.1.1.17.1',
|
||||
counter: '1.3.6.1.4.1.1347.43.10.1.1.12.1.1',
|
||||
location: '1.3.6.1.2.1.1.6.0',
|
||||
toners: {
|
||||
black: {
|
||||
current: '1.3.6.1.2.1.43.11.1.1.9.1.1',
|
||||
max: '1.3.6.1.2.1.43.11.1.1.8.1.1',
|
||||
model: '1.3.6.1.2.1.43.11.1.1.6.1.1'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
export class objectIdsRepository {
|
||||
private constructor() {}
|
||||
|
||||
static getPrinterObjectIds(model: string): PrinterObjectIds {
|
||||
const printerObjectIds = objectIds.find(printer => printer.model === model)
|
||||
|
||||
if (!printerObjectIds) throw new Error('Model not found')
|
||||
|
||||
return printerObjectIds
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import { authMiddleware } from './middlewares/authMiddleware.js'
|
|||
|
||||
import LoginRouter from './controllers/LoginController.js'
|
||||
import PrinterRouter from './controllers/PrinterController.js'
|
||||
import PrinterStatusRouter from './controllers/PrinterStatusController.js'
|
||||
|
||||
export const app = express()
|
||||
|
||||
|
@ -16,6 +17,7 @@ app.use(populateUserMiddleware)
|
|||
|
||||
app.use('/api/login', LoginRouter)
|
||||
app.use('/api/printer', PrinterRouter)
|
||||
app.use('/api/printer-status', PrinterStatusRouter)
|
||||
|
||||
app.get('/api/me', authMiddleware, async (req: Request, res: Response) =>
|
||||
res.json(res.locals.user)
|
||||
|
|
213
src/services/PrinterStatusService.ts
Normal file
213
src/services/PrinterStatusService.ts
Normal file
|
@ -0,0 +1,213 @@
|
|||
import snmp from 'net-snmp'
|
||||
import { Printer, PrinterStatus } from '@prisma/client'
|
||||
import { prisma } from '../prisma.js'
|
||||
import {
|
||||
objectIdsRepository,
|
||||
PrinterObjectIds
|
||||
} from '../repositories/ObjectIDRepository.js'
|
||||
|
||||
type VarbindString = {
|
||||
oid: string
|
||||
type: number
|
||||
value: string
|
||||
}
|
||||
|
||||
export type Varbind = {
|
||||
oid: string
|
||||
type: number
|
||||
value: string | Buffer
|
||||
}
|
||||
|
||||
export type PrinterInfo = {
|
||||
serialNumber: string
|
||||
counter: number
|
||||
location: string
|
||||
toners: {
|
||||
black: {
|
||||
level: number
|
||||
model: string
|
||||
}
|
||||
cyan?: {
|
||||
level: number
|
||||
model: string
|
||||
}
|
||||
magenta?: {
|
||||
level: number
|
||||
model: string
|
||||
}
|
||||
yellow?: {
|
||||
level: number
|
||||
model: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class PrinterStatusService {
|
||||
constructor(private printer: Printer) {
|
||||
this.getPrinterInfo().then(async printerStatus => {
|
||||
await prisma.printer.update({
|
||||
where: { id: this.printer.id },
|
||||
data: {
|
||||
serialNumber: printerStatus.serialNumber,
|
||||
location: printerStatus.location,
|
||||
blackTonerModel: printerStatus.toners.black.model,
|
||||
cyanTonerModel: printerStatus.toners.cyan?.model,
|
||||
magentaTonerModel: printerStatus.toners.magenta?.model,
|
||||
yellowTonerModel: printerStatus.toners.yellow?.model,
|
||||
|
||||
status: {
|
||||
create: {
|
||||
counter: printerStatus.counter,
|
||||
tonerBlackLevel: printerStatus.toners.black.level,
|
||||
tonerCyanLevel: printerStatus.toners.cyan?.level,
|
||||
tonerMagentaLevel: printerStatus.toners.magenta?.level,
|
||||
tonerYellowLevel: printerStatus.toners.yellow?.level
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
private objectIdsArray(): string[] {
|
||||
const oIDsArray: string[] = []
|
||||
|
||||
function extractObjValues(obj: any) {
|
||||
for (let key in obj) {
|
||||
if (typeof obj[key] === 'object') {
|
||||
extractObjValues(obj[key])
|
||||
} else {
|
||||
const oID = obj[key]
|
||||
oIDsArray.push(oID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extractObjValues(
|
||||
objectIdsRepository.getPrinterObjectIds(this.printer.model).objectIds
|
||||
)
|
||||
|
||||
return oIDsArray
|
||||
}
|
||||
|
||||
private deBufferizeVarbinds(varbinds: Varbind[]) {
|
||||
const varbindsString: VarbindString[] = []
|
||||
|
||||
varbinds.forEach((varbind: Varbind) => {
|
||||
if (varbind.value instanceof Buffer)
|
||||
varbindsString.push({ ...varbind, value: varbind.value.toString() })
|
||||
else varbindsString.push({ ...varbind, value: varbind.value })
|
||||
})
|
||||
|
||||
return varbindsString
|
||||
}
|
||||
|
||||
static getPrinterModel(ip: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const snmpSession = snmp.createSession(ip, 'public')
|
||||
snmpSession.get(
|
||||
['1.3.6.1.2.1.25.3.2.1.3.1'],
|
||||
(error: any, varbinds: any) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve(varbinds[0].value.toString())
|
||||
}
|
||||
snmpSession.close()
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
async getPrinterInfo(): Promise<PrinterInfo> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const session = snmp.createSession(this.printer.ip, 'public')
|
||||
|
||||
const oIDsArray = this.objectIdsArray()
|
||||
|
||||
session.get(oIDsArray, (error: any, varbinds: Varbind[]) => {
|
||||
if (error) reject(error)
|
||||
|
||||
const varbindsString = this.deBufferizeVarbinds(varbinds)
|
||||
const info = this.objectIDsToPrinterInfo(varbindsString)
|
||||
|
||||
resolve(info)
|
||||
session.close()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
private calcTonerLevelPercentage(
|
||||
current: string | undefined,
|
||||
max: string | undefined
|
||||
) {
|
||||
if (typeof current === 'undefined' || typeof max === 'undefined')
|
||||
throw new Error('current or max is undefined')
|
||||
|
||||
return (+current! / +max!) * 100
|
||||
}
|
||||
|
||||
private objectIDsToPrinterInfo(varbinds: Varbind[]): PrinterInfo {
|
||||
const snmpInfo = this.deBufferizeVarbinds(varbinds)
|
||||
|
||||
const { objectIds }: PrinterObjectIds =
|
||||
objectIdsRepository.getPrinterObjectIds(this.printer.model)
|
||||
|
||||
const printerInfo: PrinterInfo = {
|
||||
serialNumber: snmpInfo.find(x => x.oid === objectIds.serialNumber)
|
||||
?.value as string,
|
||||
counter: Number(snmpInfo.find(x => x.oid === objectIds.counter)?.value),
|
||||
location: snmpInfo.find(x => x.oid === objectIds.location)
|
||||
?.value as string,
|
||||
toners: {
|
||||
black: {
|
||||
level: this.calcTonerLevelPercentage(
|
||||
snmpInfo.find(x => x.oid === objectIds.toners.black.current)?.value,
|
||||
snmpInfo.find(x => x.oid === objectIds.toners.black.max)?.value
|
||||
),
|
||||
model: snmpInfo.find(x => x.oid === objectIds.toners.black.model)
|
||||
?.value as string
|
||||
},
|
||||
cyan: objectIds.toners.cyan
|
||||
? {
|
||||
level: this.calcTonerLevelPercentage(
|
||||
snmpInfo.find(x => x.oid === objectIds.toners.cyan?.current)
|
||||
?.value,
|
||||
snmpInfo.find(x => x.oid === objectIds.toners.cyan?.max)?.value
|
||||
),
|
||||
model: snmpInfo.find(x => x.oid === objectIds.toners.cyan?.model)
|
||||
?.value as string
|
||||
}
|
||||
: undefined,
|
||||
magenta: objectIds.toners.magenta
|
||||
? {
|
||||
level: this.calcTonerLevelPercentage(
|
||||
snmpInfo.find(x => x.oid === objectIds.toners.magenta?.current)
|
||||
?.value,
|
||||
snmpInfo.find(x => x.oid === objectIds.toners.magenta?.max)
|
||||
?.value
|
||||
),
|
||||
model: snmpInfo.find(
|
||||
x => x.oid === objectIds.toners.magenta?.model
|
||||
)?.value as string
|
||||
}
|
||||
: undefined,
|
||||
yellow: objectIds.toners.yellow
|
||||
? {
|
||||
level: this.calcTonerLevelPercentage(
|
||||
snmpInfo.find(x => x.oid === objectIds.toners.yellow?.current)
|
||||
?.value,
|
||||
snmpInfo.find(x => x.oid === objectIds.toners.yellow?.max)
|
||||
?.value
|
||||
),
|
||||
model: snmpInfo.find(
|
||||
x => x.oid === objectIds.toners.yellow?.model
|
||||
)?.value as string
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
}
|
||||
|
||||
return printerInfo
|
||||
}
|
||||
}
|
|
@ -14,12 +14,12 @@ export class UserService {
|
|||
|
||||
if (!ldapUser) throw new Error('User not found!')
|
||||
|
||||
const user = {
|
||||
const user: Omit<User, 'id' | 'createdAt' | 'updatedAt'> = {
|
||||
username: ldapUser.username,
|
||||
displayName: ldapUser.displayName,
|
||||
mail: ldapUser.mail,
|
||||
thumbnailPhoto: ldapUser.thumbnailPhoto,
|
||||
roles: [] as User['roles']
|
||||
roles: []
|
||||
}
|
||||
|
||||
ldapUser.groups?.forEach(group => {
|
||||
|
|
|
@ -106,5 +106,5 @@
|
|||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
},
|
||||
"include": ["src/**/*", "jobs/**/*"]
|
||||
"include": ["src/**/*", "jobs/**/*", "globals.d.ts"]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user