Prettier lint

This commit is contained in:
Douglas Barone 2023-06-28 13:21:42 -04:00
parent 54948c1795
commit a425a59cc7
45 changed files with 423 additions and 394 deletions

2
.gitignore vendored
View File

@ -150,4 +150,4 @@ dev.db
db/ db/
# Frontend build # Frontend build
public/ /public/

View File

@ -1,5 +1,6 @@
{ {
"tabWidth": 2, "tabWidth": 2,
"useTabs": false, "useTabs": false,
"htmlWhitespaceSensitivity": "ignore" "htmlWhitespaceSensitivity": "ignore",
"semi": false
} }

2
globals.d.ts vendored
View File

@ -1 +1 @@
declare module 'net-snmp' declare module "net-snmp"

16
package-lock.json generated
View File

@ -31,6 +31,7 @@
"@types/jsonwebtoken": "^9.0.2", "@types/jsonwebtoken": "^9.0.2",
"@types/node": "^20.3.1", "@types/node": "^20.3.1",
"nodemon": "^2.0.22", "nodemon": "^2.0.22",
"prettier": "^2.8.8",
"prisma": "^4.15.0", "prisma": "^4.15.0",
"rimraf": "^5.0.1", "rimraf": "^5.0.1",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
@ -3927,6 +3928,21 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/prettier": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prisma": { "node_modules/prisma": {
"version": "4.16.1", "version": "4.16.1",
"resolved": "https://registry.npmjs.org/prisma/-/prisma-4.16.1.tgz", "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.16.1.tgz",

View File

@ -16,7 +16,8 @@
"dev": "concurrently --kill-others -n Server,Web \"npm run dev:server\" \"npm run dev:web\"", "dev": "concurrently --kill-others -n Server,Web \"npm run dev:server\" \"npm run dev:web\"",
"dev:server": "nodemon --ext js,ts,mts,mjs,json,prisma --exclude ./web/* --exec \"tsx src/index.ts\"", "dev:server": "nodemon --ext js,ts,mts,mjs,json,prisma --exclude ./web/* --exec \"tsx src/index.ts\"",
"dev:web": "npm run dev -w web", "dev:web": "npm run dev -w web",
"devLegacy": "NODE_OPTIONS=\"--loader ts-node/esm\" node ./src/index.ts" "devLegacy": "NODE_OPTIONS=\"--loader ts-node/esm\" node ./src/index.ts",
"prettier": "prettier --write \"src/**/*.{js,ts,tsx,json,md}\" \"web/**/*.{js,ts,tsx,json,md}\""
}, },
"prisma": { "prisma": {
"seed": "tsx prisma/seed.ts" "seed": "tsx prisma/seed.ts"
@ -29,6 +30,7 @@
"@types/jsonwebtoken": "^9.0.2", "@types/jsonwebtoken": "^9.0.2",
"@types/node": "^20.3.1", "@types/node": "^20.3.1",
"nodemon": "^2.0.22", "nodemon": "^2.0.22",
"prettier": "^2.8.8",
"prisma": "^4.15.0", "prisma": "^4.15.0",
"rimraf": "^5.0.1", "rimraf": "^5.0.1",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",

View File

@ -1,116 +1,116 @@
import { PrismaClient } from '@prisma/client' import { PrismaClient } from "@prisma/client"
export const prisma = new PrismaClient() export const prisma = new PrismaClient()
async function main() { async function main() {
console.log('Seeding printers...') console.log("Seeding printers...")
console.log('Seeding subnets...') console.log("Seeding subnets...")
await prisma.network.createMany({ await prisma.network.createMany({
data: [ data: [
{ {
shortName: 'RT1', shortName: "RT1",
name: 'Reitoria', name: "Reitoria",
cidr: '10.0.0.0/21' cidr: "10.0.0.0/21",
}, },
{ {
shortName: 'RT2', shortName: "RT2",
name: 'Reitoria 2', name: "Reitoria 2",
cidr: '10.1.0.0/21' cidr: "10.1.0.0/21",
}, },
{ {
shortName: 'AQ', shortName: "AQ",
name: 'Aquidauana', name: "Aquidauana",
cidr: '10.2.0.0/21' cidr: "10.2.0.0/21",
}, },
{ {
shortName: 'CG', shortName: "CG",
name: 'Campo Grande', name: "Campo Grande",
cidr: '10.3.0.0/21' cidr: "10.3.0.0/21",
}, },
{ {
shortName: 'CB', shortName: "CB",
name: 'Corumbá', name: "Corumbá",
cidr: '10.4.0.0/21' cidr: "10.4.0.0/21",
}, },
{ {
shortName: 'CX', shortName: "CX",
name: 'Coxim', name: "Coxim",
cidr: '10.5.0.0/21' cidr: "10.5.0.0/21",
}, },
{ {
shortName: 'NA', shortName: "NA",
name: 'Nova Andradina', name: "Nova Andradina",
cidr: '10.6.0.0/21' cidr: "10.6.0.0/21",
}, },
{ {
shortName: 'PP', shortName: "PP",
name: 'Ponta Porã', name: "Ponta Porã",
cidr: '10.7.0.0/21' cidr: "10.7.0.0/21",
}, },
{ {
shortName: 'TL', shortName: "TL",
name: 'Três Lagoas', name: "Três Lagoas",
cidr: '10.8.0.0/21' cidr: "10.8.0.0/21",
}, },
{ {
shortName: 'JD', shortName: "JD",
name: 'Jardim', name: "Jardim",
cidr: '10.9.0.0/21' cidr: "10.9.0.0/21",
}, },
{ {
shortName: 'NV', shortName: "NV",
name: 'Naviraí', name: "Naviraí",
cidr: '10.10.0.0/21' cidr: "10.10.0.0/21",
}, },
{ {
shortName: 'DR', shortName: "DR",
name: 'Dourados', name: "Dourados",
cidr: '10.11.0.0/21' cidr: "10.11.0.0/21",
} },
], ],
skipDuplicates: true skipDuplicates: true,
}) })
await prisma.printer.createMany({ await prisma.printer.createMany({
data: [ data: [
{ {
friendlyName: 'P04', friendlyName: "P04",
ip: '10.7.0.134', ip: "10.7.0.134",
model: 'ECOSYS M3655idn', model: "ECOSYS M3655idn",
serialNumber: 'R4P1478461', serialNumber: "R4P1478461",
networkId: 8 networkId: 8,
}, },
{ {
friendlyName: 'P05', friendlyName: "P05",
ip: '10.7.0.135', ip: "10.7.0.135",
model: 'ECOSYS M2040dn', model: "ECOSYS M2040dn",
serialNumber: 'VR91483974', serialNumber: "VR91483974",
networkId: 8 networkId: 8,
}, },
{ {
friendlyName: 'P06', friendlyName: "P06",
ip: '10.7.0.136', ip: "10.7.0.136",
model: 'ECOSYS M2040dn', model: "ECOSYS M2040dn",
serialNumber: 'VR91586433', serialNumber: "VR91586433",
networkId: 8 networkId: 8,
}, },
{ {
friendlyName: 'P07', friendlyName: "P07",
ip: '10.7.0.137', ip: "10.7.0.137",
model: 'ECOSYS M2040dn', model: "ECOSYS M2040dn",
serialNumber: 'VR91586432', serialNumber: "VR91586432",
networkId: 8 networkId: 8,
}, },
{ {
friendlyName: 'P08', friendlyName: "P08",
ip: '10.7.0.138', ip: "10.7.0.138",
model: 'ECOSYS P6235cdn', model: "ECOSYS P6235cdn",
serialNumber: 'RCG0304510', serialNumber: "RCG0304510",
networkId: 8 networkId: 8,
} },
] ],
}) })
} }
@ -118,7 +118,7 @@ main()
.then(() => { .then(() => {
prisma.$disconnect() prisma.$disconnect()
}) })
.catch(error => { .catch((error) => {
console.error(error) console.error(error)
prisma.$disconnect() prisma.$disconnect()
process.exit(1) process.exit(1)

View File

@ -1,7 +1,8 @@
import { Request, Response, Router } from 'express' import { Request, Response, Router } from "express"
import { AuthenticationService } from '../services/AuthenticationService.js' import { AuthenticationService } from "../services/AuthenticationService.js"
import { InvalidCredentialsError } from 'ldapts' import { InvalidCredentialsError } from "ldapts"
import { User } from '@prisma/client' import { User } from "@prisma/client"
import { authMiddleware } from "../middlewares/authMiddleware.js"
const router = Router() const router = Router()
@ -10,7 +11,7 @@ class LoginController {
const { username, password } = req.body const { username, password } = req.body
if (!username || !password) { if (!username || !password) {
res.status(400).json({ error: 'Usuário e senha devem ser informados!' }) res.status(400).json({ error: "Usuário e senha devem ser informados!" })
return return
} }
@ -19,7 +20,7 @@ class LoginController {
res.json({ token }) res.json({ token })
} catch (error: any) { } catch (error: any) {
if (error instanceof InvalidCredentialsError) { if (error instanceof InvalidCredentialsError) {
res.status(401).json({ error: 'Usuário ou senha inválidos' }) res.status(401).json({ error: "Usuário ou senha inválidos" })
return return
} }
res.status(401).json({ error: error.message }) res.status(401).json({ error: error.message })
@ -31,7 +32,7 @@ class LoginController {
} }
} }
router.post('/', LoginController.login) router.post("/", LoginController.login)
router.get('/me', LoginController.me) router.get("/me", authMiddleware, LoginController.me)
export default router export default router

View File

@ -1,9 +1,9 @@
import { Request, Response, Router } from 'express' import { Request, Response, Router } from "express"
import { hasRolesMiddleware } from '../middlewares/hasRolesMiddleware.js' import { hasRolesMiddleware } from "../middlewares/hasRolesMiddleware.js"
import { prisma } from '../prisma.js' import { prisma } from "../prisma.js"
import { distributedCopy } from '../utils/distributedCopy.js' import { distributedCopy } from "../utils/distributedCopy.js"
const router = Router() const router = Router()
@ -13,7 +13,7 @@ class PrinterController {
if (!campus) { if (!campus) {
const printers = await prisma.printer.findMany({ const printers = await prisma.printer.findMany({
include: { network: true } include: { network: true },
}) })
return res.json(printers) return res.json(printers)
} }
@ -21,10 +21,10 @@ class PrinterController {
const printers = await prisma.printer.findMany({ const printers = await prisma.printer.findMany({
where: { where: {
network: { network: {
shortName: String(campus) shortName: String(campus),
}
}, },
include: { network: true } },
include: { network: true },
}) })
return res.json(printers) return res.json(printers)
@ -42,23 +42,23 @@ class PrinterController {
status: { status: {
where: { where: {
timestamp: { timestamp: {
gte gte,
} },
}, },
orderBy: { orderBy: {
timestamp: 'desc' timestamp: "desc",
} },
} },
} },
}) })
if (printer) if (printer)
res.json({ res.json({
...printer, ...printer,
status: distributedCopy(printer.status, Number(take)) status: distributedCopy(printer.status, Number(take)),
}) })
else res.status(400).json({ error: 'Printer not found' }) else res.status(400).json({ error: "Printer not found" })
} }
static async edit(req: Request, res: Response) { static async edit(req: Request, res: Response) {
@ -67,18 +67,18 @@ class PrinterController {
// Verify if printer exists // Verify if printer exists
const printerExists = await prisma.printer.findUnique({ const printerExists = await prisma.printer.findUnique({
where: { id: Number(id) } where: { id: Number(id) },
}) })
if (printerExists) { if (printerExists) {
const printer = await prisma.printer.update({ const printer = await prisma.printer.update({
where: { id: Number(id) }, where: { id: Number(id) },
data: { friendlyName } data: { friendlyName },
}) })
res.json(printer) res.json(printer)
} else { } else {
res.status(400).json({ error: 'Printer not found' }) res.status(400).json({ error: "Printer not found" })
} }
} }
@ -87,15 +87,15 @@ class PrinterController {
await prisma.printer.delete({ where: { id: Number(id) } }) await prisma.printer.delete({ where: { id: Number(id) } })
res.json({ message: 'Printer deleted' }) res.json({ message: "Printer deleted" })
} }
} }
router.use(hasRolesMiddleware(['ADMIN', 'INSPECTOR'])) router.use(hasRolesMiddleware(["ADMIN", "INSPECTOR"]))
router.get('/', PrinterController.index) router.get("/", PrinterController.index)
router.get('/:id', PrinterController.show) router.get("/:id", PrinterController.show)
router.put('/:id', PrinterController.edit) router.put("/:id", PrinterController.edit)
router.delete('/:id', PrinterController.delete) router.delete("/:id", PrinterController.delete)
export default router export default router

View File

@ -1,7 +1,7 @@
import { Router, Request, Response } from 'express' import { Router, Request, Response } from "express"
import { hasRolesMiddleware } from '../middlewares/hasRolesMiddleware.js' import { hasRolesMiddleware } from "../middlewares/hasRolesMiddleware.js"
import { PrinterDiscoveryService } from '../services/PrinterDiscoveryService.js' import { PrinterDiscoveryService } from "../services/PrinterDiscoveryService.js"
const router = Router() const router = Router()
@ -12,8 +12,8 @@ class PrinterDiscoveryController {
} }
} }
router.use(hasRolesMiddleware(['ADMIN', 'INSPECTOR'])) router.use(hasRolesMiddleware(["ADMIN", "INSPECTOR"]))
router.post('/', PrinterDiscoveryController.discovery) router.post("/", PrinterDiscoveryController.discovery)
export default router export default router

View File

@ -1,7 +1,7 @@
import { Router, Request, Response } from 'express' import { Router, Request, Response } from "express"
import { prisma } from '../prisma.js' import { prisma } from "../prisma.js"
import { PrinterStatusService } from '../services/PrinterStatusService.js' import { PrinterStatusService } from "../services/PrinterStatusService.js"
import { hasRolesMiddleware } from '../middlewares/hasRolesMiddleware.js' import { hasRolesMiddleware } from "../middlewares/hasRolesMiddleware.js"
const router = Router() const router = Router()
@ -9,16 +9,16 @@ class PrinterStatusController {
static async update(req: Request, res: Response) { static async update(req: Request, res: Response) {
const printers = await prisma.printer.findMany() const printers = await prisma.printer.findMany()
printers.forEach(async printer => { printers.forEach(async (printer) => {
new PrinterStatusService(printer) new PrinterStatusService(printer)
}) })
res.json({ message: 'Updating printer status' }) res.json({ message: "Updating printer status" })
} }
} }
router.use(hasRolesMiddleware(['ADMIN', 'INSPECTOR'])) router.use(hasRolesMiddleware(["ADMIN", "INSPECTOR"]))
router.post('/update', PrinterStatusController.update) router.post("/update", PrinterStatusController.update)
export default router export default router

View File

@ -1,7 +1,7 @@
import 'dotenv/config' import "dotenv/config"
import { app } from './server.js' import { app } from "./server.js"
import { jobs } from './jobs.js' import { jobs } from "./jobs.js"
const PORT = 8000 const PORT = 8000
@ -9,7 +9,7 @@ const PORT = 8000
app.listen(PORT, () => { app.listen(PORT, () => {
console.log( console.log(
`Running in ${ `Running in ${
process.env.NODE_ENV == 'production' ? 'PRODUCTION' : 'DEVELOPMENT' process.env.NODE_ENV == "production" ? "PRODUCTION" : "DEVELOPMENT"
} mode. \nServer listening http://127.0.0.1:${PORT}` } mode. \nServer listening http://127.0.0.1:${PORT}`
) )
}) })

View File

@ -1,20 +1,20 @@
import * as path from 'node:path' import * as path from "node:path"
import { fileURLToPath } from 'node:url' import { fileURLToPath } from "node:url"
import Bree from 'bree' import Bree from "bree"
export const jobs = new Bree({ export const jobs = new Bree({
root: path.join(path.dirname(fileURLToPath(import.meta.url)), 'jobs'), root: path.join(path.dirname(fileURLToPath(import.meta.url)), "jobs"),
defaultExtension: process.env.NODE_ENV == 'production' ? 'js' : 'ts', defaultExtension: process.env.NODE_ENV == "production" ? "js" : "ts",
logger: false, logger: false,
jobs: [ jobs: [
{ {
name: 'updatePrinterStatus', name: "updatePrinterStatus",
interval: process.env.UPDATE_INTERVAL || '1m', interval: process.env.UPDATE_INTERVAL || "1m",
timeout: 0 timeout: 0,
}, },
{ {
name: 'discoverPrinters', name: "discoverPrinters",
cron: '0 */12 * * *' cron: "0 */12 * * *",
} },
] ],
}) })

View File

@ -1,4 +1,4 @@
import { PrinterDiscoveryService } from '../services/PrinterDiscoveryService.js' import { PrinterDiscoveryService } from "../services/PrinterDiscoveryService.js"
async function discoverPrinters() { async function discoverPrinters() {
console.log(`Discovering printers ${new Date().toLocaleString()}`) console.log(`Discovering printers ${new Date().toLocaleString()}`)

View File

@ -1,11 +1,11 @@
import { prisma } from '../prisma.js' import { prisma } from "../prisma.js"
import { PrinterStatusService } from '../services/PrinterStatusService.js' import { PrinterStatusService } from "../services/PrinterStatusService.js"
function updatePrinterStatus() { function updatePrinterStatus() {
console.log(`Updating printers status ${new Date().toLocaleString()}`) console.log(`Updating printers status ${new Date().toLocaleString()}`)
prisma.printer.findMany().then(printers => { prisma.printer.findMany().then((printers) => {
printers.forEach(async printer => { printers.forEach(async (printer) => {
new PrinterStatusService(printer) new PrinterStatusService(printer)
}) })
}) })

View File

@ -1,4 +1,4 @@
import { Response, NextFunction, Request } from 'express' import { Response, NextFunction, Request } from "express"
export async function authMiddleware( export async function authMiddleware(
req: Request, req: Request,
@ -7,7 +7,7 @@ export async function authMiddleware(
) { ) {
try { try {
if (!res.locals.user) { if (!res.locals.user) {
res.status(401).json({ error: 'Must be logged in' }) res.status(401).json({ error: "Must be logged in" })
return return
} }

View File

@ -1,14 +1,14 @@
import { Response, NextFunction, Request } from 'express' import { Response, NextFunction, Request } from "express"
import { Role } from '@prisma/client' import { Role } from "@prisma/client"
export function hasRolesMiddleware(roles: Role[]) { export function hasRolesMiddleware(roles: Role[]) {
return function (req: Request, res: Response, next: NextFunction) { return function (req: Request, res: Response, next: NextFunction) {
try { try {
const userRoles = res.locals.user?.roles const userRoles = res.locals.user?.roles
if (roles.some(role => userRoles?.includes(role))) next() if (roles.some((role) => userRoles?.includes(role))) next()
else res.status(401).json({ error: 'Not authorized!' }) else res.status(401).json({ error: "Not authorized!" })
} catch (error: any) { } catch (error: any) {
res.status(401).json({ error: error.message }) res.status(401).json({ error: error.message })
} }

View File

@ -1,4 +1,4 @@
import { Response, NextFunction, Request } from 'express' import { Response, NextFunction, Request } from "express"
export async function loggerMiddleware( export async function loggerMiddleware(
req: Request, req: Request,
@ -6,7 +6,7 @@ export async function loggerMiddleware(
next: NextFunction next: NextFunction
) { ) {
console.log( console.log(
'Request:', "Request:",
new Date().toLocaleString(), new Date().toLocaleString(),
req.method, req.method,
req.url, req.url,

View File

@ -1,13 +1,13 @@
import { NextFunction, Request, Response } from 'express' import { NextFunction, Request, Response } from "express"
import { AuthenticationService } from '../services/AuthenticationService.js' import { AuthenticationService } from "../services/AuthenticationService.js"
function getToken(req: Request) { function getToken(req: Request) {
const authHeader = req.headers.authorization as string const authHeader = req.headers.authorization as string
if (!authHeader) return null if (!authHeader) return null
const [type, token] = authHeader.split(' ') const [type, token] = authHeader.split(" ")
if (type !== 'Bearer') throw new Error('Expected a Bearer token') if (type !== "Bearer") throw new Error("Expected a Bearer token")
return token return token
} }
@ -24,7 +24,7 @@ export async function populateUserMiddleware(
const user = await AuthenticationService.jwtAuth(token) const user = await AuthenticationService.jwtAuth(token)
res.locals.user = user res.locals.user = user
} catch (error: any) { } catch (error: any) {
return res.status(401).json({ error: error.message }) res.locals.user = null
} }
} }

View File

@ -1,3 +1,3 @@
import { PrismaClient } from '@prisma/client' import { PrismaClient } from "@prisma/client"
export const prisma = new PrismaClient() export const prisma = new PrismaClient()

View File

@ -32,77 +32,79 @@ export type PrinterObjectIds = {
const objectIds: PrinterObjectIds[] = [ const objectIds: PrinterObjectIds[] = [
{ {
model: 'ECOSYS M3655idn', model: "ECOSYS M3655idn",
objectIds: { objectIds: {
model: '1.3.6.1.2.1.25.3.2.1.3.1', 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', 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', 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', location: "1.3.6.1.2.1.1.6.0",
toners: { toners: {
black: { black: {
current: '1.3.6.1.2.1.43.11.1.1.9.1.1', 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', 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: "1.3.6.1.2.1.43.11.1.1.6.1.1",
} },
} },
} },
}, },
{ {
model: 'ECOSYS P6235cdn', model: "ECOSYS P6235cdn",
objectIds: { objectIds: {
model: '1.3.6.1.2.1.25.3.2.1.3.1', 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', 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', 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', location: "1.3.6.1.2.1.1.6.0",
toners: { toners: {
black: { black: {
current: '1.3.6.1.2.1.43.11.1.1.9.1.4', 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', 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' model: "1.3.6.1.2.1.43.11.1.1.6.1.4",
}, },
cyan: { cyan: {
current: '1.3.6.1.2.1.43.11.1.1.9.1.1', 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', 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: "1.3.6.1.2.1.43.11.1.1.6.1.1",
}, },
magenta: { magenta: {
current: '1.3.6.1.2.1.43.11.1.1.9.1.2', 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', 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' model: "1.3.6.1.2.1.43.11.1.1.6.1.2",
}, },
yellow: { yellow: {
current: '1.3.6.1.2.1.43.11.1.1.9.1.3', 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', 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: "1.3.6.1.2.1.43.11.1.1.6.1.3",
} },
} },
} },
}, },
{ {
model: 'ECOSYS M2040dn', model: "ECOSYS M2040dn",
objectIds: { objectIds: {
model: '1.3.6.1.2.1.25.3.2.1.3.1', 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', 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', 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', location: "1.3.6.1.2.1.1.6.0",
toners: { toners: {
black: { black: {
current: '1.3.6.1.2.1.43.11.1.1.9.1.1', 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', 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: "1.3.6.1.2.1.43.11.1.1.6.1.1",
} },
} },
} },
} },
] ]
export class objectIdsRepository { export class objectIdsRepository {
private constructor() {} private constructor() {}
static getPrinterObjectIds(model: string): PrinterObjectIds { static getPrinterObjectIds(model: string): PrinterObjectIds {
const printerObjectIds = objectIds.find(printer => printer.model === model) const printerObjectIds = objectIds.find(
(printer) => printer.model === model
)
if (!printerObjectIds) throw new Error('Model not found') if (!printerObjectIds) throw new Error("Model not found")
return printerObjectIds return printerObjectIds
} }

View File

@ -1,32 +1,32 @@
import express, { Request, Response } from 'express' import express, { Request, Response } from "express"
import bodyParser from 'body-parser' import bodyParser from "body-parser"
import cors from 'cors' import cors from "cors"
import { populateUserMiddleware } from './middlewares/populateUserMiddleware.js' import { populateUserMiddleware } from "./middlewares/populateUserMiddleware.js"
import { authMiddleware } from './middlewares/authMiddleware.js' import { authMiddleware } from "./middlewares/authMiddleware.js"
import { loggerMiddleware } from './middlewares/loggerMiddleware.js' import { loggerMiddleware } from "./middlewares/loggerMiddleware.js"
import LoginRouter from './controllers/LoginController.js' import LoginRouter from "./controllers/LoginController.js"
import PrinterRouter from './controllers/PrinterController.js' import PrinterRouter from "./controllers/PrinterController.js"
import PrinterStatusRouter from './controllers/PrinterStatusController.js' import PrinterStatusRouter from "./controllers/PrinterStatusController.js"
import PrinterDiscoveryRouter from './controllers/PrinterDiscoveryController.js' import PrinterDiscoveryRouter from "./controllers/PrinterDiscoveryController.js"
export const app = express() export const app = express()
app.use(cors()) app.use(cors())
app.use(loggerMiddleware) app.use(loggerMiddleware)
app.use('/api', bodyParser.json()) app.use("/api", bodyParser.json())
app.use('/api', populateUserMiddleware) app.use("/api", populateUserMiddleware)
app.use('/api/login', LoginRouter) app.use("/api/login", LoginRouter)
app.use('/api/printer', PrinterRouter) app.use("/api/printer", PrinterRouter)
app.use('/api/printer-status', PrinterStatusRouter) app.use("/api/printer-status", PrinterStatusRouter)
app.use('/api/discovery', PrinterDiscoveryRouter) app.use("/api/discovery", PrinterDiscoveryRouter)
app.use('/', express.static('public')) app.use("/", express.static("public"))
app.get('*', (req, res) => { app.get("*", (req, res) => {
res.sendFile('index.html', { root: './public' }) res.sendFile("index.html", { root: "./public" })
}) })

View File

@ -1,10 +1,10 @@
import jwt from 'jsonwebtoken' import jwt from "jsonwebtoken"
import { prisma } from '../prisma.js' import { prisma } from "../prisma.js"
import { LdapService } from './LdapService.js' import { LdapService } from "./LdapService.js"
import { UserService } from './UserService.js' import { UserService } from "./UserService.js"
import { User } from '@prisma/client' import { User } from "@prisma/client"
const JWT_SECRET = process.env.JWT_SECRET || 'secret' const JWT_SECRET = process.env.JWT_SECRET || "secret"
export class AuthenticationService { export class AuthenticationService {
private constructor() {} private constructor() {}
@ -17,7 +17,7 @@ export class AuthenticationService {
await UserService.importUser(username) await UserService.importUser(username)
const token = jwt.sign({ username }, JWT_SECRET, { const token = jwt.sign({ username }, JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN || '30 days' expiresIn: process.env.JWT_EXPIRES_IN || "30 days",
}) })
return `Bearer ${token}` return `Bearer ${token}`
@ -28,7 +28,7 @@ export class AuthenticationService {
const { username } = jwt.verify(token, JWT_SECRET) as { username: string } const { username } = jwt.verify(token, JWT_SECRET) as { username: string }
const user = await prisma.user.findUnique({ const user = await prisma.user.findUnique({
where: { username } where: { username },
}) })
if (!user) return await UserService.importUser(username) if (!user) return await UserService.importUser(username)

View File

@ -1,9 +1,9 @@
import { Client } from 'ldapts' import { Client } from "ldapts"
const DOMAIN = process.env.AD_DOMAIN || 'IFMS' const DOMAIN = process.env.AD_DOMAIN || "IFMS"
const DN = process.env.AD_DN || 'DC=ifms,DC=edu,DC=br' const DN = process.env.AD_DN || "DC=ifms,DC=edu,DC=br"
const BIND_USER = process.env.AD_BIND_USER || '' const BIND_USER = process.env.AD_BIND_USER || ""
const BIND_PASSWD = process.env.AD_BIND_PASSWORD || '' const BIND_PASSWD = process.env.AD_BIND_PASSWORD || ""
interface LdapClientInterface extends Client { interface LdapClientInterface extends Client {
authenticate(username: string, password: string): Promise<void> authenticate(username: string, password: string): Promise<void>
@ -26,7 +26,7 @@ export class LdapService extends Client implements LdapClientInterface {
if (LdapService.instance) return LdapService.instance if (LdapService.instance) return LdapService.instance
super({ super({
url: `ldap://${process.env.AD_HOST}` url: `ldap://${process.env.AD_HOST}`,
}) })
LdapService.instance = this LdapService.instance = this
@ -50,21 +50,21 @@ export class LdapService extends Client implements LdapClientInterface {
async getUser(username: string): Promise<LdapUser> { async getUser(username: string): Promise<LdapUser> {
return await this.adminBondOperation(async () => { return await this.adminBondOperation(async () => {
const { searchEntries } = await this.search(DN, { const { searchEntries } = await this.search(DN, {
scope: 'sub', scope: "sub",
filter: `(sAMAccountName=${username})`, filter: `(sAMAccountName=${username})`,
attributes: [ attributes: [
'mail', "mail",
'sAMAccountName', "sAMAccountName",
'displayName', "displayName",
'thumbnailPhoto', "thumbnailPhoto",
'dn', "dn",
'extensionAttribute1' "extensionAttribute1",
], ],
explicitBufferAttributes: ['thumbnailPhoto'] explicitBufferAttributes: ["thumbnailPhoto"],
}) })
if (!searchEntries.length) if (!searchEntries.length)
throw new Error('User not found on LDAP server.') throw new Error("User not found on LDAP server.")
const { const {
sAMAccountName, sAMAccountName,
@ -72,7 +72,7 @@ export class LdapService extends Client implements LdapClientInterface {
mail, mail,
thumbnailPhoto, thumbnailPhoto,
dn, dn,
extensionAttribute1 extensionAttribute1,
} = searchEntries[0] } = searchEntries[0]
const ldapUser: LdapUser = { const ldapUser: LdapUser = {
@ -81,9 +81,9 @@ export class LdapService extends Client implements LdapClientInterface {
mail: mail.toString(), mail: mail.toString(),
thumbnailPhoto: `data:image/png;base64,${Buffer.from( thumbnailPhoto: `data:image/png;base64,${Buffer.from(
thumbnailPhoto as Buffer thumbnailPhoto as Buffer
).toString('base64')}`, ).toString("base64")}`,
groups: await this.getGroupsForUser(dn.toString()), groups: await this.getGroupsForUser(dn.toString()),
campus: extensionAttribute1?.toString().split('-')[0] || '--' campus: extensionAttribute1?.toString().split("-")[0] || "--",
} }
return ldapUser return ldapUser
@ -92,14 +92,14 @@ export class LdapService extends Client implements LdapClientInterface {
async getGroupsForUser(dn: string) { async getGroupsForUser(dn: string) {
const { searchEntries } = await this.search(DN, { const { searchEntries } = await this.search(DN, {
scope: 'sub', scope: "sub",
filter: `(member:1.2.840.113556.1.4.1941:=${dn})`, filter: `(member:1.2.840.113556.1.4.1941:=${dn})`,
attributes: ['cn'] attributes: ["cn"],
}) })
if (!searchEntries.length) throw new Error('User not found on LDAP server.') if (!searchEntries.length) throw new Error("User not found on LDAP server.")
return searchEntries.map(entry => entry.cn.toString()) return searchEntries.map((entry) => entry.cn.toString())
} }
async authenticate(username: string, password: string) { async authenticate(username: string, password: string) {

View File

@ -1,17 +1,17 @@
import snmp from 'net-snmp' import snmp from "net-snmp"
import netmask from 'netmask' import netmask from "netmask"
import { PrinterStatusService } from './PrinterStatusService.js' import { PrinterStatusService } from "./PrinterStatusService.js"
import { prisma } from '../prisma.js' import { prisma } from "../prisma.js"
import { Printer } from '@prisma/client' import { Printer } from "@prisma/client"
export class PrinterDiscoveryService { export class PrinterDiscoveryService {
private static async isPrinter(ip: string) { private static async isPrinter(ip: string) {
if (ip == '10.7.0.51') return false if (ip == "10.7.0.51") return false
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const session = snmp.createSession(ip, 'public', { timeout: 1000 }) const session = snmp.createSession(ip, "public", { timeout: 1000 })
const CHECK_OID = '1.3.6.1.2.1.1.1.0' const CHECK_OID = "1.3.6.1.2.1.1.1.0"
const CHECK_STRING = 'KYOCERA Document Solutions Printing System' const CHECK_STRING = "KYOCERA Document Solutions Printing System"
session.get( session.get(
[CHECK_OID], [CHECK_OID],
@ -40,18 +40,18 @@ export class PrinterDiscoveryService {
try { try {
const block = new netmask.Netmask(cdir) const block = new netmask.Netmask(cdir)
const BLACK_LISTED_IPS = ['10.7.1.1', '10.7.0.51'] const BLACK_LISTED_IPS = ["10.7.1.1", "10.7.0.51"]
block.forEach(ip => { block.forEach((ip) => {
if (!BLACK_LISTED_IPS.includes(ip)) blockIPs.push(ip) if (!BLACK_LISTED_IPS.includes(ip)) blockIPs.push(ip)
}) })
} catch (err) { } catch (err) {
throw new Error('Invalid IP CIDR') throw new Error("Invalid IP CIDR")
} }
try { try {
await Promise.allSettled( await Promise.allSettled(
blockIPs.map(async ip => { blockIPs.map(async (ip) => {
try { try {
if (await PrinterDiscoveryService.isPrinter(ip)) { if (await PrinterDiscoveryService.isPrinter(ip)) {
printers.push(ip) printers.push(ip)
@ -76,7 +76,7 @@ export class PrinterDiscoveryService {
const discoveredPrintersIPs: string[] = [] const discoveredPrintersIPs: string[] = []
for (const network of networks) { for (const network of networks) {
console.log('Discovering printers for network', network.cidr) console.log("Discovering printers for network", network.cidr)
try { try {
const discoveredPrintersIPsForNetwork = const discoveredPrintersIPsForNetwork =
@ -90,11 +90,11 @@ export class PrinterDiscoveryService {
const printers = await prisma.printer.findMany() const printers = await prisma.printer.findMany()
const newPrintersIPs = discoveredPrintersIPs.filter( const newPrintersIPs = discoveredPrintersIPs.filter(
ip => !printers.find(printer => printer.ip === ip) (ip) => !printers.find((printer) => printer.ip === ip)
) )
await Promise.allSettled( await Promise.allSettled(
newPrintersIPs.map(async ip => { newPrintersIPs.map(async (ip) => {
const model = await PrinterStatusService.getPrinterModel(ip) const model = await PrinterStatusService.getPrinterModel(ip)
const serialNumber = const serialNumber =
await PrinterStatusService.getPrinterSerialNumber(ip) await PrinterStatusService.getPrinterSerialNumber(ip)
@ -102,7 +102,7 @@ export class PrinterDiscoveryService {
const printer = await prisma.printer.upsert({ const printer = await prisma.printer.upsert({
where: { serialNumber }, where: { serialNumber },
create: { ip, model, networkId: network.id, serialNumber }, create: { ip, model, networkId: network.id, serialNumber },
update: { ip, model, networkId: network.id } update: { ip, model, networkId: network.id },
}) })
new PrinterStatusService(printer) new PrinterStatusService(printer)

View File

@ -1,10 +1,10 @@
import snmp from 'net-snmp' import snmp from "net-snmp"
import { Printer } from '@prisma/client' import { Printer } from "@prisma/client"
import { prisma } from '../prisma.js' import { prisma } from "../prisma.js"
import { import {
objectIdsRepository, objectIdsRepository,
PrinterObjectIds PrinterObjectIds,
} from '../repositories/ObjectIDRepository.js' } from "../repositories/ObjectIDRepository.js"
type VarbindString = { type VarbindString = {
oid: string oid: string
@ -43,10 +43,10 @@ export type PrinterInfo = {
export class PrinterStatusService { export class PrinterStatusService {
constructor(private printer: Printer) { constructor(private printer: Printer) {
this.getPrinterSnmpStatus().then(async printerStatus => { this.getPrinterSnmpStatus().then(async (printerStatus) => {
const lastStatus = await prisma.printerStatus.findFirst({ const lastStatus = await prisma.printerStatus.findFirst({
where: { printerId: this.printer.id }, where: { printerId: this.printer.id },
orderBy: { timestamp: 'desc' } orderBy: { timestamp: "desc" },
}) })
if ( if (
@ -58,7 +58,7 @@ export class PrinterStatusService {
) { ) {
await prisma.printerStatus.update({ await prisma.printerStatus.update({
where: { id: lastStatus.id }, where: { id: lastStatus.id },
data: { timestamp: new Date() } data: { timestamp: new Date() },
}) })
} else { } else {
console.log( console.log(
@ -80,10 +80,10 @@ export class PrinterStatusService {
tonerBlackLevel: printerStatus.toners.black.level, tonerBlackLevel: printerStatus.toners.black.level,
tonerCyanLevel: printerStatus.toners.cyan?.level, tonerCyanLevel: printerStatus.toners.cyan?.level,
tonerMagentaLevel: printerStatus.toners.magenta?.level, tonerMagentaLevel: printerStatus.toners.magenta?.level,
tonerYellowLevel: printerStatus.toners.yellow?.level tonerYellowLevel: printerStatus.toners.yellow?.level,
} },
} },
} },
}) })
} }
}) })
@ -94,7 +94,7 @@ export class PrinterStatusService {
function extractObjValues(obj: any) { function extractObjValues(obj: any) {
for (let key in obj) { for (let key in obj) {
if (typeof obj[key] === 'object') { if (typeof obj[key] === "object") {
extractObjValues(obj[key]) extractObjValues(obj[key])
} else { } else {
const oID = obj[key] const oID = obj[key]
@ -124,9 +124,9 @@ export class PrinterStatusService {
static getPrinterModel(ip: string): Promise<string> { static getPrinterModel(ip: string): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const snmpSession = snmp.createSession(ip, 'public') const snmpSession = snmp.createSession(ip, "public")
snmpSession.get( snmpSession.get(
['1.3.6.1.2.1.25.3.2.1.3.1'], ["1.3.6.1.2.1.25.3.2.1.3.1"],
(error: any, varbinds: any) => { (error: any, varbinds: any) => {
if (error) { if (error) {
reject(error) reject(error)
@ -141,9 +141,9 @@ export class PrinterStatusService {
static getPrinterSerialNumber(ip: string): Promise<string> { static getPrinterSerialNumber(ip: string): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const snmpSession = snmp.createSession(ip, 'public') const snmpSession = snmp.createSession(ip, "public")
snmpSession.get( snmpSession.get(
['1.3.6.1.2.1.43.5.1.1.17.1'], ["1.3.6.1.2.1.43.5.1.1.17.1"],
(error: any, varbinds: any) => { (error: any, varbinds: any) => {
if (error) { if (error) {
reject(error) reject(error)
@ -158,7 +158,7 @@ export class PrinterStatusService {
async getPrinterSnmpStatus(): Promise<PrinterInfo> { async getPrinterSnmpStatus(): Promise<PrinterInfo> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const session = snmp.createSession(this.printer.ip, 'public') const session = snmp.createSession(this.printer.ip, "public")
const oIDsArray = this.objectIdsArray() const oIDsArray = this.objectIdsArray()
@ -178,8 +178,8 @@ export class PrinterStatusService {
current: string | undefined, current: string | undefined,
max: string | undefined max: string | undefined
) { ) {
if (typeof current === 'undefined' || typeof max === 'undefined') if (typeof current === "undefined" || typeof max === "undefined")
throw new Error('current or max is undefined') throw new Error("current or max is undefined")
return Math.floor((+current! / +max!) * 100) return Math.floor((+current! / +max!) * 100)
} }
@ -191,56 +191,60 @@ export class PrinterStatusService {
objectIdsRepository.getPrinterObjectIds(this.printer.model) objectIdsRepository.getPrinterObjectIds(this.printer.model)
const printerInfo: PrinterInfo = { const printerInfo: PrinterInfo = {
counter: Number(snmpInfo.find(x => x.oid === objectIds.counter)?.value), counter: Number(snmpInfo.find((x) => x.oid === objectIds.counter)?.value),
location: snmpInfo.find(x => x.oid === objectIds.location) location: snmpInfo.find((x) => x.oid === objectIds.location)
?.value as string, ?.value as string,
toners: { toners: {
black: { black: {
level: this.calcTonerLevelPercentage( level: this.calcTonerLevelPercentage(
snmpInfo.find(x => x.oid === objectIds.toners.black.current)?.value, snmpInfo.find((x) => x.oid === objectIds.toners.black.current)
snmpInfo.find(x => x.oid === objectIds.toners.black.max)?.value ?.value,
snmpInfo.find((x) => x.oid === objectIds.toners.black.max)?.value
), ),
model: snmpInfo.find(x => x.oid === objectIds.toners.black.model) model: snmpInfo.find((x) => x.oid === objectIds.toners.black.model)
?.value as string ?.value as string,
}, },
cyan: objectIds.toners.cyan cyan: objectIds.toners.cyan
? { ? {
level: this.calcTonerLevelPercentage( level: this.calcTonerLevelPercentage(
snmpInfo.find(x => x.oid === objectIds.toners.cyan?.current) snmpInfo.find((x) => x.oid === objectIds.toners.cyan?.current)
?.value, ?.value,
snmpInfo.find(x => x.oid === objectIds.toners.cyan?.max)?.value snmpInfo.find((x) => x.oid === objectIds.toners.cyan?.max)
?.value
), ),
model: snmpInfo.find(x => x.oid === objectIds.toners.cyan?.model) model: snmpInfo.find(
?.value as string (x) => x.oid === objectIds.toners.cyan?.model
)?.value as string,
} }
: undefined, : undefined,
magenta: objectIds.toners.magenta magenta: objectIds.toners.magenta
? { ? {
level: this.calcTonerLevelPercentage( level: this.calcTonerLevelPercentage(
snmpInfo.find(x => x.oid === objectIds.toners.magenta?.current) snmpInfo.find(
?.value, (x) => x.oid === objectIds.toners.magenta?.current
snmpInfo.find(x => x.oid === objectIds.toners.magenta?.max) )?.value,
snmpInfo.find((x) => x.oid === objectIds.toners.magenta?.max)
?.value ?.value
), ),
model: snmpInfo.find( model: snmpInfo.find(
x => x.oid === objectIds.toners.magenta?.model (x) => x.oid === objectIds.toners.magenta?.model
)?.value as string )?.value as string,
} }
: undefined, : undefined,
yellow: objectIds.toners.yellow yellow: objectIds.toners.yellow
? { ? {
level: this.calcTonerLevelPercentage( level: this.calcTonerLevelPercentage(
snmpInfo.find(x => x.oid === objectIds.toners.yellow?.current) snmpInfo.find((x) => x.oid === objectIds.toners.yellow?.current)
?.value, ?.value,
snmpInfo.find(x => x.oid === objectIds.toners.yellow?.max) snmpInfo.find((x) => x.oid === objectIds.toners.yellow?.max)
?.value ?.value
), ),
model: snmpInfo.find( model: snmpInfo.find(
x => x.oid === objectIds.toners.yellow?.model (x) => x.oid === objectIds.toners.yellow?.model
)?.value as string )?.value as string,
}
: undefined
} }
: undefined,
},
} }
return printerInfo return printerInfo

View File

@ -1,10 +1,10 @@
import { User } from '@prisma/client' import { User } from "@prisma/client"
import { LdapService } from './LdapService.js' import { LdapService } from "./LdapService.js"
import { prisma } from '../prisma.js' import { prisma } from "../prisma.js"
const ADMIN_GROUP = process.env.ADMIN_GROUP || 'PP-SERTI' const ADMIN_GROUP = process.env.ADMIN_GROUP || "PP-SERTI"
const INSPECTOR_GROUP = process.env.INSPECTOR_GROUP || 'Inspectors' const INSPECTOR_GROUP = process.env.INSPECTOR_GROUP || "Inspectors"
const USER_GROUP = process.env.USER_GROUP || 'G_SERVIDORES' const USER_GROUP = process.env.USER_GROUP || "G_SERVIDORES"
export class UserService { export class UserService {
static async importUser(username: string) { static async importUser(username: string) {
@ -12,27 +12,27 @@ export class UserService {
const ldapUser = await ldap.getUser(username) const ldapUser = await ldap.getUser(username)
if (!ldapUser) throw new Error('User not found!') if (!ldapUser) throw new Error("User not found!")
const user: Omit<User, 'id' | 'createdAt' | 'updatedAt'> = { const user: Omit<User, "id" | "createdAt" | "updatedAt"> = {
username: ldapUser.username, username: ldapUser.username,
displayName: ldapUser.displayName, displayName: ldapUser.displayName,
mail: ldapUser.mail, mail: ldapUser.mail,
thumbnailPhoto: ldapUser.thumbnailPhoto, thumbnailPhoto: ldapUser.thumbnailPhoto,
campus: ldapUser.campus, campus: ldapUser.campus,
roles: [] roles: [],
} }
ldapUser.groups?.forEach(group => { ldapUser.groups?.forEach((group) => {
if (group === USER_GROUP) user.roles?.push('USER') if (group === USER_GROUP) user.roles?.push("USER")
if (group === ADMIN_GROUP) user.roles?.push('ADMIN') if (group === ADMIN_GROUP) user.roles?.push("ADMIN")
if (group === INSPECTOR_GROUP) user.roles?.push('INSPECTOR') if (group === INSPECTOR_GROUP) user.roles?.push("INSPECTOR")
}) })
return await prisma.user.upsert({ return await prisma.user.upsert({
where: { username: ldapUser.username }, where: { username: ldapUser.username },
update: user, update: user,
create: user create: user,
}) })
} }
} }

View File

@ -4,11 +4,11 @@ module.exports = {
node: true, node: true,
}, },
extends: [ extends: [
'plugin:vue/vue3-essential', "plugin:vue/vue3-essential",
'eslint:recommended', "eslint:recommended",
'@vue/eslint-config-typescript', "@vue/eslint-config-typescript",
], ],
rules: { rules: {
'vue/multi-word-component-names': 'off', "vue/multi-word-component-names": "off",
}, },
} }

BIN
web/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

View File

@ -1,27 +1,27 @@
const BASE_URL = process.env.BASE_URL || "http://localhost:8000/api/"; const BASE_URL = process.env.BASE_URL || "http://localhost:8000/api/"
export async function api<T>(endpoint: string, options: any): Promise<T> { export async function api<T>(endpoint: string, options: any): Promise<T> {
const token = localStorage.getItem("token"); const token = localStorage.getItem("token")
if (token) { if (token) {
options.headers = { options.headers = {
...options.headers, ...options.headers,
Authorization: token, Authorization: token,
}; }
} }
options.headers = { options.headers = {
...options.headers, ...options.headers,
"Content-Type": "application/json", "Content-Type": "application/json",
};
const response = await fetch(BASE_URL + endpoint, options);
const json = await response.json();
if (response.ok) {
return json;
} }
throw new Error(json.error); const response = await fetch(BASE_URL + endpoint, options)
const json = await response.json()
if (response.ok) {
return json
}
throw new Error(json.error)
} }

View File

@ -1,13 +1,13 @@
const LOCAL_STORAGE_KEY = "token"; const LOCAL_STORAGE_KEY = "token"
export function saveJwtToken(token: string) { export function saveJwtToken(token: string) {
localStorage.setItem(LOCAL_STORAGE_KEY, token); localStorage.setItem(LOCAL_STORAGE_KEY, token)
} }
export function getJwtToken() { export function getJwtToken() {
return localStorage.getItem(LOCAL_STORAGE_KEY); return localStorage.getItem(LOCAL_STORAGE_KEY)
} }
export function removeJwtToken() { export function removeJwtToken() {
localStorage.removeItem(LOCAL_STORAGE_KEY); localStorage.removeItem(LOCAL_STORAGE_KEY)
} }

View File

@ -5,16 +5,16 @@
*/ */
// Components // Components
import App from './App.vue' import App from "./App.vue"
// Composables // Composables
import { createApp } from 'vue' import { createApp } from "vue"
// Plugins // Plugins
import { registerPlugins } from '@/plugins' import { registerPlugins } from "@/plugins"
const app = createApp(App) const app = createApp(App)
registerPlugins(app) registerPlugins(app)
app.mount('#app') app.mount("#app")

View File

@ -5,18 +5,15 @@
*/ */
// Plugins // Plugins
import { loadFonts } from './webfontloader' import { loadFonts } from "./webfontloader"
import vuetify from './vuetify' import vuetify from "./vuetify"
import pinia from '../store' import pinia from "../store"
import router from '../router' import router from "../router"
// Types // Types
import type { App } from 'vue' import type { App } from "vue"
export function registerPlugins (app: App) { export function registerPlugins(app: App) {
loadFonts() loadFonts()
app app.use(vuetify).use(router).use(pinia)
.use(vuetify)
.use(router)
.use(pinia)
} }

View File

@ -5,11 +5,11 @@
*/ */
// Styles // Styles
import "@mdi/font/css/materialdesignicons.css"; import "@mdi/font/css/materialdesignicons.css"
import "vuetify/styles"; import "vuetify/styles"
// Composables // Composables
import { createVuetify } from "vuetify"; import { createVuetify } from "vuetify"
// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides // https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
export default createVuetify({ export default createVuetify({
@ -23,4 +23,4 @@ export default createVuetify({
}, },
}, },
}, },
}); })

View File

@ -4,12 +4,14 @@
* webfontloader documentation: https://github.com/typekit/webfontloader * webfontloader documentation: https://github.com/typekit/webfontloader
*/ */
export async function loadFonts () { export async function loadFonts() {
const webFontLoader = await import(/* webpackChunkName: "webfontloader" */'webfontloader') const webFontLoader = await import(
/* webpackChunkName: "webfontloader" */ "webfontloader"
)
webFontLoader.load({ webFontLoader.load({
google: { google: {
families: ['Roboto:100,300,400,500,700,900&display=swap'], families: ["Roboto:100,300,400,500,700,900&display=swap"],
}, },
}) })
} }

View File

@ -1,5 +1,5 @@
// Composables // Composables
import { createRouter, createWebHistory } from "vue-router"; import { createRouter, createWebHistory } from "vue-router"
const routes = [ const routes = [
{ {
@ -36,11 +36,11 @@ const routes = [
}, },
], ],
}, },
]; ]
const router = createRouter({ const router = createRouter({
history: createWebHistory(process.env.BASE_URL), history: createWebHistory(process.env.BASE_URL),
routes, routes,
}); })
export default router; export default router

View File

@ -1,28 +1,28 @@
// Utilities // Utilities
import { defineStore } from "pinia"; import { defineStore } from "pinia"
import { api } from "@/api"; import { api } from "@/api"
import { useRouter } from "vue-router"; import { useRouter } from "vue-router"
import { User } from "@prisma/client"; import { Printer, User } from "@prisma/client"
const router = useRouter()
export const useAppStore = defineStore("app", { export const useAppStore = defineStore("app", {
state: () => ({ state: () => ({
me: null as User | null, me: null as User | null,
printers: [], printers: [] as Printer[],
}), }),
actions: { actions: {
async fetchPrinters() { async fetchPrinters() {
this.printers = await api("printer", { method: "GET" }); this.printers = await api<Printer[]>("printer", { method: "GET" })
}, },
async fetchMe() { async fetchMe() {
const router = useRouter();
try { try {
this.me = await api<User>("login/me", { method: "GET" }); this.me = await api<User>("login/me", { method: "GET" })
} catch (error) { } catch (error) {
router.push({ name: "Login" }); router.push({ name: "Login" })
} }
}, },
}, },
}); })

View File

@ -1,4 +1,4 @@
// Utilities // Utilities
import { createPinia } from 'pinia' import { createPinia } from "pinia"
export default createPinia() export default createPinia()

View File

@ -1,6 +1,5 @@
<template> <template>
<div> <div>
<h1>Home</h1>
<printer-img model="ECOSYS P6235cdn" /> <printer-img model="ECOSYS P6235cdn" />
</div> </div>
</template> </template>

View File

@ -62,10 +62,21 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive } from "vue"; import { ref, reactive } from "vue";
import { api } from "@/api"; import { api } from "@/api";
import { saveJwtToken } from "@/auth"; import { getJwtToken, saveJwtToken } from "@/auth";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { useAppStore } from "@/store/app"; import { useAppStore } from "@/store/app";
const router = useRouter();
const token = getJwtToken();
const { fetchMe } = useAppStore();
if (token) {
fetchMe();
router.replace({ name: "Home" });
}
const username = ref<string>(""); const username = ref<string>("");
const password = ref<string>(""); const password = ref<string>("");
@ -74,10 +85,6 @@ const errors = reactive<string[]>([]);
const loading = ref(false); const loading = ref(false);
const router = useRouter();
const { fetchMe } = useAppStore();
async function login() { async function login() {
errors.splice(0, errors.length); errors.splice(0, errors.length);

View File

@ -1,7 +1,7 @@
/// <reference types="vite/client" /> /// <reference types="vite/client" />
declare module '*.vue' { declare module "*.vue" {
import type { DefineComponent } from 'vue' import type { DefineComponent } from "vue"
const component: DefineComponent<{}, {}, any> const component: DefineComponent<{}, {}, any>
export default component export default component
} }

View File

@ -14,9 +14,7 @@
"skipLibCheck": true, "skipLibCheck": true,
"noEmit": true, "noEmit": true,
"paths": { "paths": {
"@/*": [ "@/*": ["src/*"]
"src/*"
]
} }
}, },
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],

View File

@ -1,10 +1,10 @@
// Plugins // Plugins
import vue from "@vitejs/plugin-vue"; import vue from "@vitejs/plugin-vue"
import vuetify, { transformAssetUrls } from "vite-plugin-vuetify"; import vuetify, { transformAssetUrls } from "vite-plugin-vuetify"
// Utilities // Utilities
import { defineConfig } from "vite"; import { defineConfig } from "vite"
import { fileURLToPath, URL } from "node:url"; import { fileURLToPath, URL } from "node:url"
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
@ -31,4 +31,4 @@ export default defineConfig({
server: { server: {
port: 3000, port: 3000,
}, },
}); })