344 lines
7.3 KiB
TypeScript
344 lines
7.3 KiB
TypeScript
import bcrypt from "bcryptjs";
|
|
import { eq, sql } from "drizzle-orm";
|
|
import { Router } from "express";
|
|
import z from "zod";
|
|
import { db } from "../db/db.controller.js";
|
|
import {
|
|
type NewScanUser,
|
|
type ScanUser,
|
|
scanUser,
|
|
} from "../db/schema/scanUsers.js";
|
|
import { requireAuth } from "../middleware/auth.middleware.js";
|
|
import { apiReturn, returnFunc } from "../utils/returnHelper.utils.js";
|
|
import { tryCatch } from "../utils/trycatch.utils.js";
|
|
|
|
const r = Router();
|
|
|
|
export async function hashPin(pin: string) {
|
|
// if (!/^\d{6}$/.test(pin)) {
|
|
// throw new Error("PIN must be exactly 6 digits");
|
|
// }
|
|
|
|
return bcrypt.hashSync(pin, 12);
|
|
}
|
|
|
|
const registerSchema = z.object({
|
|
name: z.string().min(2).max(100),
|
|
pinNumber: z.string(),
|
|
scannerId: z
|
|
.string()
|
|
.min(1)
|
|
.max(500)
|
|
.optional()
|
|
.describe("if you leave blank it will be the same as your username"),
|
|
role: z
|
|
.enum(["user", "lead", "manager", "admin"])
|
|
.optional()
|
|
.describe("What roles are available to use."),
|
|
pinHash: z.string().optional(),
|
|
});
|
|
|
|
r.post("/pin", async (req, res) => {
|
|
const { pin } = req.body;
|
|
|
|
if (!pin || pin.length !== 6) {
|
|
return apiReturn(res, {
|
|
success: false,
|
|
level: "error",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message: `Pin number must be a min of 6 digits`,
|
|
data: [],
|
|
status: 401,
|
|
});
|
|
}
|
|
|
|
// const user = await db
|
|
// .select()
|
|
// .from(scanUser)
|
|
// .where(eq(scanUser.pinNumber, parseInt(pin, 10)));
|
|
|
|
const user = await db.query.scanUser.findFirst({
|
|
where: (u, { eq }) => eq(u.pinNumber, pin),
|
|
});
|
|
|
|
if (!user) {
|
|
return apiReturn(res, {
|
|
success: false,
|
|
level: "error",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message: `Invalid login please try again.`,
|
|
data: [],
|
|
status: 401,
|
|
});
|
|
}
|
|
|
|
const validPin = bcrypt.compareSync(pin, user.pinHash);
|
|
|
|
if (!validPin) {
|
|
return apiReturn(res, {
|
|
success: false,
|
|
level: "error",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message: `Invalid pin please try again.`,
|
|
data: [],
|
|
status: 401,
|
|
});
|
|
}
|
|
|
|
return apiReturn(res, {
|
|
success: true,
|
|
level: "info",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message: `Welcome back ${user.name}`,
|
|
data: user as ScanUser | any,
|
|
status: 200,
|
|
});
|
|
});
|
|
|
|
r.post("/user", async (req, res) => {
|
|
try {
|
|
// validate the body is correct before accepting it
|
|
let validated = registerSchema.parse(req.body);
|
|
|
|
validated = {
|
|
...validated,
|
|
pinHash: await hashPin(validated.pinNumber.toString()),
|
|
};
|
|
|
|
const values: NewScanUser = {
|
|
name: validated.name,
|
|
pinNumber: validated.pinNumber,
|
|
pinHash: validated.pinHash ?? "",
|
|
scannerId: validated.scannerId ?? "",
|
|
};
|
|
|
|
const newUser = await db.insert(scanUser).values(values).returning();
|
|
|
|
apiReturn(res, {
|
|
success: true,
|
|
level: "info", //connect.success ? "info" : "error",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message: `${validated.name} was just created`,
|
|
data: newUser as any,
|
|
status: 200, //connect.success ? 200 : 400,
|
|
});
|
|
} catch (err) {
|
|
if (err instanceof z.ZodError) {
|
|
const flattened = z.flattenError(err);
|
|
// return res.status(400).json({
|
|
// error: "Validation failed",
|
|
// details: flattened,
|
|
// });
|
|
|
|
return apiReturn(res, {
|
|
success: false,
|
|
level: "error", //connect.success ? "info" : "error",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message: "Validation failed",
|
|
data: [flattened.fieldErrors],
|
|
status: 400, //connect.success ? 200 : 400,
|
|
});
|
|
}
|
|
|
|
return apiReturn(res, {
|
|
success: false,
|
|
level: "error", //connect.success ? "info" : "error",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message:
|
|
"This User already exist with this pin or scanner id please try again",
|
|
data: [err],
|
|
status: 400, //connect.success ? 200 : 400,
|
|
});
|
|
}
|
|
});
|
|
|
|
r.get("/user", requireAuth, async (_, res) => {
|
|
const { data, error } = await tryCatch(db.select().from(scanUser));
|
|
|
|
// await trackLstEvent({
|
|
// eventName: "mobile_get_users",
|
|
// url: "/mobile/users",
|
|
// eventData: {
|
|
// module: "mobile",
|
|
// },
|
|
// });
|
|
|
|
if (error) {
|
|
return apiReturn(res, {
|
|
success: false,
|
|
level: "error",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message: `There was an error getting the user`,
|
|
data: error as any,
|
|
status: 400,
|
|
});
|
|
}
|
|
|
|
if (!data) {
|
|
return apiReturn(res, {
|
|
success: true,
|
|
level: "info",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message: `There are no users you should add one . `,
|
|
data: [],
|
|
status: 200,
|
|
});
|
|
}
|
|
|
|
return apiReturn(res, {
|
|
success: true,
|
|
level: "info",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message: `All users. `,
|
|
data,
|
|
status: 200,
|
|
});
|
|
});
|
|
|
|
r.patch("/user/:id", requireAuth, async (req, res) => {
|
|
const updates: Record<string, unknown | null> = {};
|
|
const { id } = req.params;
|
|
|
|
const { data, error } = await tryCatch(
|
|
db.query.scanUser.findFirst({
|
|
where: (u, { eq }) => eq(u.id, `${id}`),
|
|
}),
|
|
);
|
|
|
|
if (error) {
|
|
return apiReturn(res, {
|
|
success: false,
|
|
level: "error",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message: `There was an error getting the user`,
|
|
data: error as any,
|
|
status: 400,
|
|
});
|
|
}
|
|
|
|
if (!data) {
|
|
return apiReturn(res, {
|
|
success: false,
|
|
level: "error",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message: `Invalid user id was passed over. `,
|
|
data: [],
|
|
status: 400,
|
|
});
|
|
}
|
|
|
|
if (req.body?.name !== undefined) {
|
|
updates.name = req.body.name;
|
|
}
|
|
|
|
if (req.body?.pinNumber !== undefined) {
|
|
const existing = await db.query.scanUser.findFirst({
|
|
where: (u, { eq }) => eq(u.pinHash, req.body.pinNumber),
|
|
});
|
|
|
|
if (existing)
|
|
return returnFunc({
|
|
success: false,
|
|
level: "error",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message: `${req.body.pinNumber} already exists please try again`,
|
|
data: [],
|
|
notify: false,
|
|
room: "",
|
|
});
|
|
updates.pinNumber = req.body.pinNumber;
|
|
updates.pinHash = await hashPin(req.body.pinNumber);
|
|
}
|
|
|
|
if (req.body?.scannerId !== undefined) {
|
|
updates.scannerId = req.body.scannerId;
|
|
}
|
|
|
|
if (req.body?.active !== undefined) {
|
|
updates.active = req.body.active;
|
|
}
|
|
|
|
if (req.body?.excludedCommand !== undefined) {
|
|
updates.excludedCommand = req.body.excludedCommand;
|
|
}
|
|
|
|
if (req.body?.role !== undefined) {
|
|
updates.role = req.body.role;
|
|
}
|
|
|
|
updates.upd_date = sql`NOW()`;
|
|
|
|
const updatedSetting = await db
|
|
.update(scanUser)
|
|
.set(updates)
|
|
.where(eq(scanUser.id, `${id}`))
|
|
.returning();
|
|
|
|
return apiReturn(res, {
|
|
success: true,
|
|
level: "info",
|
|
module: "mobile",
|
|
subModule: "user",
|
|
message: `User ${data.name} was updated. `,
|
|
data: updatedSetting,
|
|
status: 200,
|
|
});
|
|
});
|
|
|
|
r.delete("/user/:id", requireAuth, async (req, res) => {
|
|
const { id } = req.params;
|
|
|
|
const { data, error } = await tryCatch(
|
|
db.delete(scanUser).where(eq(scanUser.id, `${id}`)),
|
|
);
|
|
|
|
if (error) {
|
|
return apiReturn(res, {
|
|
success: false,
|
|
level: "error",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message: `There was an error deleting the user`,
|
|
data: error as any,
|
|
status: 400,
|
|
});
|
|
}
|
|
|
|
if (!data) {
|
|
return apiReturn(res, {
|
|
success: false,
|
|
level: "error",
|
|
module: "mobile",
|
|
subModule: "auth",
|
|
message: `There was no user to delete. `,
|
|
data: [],
|
|
status: 400,
|
|
});
|
|
}
|
|
|
|
return apiReturn(res, {
|
|
success: true,
|
|
level: "info",
|
|
module: "mobile",
|
|
subModule: "user",
|
|
message: `User was deleted. `,
|
|
data: data ?? [],
|
|
status: 200,
|
|
});
|
|
});
|
|
|
|
export default r;
|