Package Updates

This commit is contained in:
Allan Carr
2024-07-23 09:49:47 -07:00
parent f295488195
commit 58055fd1b3
22 changed files with 1686 additions and 3807 deletions

18
.prettierrc.js Normal file
View File

@@ -0,0 +1,18 @@
const config = {
printWidth: 120,
useTabs: false,
tabWidth: 2,
trailingComma: "none",
semi: true,
singleQuote: false,
bracketSpacing: true,
arrowParens: "always",
jsxSingleQuote: false,
bracketSameLine: false,
endOfLine: "lf"
// importOrder: ["^@core/(.*)$", "^@server/(.*)$", "^@ui/(.*)$", "^[./]"],
// importOrderSeparation: true,
// importOrderSortSpecifiers: true
};
module.exports = config;

View File

@@ -1,4 +1,4 @@
FROM node:16 FROM node:20
# Create app directory # Create app directory
WORKDIR /usr/src/app WORKDIR /usr/src/app
@@ -28,9 +28,9 @@ RUN apt install -y libwebp-dev
# Install HEIF support (libheic-dev Package does not exist on 16.04) # Install HEIF support (libheic-dev Package does not exist on 16.04)
RUN apt-get -y install libde265-dev RUN apt-get -y install libde265-dev
RUN apt-get -y install pkg-config m4 libtool automake autoconf RUN apt-get -y install pkg-config m4 libtool automake autoconf
RUN wget https://github.com/strukturag/libheif/archive/v1.14.1.tar.gz RUN wget https://github.com/strukturag/libheif/archive/v1.18.0.tar.gz
RUN tar -xvf v1.14.1.tar.gz RUN tar -xvf v1.18.0.tar.gz
WORKDIR /usr/src/app/libheif-1.14.1/ WORKDIR /usr/src/app/libheif-1.18.0/
RUN ./autogen.sh RUN ./autogen.sh
RUN ./configure RUN ./configure
RUN make RUN make
@@ -46,9 +46,9 @@ RUN apt-get -y install wget && apt-get install -y ruby-full && ruby -v
# RUN apt-get install imagemagick -y # RUN apt-get install imagemagick -y
# # Install ImageMagick with WEBP and HEIC support # # Install ImageMagick with WEBP and HEIC support
RUN wget https://download.imagemagick.org/archive/releases/ImageMagick-7.1.1-13.tar.xz RUN wget https://download.imagemagick.org/archive/releases/ImageMagick-7.1.1-35.tar.xz
RUN tar -xvf ImageMagick-7.1.1-13.tar.xz RUN tar -xvf ImageMagick-7.1.1-35.tar.xz
WORKDIR /usr/src/app/ImageMagick-7.1.1-13/ WORKDIR /usr/src/app/ImageMagick-7.1.1-35/
RUN ./configure --with-heic=yes --with-webp=yes RUN ./configure --with-heic=yes --with-webp=yes
RUN make RUN make
RUN make install RUN make install

View File

@@ -1,10 +1,6 @@
import { Request, Response, NextFunction } from "express"; import { Request, Response, NextFunction } from "express";
export default function BillRequestValidator( export default function BillRequestValidator(req: Request, res: Response, next: NextFunction) {
req: Request,
res: Response,
next: NextFunction
) {
const vendorid: string = (req.body.vendorid || "").trim(); const vendorid: string = (req.body.vendorid || "").trim();
const invoice_number: string = (req.body.invoice_number || "").trim(); const invoice_number: string = (req.body.invoice_number || "").trim();
const jobid: string = (req.body.jobid || "").trim(); const jobid: string = (req.body.jobid || "").trim();

View File

@@ -22,17 +22,10 @@ export async function BillsListMedia(req: Request, res: Response) {
if (req.files) { if (req.files) {
ret = await Promise.all( ret = await Promise.all(
(req.files as Express.Multer.File[]).map(async (file) => { (req.files as Express.Multer.File[]).map(async (file) => {
const relativeFilePath: string = path.join( const relativeFilePath: string = path.join(PathToRoBillsFolder(jobid), file.filename);
PathToRoBillsFolder(jobid),
file.filename
);
const relativeThumbPath: string = await GenerateThumbnail( const relativeThumbPath: string = await GenerateThumbnail(relativeFilePath);
relativeFilePath const type: core.FileTypeResult | undefined = await ft.fileTypeFromFile(relativeFilePath);
);
const type: core.FileTypeResult | undefined = await ft.fromFile(
relativeFilePath
);
return { return {
type, type,
size: file.size, size: file.size,
@@ -41,72 +34,57 @@ export async function BillsListMedia(req: Request, res: Response) {
FolderPaths.JobsFolder, FolderPaths.JobsFolder,
jobid, jobid,
FolderPaths.BillsSubDir, FolderPaths.BillsSubDir,
file.filename, file.filename
]), ]),
thumbnail: GenerateUrl([ thumbnail: GenerateUrl([
FolderPaths.StaticPath, FolderPaths.StaticPath,
FolderPaths.JobsFolder, FolderPaths.JobsFolder,
jobid, jobid,
FolderPaths.BillsSubDir, FolderPaths.BillsSubDir,
relativeThumbPath, relativeThumbPath
]), ]),
thumbnailHeight: 250, thumbnailHeight: 250,
thumbnailWidth: 250, thumbnailWidth: 250,
filename: file.filename, filename: file.filename,
relativeFilePath, relativeFilePath
}; };
}) })
); );
} else { } else {
let filesList: fs.Dirent[] = ( let filesList: fs.Dirent[] = (
await fs.readdir(PathToRoBillsFolder(jobid), { await fs.readdir(PathToRoBillsFolder(jobid), {
withFileTypes: true, withFileTypes: true
}) })
).filter( ).filter(
(f) => (f) =>
f.isFile() && f.isFile() &&
!/(^|\/)\.[^\/\.]/g.test(f.name) && !/(^|\/)\.[^\/\.]/g.test(f.name) &&
(invoice_number !== "" (invoice_number !== "" ? f.name.toLowerCase().includes(invoice_number.toLowerCase()) : true) &&
? f.name.toLowerCase().includes(invoice_number.toLowerCase())
: true) &&
ListableChecker(f) ListableChecker(f)
); );
ret = await Promise.all( ret = await Promise.all(
filesList.map(async (file) => { filesList.map(async (file) => {
const relativeFilePath: string = path.join( const relativeFilePath: string = path.join(PathToRoBillsFolder(jobid), file.name);
PathToRoBillsFolder(jobid),
file.name
);
const relativeThumbPath: string = await GenerateThumbnail( const relativeThumbPath: string = await GenerateThumbnail(relativeFilePath);
relativeFilePath const type: core.FileTypeResult | undefined = await ft.fileTypeFromFile(relativeFilePath);
);
const type: core.FileTypeResult | undefined = await ft.fromFile(
relativeFilePath
);
const fileSize = await fs.stat(relativeFilePath); const fileSize = await fs.stat(relativeFilePath);
return { return {
type, type,
size: fileSize.size, size: fileSize.size,
src: GenerateUrl([ src: GenerateUrl([FolderPaths.StaticPath, FolderPaths.JobsFolder, jobid, FolderPaths.BillsSubDir, file.name]),
FolderPaths.StaticPath,
FolderPaths.JobsFolder,
jobid,
FolderPaths.BillsSubDir,
file.name,
]),
thumbnail: GenerateUrl([ thumbnail: GenerateUrl([
FolderPaths.StaticPath, FolderPaths.StaticPath,
FolderPaths.JobsFolder, FolderPaths.JobsFolder,
jobid, jobid,
FolderPaths.BillsSubDir, FolderPaths.BillsSubDir,
relativeThumbPath, relativeThumbPath
]), ]),
thumbnailHeight: 250, thumbnailHeight: 250,
thumbnailWidth: 250, thumbnailWidth: 250,
filename: file.name, filename: file.name,
relativeFilePath, relativeFilePath
}; };
}) })
); );

View File

@@ -5,18 +5,13 @@ import multer from "multer";
import path, { resolve } from "path"; import path, { resolve } from "path";
import { logger } from "../server"; import { logger } from "../server";
import GenerateThumbnail from "../util/generateThumbnail"; import GenerateThumbnail from "../util/generateThumbnail";
import generateUniqueFilename, { import generateUniqueFilename, { generateUniqueBillFilename } from "../util/generateUniqueFilename";
generateUniqueBillFilename,
} from "../util/generateUniqueFilename";
import { ConvertHeicFiles } from "../util/heicConverter"; import { ConvertHeicFiles } from "../util/heicConverter";
import { import { PathToRoBillsFolder, PathToVendorBillsFile } from "../util/pathGenerators";
PathToRoBillsFolder,
PathToVendorBillsFile,
} from "../util/pathGenerators";
import { BillsListMedia } from "./billsListMedia"; import { BillsListMedia } from "./billsListMedia";
dotenv.config({ dotenv.config({
path: resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`), path: resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
}); });
export const BillsMediaUploadMulter = multer({ export const BillsMediaUploadMulter = multer({
@@ -25,27 +20,20 @@ export const BillsMediaUploadMulter = multer({
const jobid: string = (req.body.jobid || "").trim(); const jobid: string = (req.body.jobid || "").trim();
const DestinationFolder: string = PathToRoBillsFolder(jobid); const DestinationFolder: string = PathToRoBillsFolder(jobid);
fs.ensureDirSync(DestinationFolder); fs.ensureDirSync(DestinationFolder);
cb( cb(jobid === "" || jobid === null ? new Error("Job ID not specified.") : null, DestinationFolder);
jobid === "" || jobid === null
? new Error("Job ID not specified.")
: null,
DestinationFolder
);
}, },
filename: function (req, file, cb) { filename: function (req, file, cb) {
logger.info("Uploading file: ", { logger.info("Uploading file: ", {
file: path.basename(file.originalname), file: path.basename(file.originalname)
}); });
const invoice_number: string = (req.body.invoice_number || "").trim(); const invoice_number: string = (req.body.invoice_number || "").trim();
cb( cb(
invoice_number === "" || invoice_number === null invoice_number === "" || invoice_number === null ? new Error("Invoice number not specified.") : null,
? new Error("Invoice number not specified.")
: null,
generateUniqueBillFilename(file, invoice_number) generateUniqueBillFilename(file, invoice_number)
); );
}, }
}), })
}); });
export async function BillsUploadMedia(req: Request, res: Response) { export async function BillsUploadMedia(req: Request, res: Response) {
@@ -53,7 +41,7 @@ export async function BillsUploadMedia(req: Request, res: Response) {
if (!req.files) { if (!req.files) {
res.send({ res.send({
status: false, status: false,
message: "No file uploaded", message: "No file uploaded"
}); });
} else { } else {
await ConvertHeicFiles(req.files as Express.Multer.File[]); await ConvertHeicFiles(req.files as Express.Multer.File[]);
@@ -76,10 +64,7 @@ export async function BillsUploadMedia(req: Request, res: Response) {
copyQueue.push( copyQueue.push(
(async () => { (async () => {
const target: string = path.join( const target: string = path.join(PathToVendorBillsFile(vendorid), file.filename);
PathToVendorBillsFile(vendorid),
file.filename
);
await fs.ensureDir(path.dirname(target)); await fs.ensureDir(path.dirname(target));
await fs.copyFile(file.path, target); await fs.copyFile(file.path, target);
})() })()
@@ -93,7 +78,7 @@ export async function BillsUploadMedia(req: Request, res: Response) {
} catch (error) { } catch (error) {
logger.error("Error while uploading Bill Media", { logger.error("Error while uploading Bill Media", {
files: req.files, files: req.files,
error, error
}); });
res.status(500).send(error); res.status(500).send(error);
} }

View File

@@ -3,6 +3,6 @@ module.exports = [
script: "dist/server.js", script: "dist/server.js",
name: "MediaServer", name: "MediaServer",
exec_mode: "cluster", exec_mode: "cluster",
instances: 0, instances: 0
}, }
]; ];

View File

@@ -1,10 +1,6 @@
import { Request, Response, NextFunction } from "express"; import { Request, Response, NextFunction } from "express";
export default function ValidateJobBasedRequest( export default function ValidateJobBasedRequest(req: Request, res: Response, next: NextFunction) {
req: Request,
res: Response,
next: NextFunction
) {
const jobid: string = (req.body.jobid || "").trim(); const jobid: string = (req.body.jobid || "").trim();
if (jobid === "") { if (jobid === "") {
res.status(400).json({ error: "No RO Number has been specified." }); res.status(400).json({ error: "No RO Number has been specified." });

View File

@@ -5,11 +5,7 @@ import { logger } from "../server";
import MediaFile from "../util/interfaces/MediaFile"; import MediaFile from "../util/interfaces/MediaFile";
import ListableChecker from "../util/listableChecker"; import ListableChecker from "../util/listableChecker";
import { PathToRoBillsFolder, PathToRoFolder } from "../util/pathGenerators"; import { PathToRoBillsFolder, PathToRoFolder } from "../util/pathGenerators";
import { import { BillsRelativeFilePath, FolderPaths, JobRelativeFilePath } from "../util/serverInit";
BillsRelativeFilePath,
FolderPaths,
JobRelativeFilePath,
} from "../util/serverInit";
export async function JobsDeleteMedia(req: Request, res: Response) { export async function JobsDeleteMedia(req: Request, res: Response) {
const jobid: string = (req.body.jobid || "").trim(); const jobid: string = (req.body.jobid || "").trim();
@@ -21,12 +17,12 @@ export async function JobsDeleteMedia(req: Request, res: Response) {
// Setup lists for both file locations // Setup lists for both file locations
const jobFileList: fs.Dirent[] = ( const jobFileList: fs.Dirent[] = (
await fs.readdir(PathToRoFolder(jobid), { await fs.readdir(PathToRoFolder(jobid), {
withFileTypes: true, withFileTypes: true
}) })
).filter((f) => f.isFile() && ListableChecker(f)); ).filter((f) => f.isFile() && ListableChecker(f));
const billFileList: fs.Dirent[] = ( const billFileList: fs.Dirent[] = (
await fs.readdir(PathToRoBillsFolder(jobid), { await fs.readdir(PathToRoBillsFolder(jobid), {
withFileTypes: true, withFileTypes: true
}) })
).filter((f) => f.isFile() && ListableChecker(f)); ).filter((f) => f.isFile() && ListableChecker(f));
@@ -37,12 +33,7 @@ export async function JobsDeleteMedia(req: Request, res: Response) {
// File is in the set of requested files. // File is in the set of requested files.
await fs.remove(JobRelativeFilePath(jobid, file.name)); await fs.remove(JobRelativeFilePath(jobid, file.name));
await fs.remove( await fs.remove(
path.join( path.join(FolderPaths.Jobs, jobid, FolderPaths.ThumbsSubDir, file.name.replace(/\.[^/.]+$/, ".png"))
FolderPaths.Jobs,
jobid,
FolderPaths.ThumbsSubDir,
file.name.replace(/\.[^/.]+$/, ".png")
)
); );
} }
}) })

View File

@@ -22,12 +22,12 @@ export async function jobsDownloadMedia(req: Request, res: Response) {
const jobFileList: fs.Dirent[] = ( const jobFileList: fs.Dirent[] = (
await fs.readdir(PathToRoFolder(jobid), { await fs.readdir(PathToRoFolder(jobid), {
withFileTypes: true, withFileTypes: true
}) })
).filter((f) => f.isFile() && ListableChecker(f)); ).filter((f) => f.isFile() && ListableChecker(f));
const billFileList: fs.Dirent[] = ( const billFileList: fs.Dirent[] = (
await fs.readdir(PathToRoBillsFolder(jobid), { await fs.readdir(PathToRoBillsFolder(jobid), {
withFileTypes: true, withFileTypes: true
}) })
).filter((f) => f.isFile() && ListableChecker(f)); ).filter((f) => f.isFile() && ListableChecker(f));
@@ -36,18 +36,14 @@ export async function jobsDownloadMedia(req: Request, res: Response) {
await Promise.all( await Promise.all(
jobFileList.map(async (file) => { jobFileList.map(async (file) => {
//Do something async //Do something async
const fileOnDisk: Buffer = await fs.readFile( const fileOnDisk: Buffer = await fs.readFile(JobRelativeFilePath(jobid, file.name));
JobRelativeFilePath(jobid, file.name)
);
zip.file(path.parse(path.basename(file.name)).base, fileOnDisk); zip.file(path.parse(path.basename(file.name)).base, fileOnDisk);
}) })
); );
await Promise.all( await Promise.all(
billFileList.map(async (file) => { billFileList.map(async (file) => {
//Do something async //Do something async
const fileOnDisk: Buffer = await fs.readFile( const fileOnDisk: Buffer = await fs.readFile(BillsRelativeFilePath(jobid, file.name));
BillsRelativeFilePath(jobid, file.name)
);
zip.file(path.parse(path.basename(file.name)).base, fileOnDisk); zip.file(path.parse(path.basename(file.name)).base, fileOnDisk);
}) })
); );
@@ -57,23 +53,19 @@ export async function jobsDownloadMedia(req: Request, res: Response) {
jobFileList.map(async (file) => { jobFileList.map(async (file) => {
if (files.includes(path.parse(path.basename(file.name)).base)) { if (files.includes(path.parse(path.basename(file.name)).base)) {
// File is in the set of requested files. // File is in the set of requested files.
const fileOnDisk: Buffer = await fs.readFile( const fileOnDisk: Buffer = await fs.readFile(JobRelativeFilePath(jobid, file.name));
JobRelativeFilePath(jobid, file.name)
);
zip.file(path.parse(path.basename(file.name)).base, fileOnDisk); zip.file(path.parse(path.basename(file.name)).base, fileOnDisk);
} }
}), })
); );
await Promise.all( await Promise.all(
billFileList.map(async (file) => { billFileList.map(async (file) => {
if (files.includes(path.parse(path.basename(file.name)).base)) { if (files.includes(path.parse(path.basename(file.name)).base)) {
// File is in the set of requested files. // File is in the set of requested files.
const fileOnDisk: Buffer = await fs.readFile( const fileOnDisk: Buffer = await fs.readFile(BillsRelativeFilePath(jobid, file.name));
BillsRelativeFilePath(jobid, file.name)
);
zip.file(path.parse(path.basename(file.name)).base, fileOnDisk); zip.file(path.parse(path.basename(file.name)).base, fileOnDisk);
} }
}), })
); );
} }
//Send it as a response to download it automatically. //Send it as a response to download it automatically.
@@ -82,14 +74,14 @@ export async function jobsDownloadMedia(req: Request, res: Response) {
zip zip
.generateNodeStream({ .generateNodeStream({
type: "nodebuffer", type: "nodebuffer",
streamFiles: true, streamFiles: true
//encodeFileName: (filename) => `${jobid}.zip`, //encodeFileName: (filename) => `${jobid}.zip`,
}) })
.pipe(res); .pipe(res);
} catch (error) { } catch (error) {
logger.error("Error downloading job media.", { logger.error("Error downloading job media.", {
jobid, jobid,
error: (error as Error).message, error: (error as Error).message
}); });
res.status(500).json((error as Error).message); res.status(500).json((error as Error).message);
} }

View File

@@ -20,81 +20,47 @@ export async function JobsListMedia(req: Request, res: Response) {
//We just uploaded files, we're going to send only those back. //We just uploaded files, we're going to send only those back.
ret = await Promise.all( ret = await Promise.all(
(req.files as Express.Multer.File[]).map(async (file) => { (req.files as Express.Multer.File[]).map(async (file) => {
const relativeFilePath: string = JobRelativeFilePath( const relativeFilePath: string = JobRelativeFilePath(jobid, file.filename);
jobid,
file.filename
);
const relativeThumbPath: string = await GenerateThumbnail( const relativeThumbPath: string = await GenerateThumbnail(relativeFilePath);
relativeFilePath
);
const type: core.FileTypeResult | undefined = await ft.fromFile( const type: core.FileTypeResult | undefined = await ft.fileTypeFromFile(relativeFilePath);
relativeFilePath
);
return { return {
type, type,
size: file.size, size: file.size,
src: GenerateUrl([ src: GenerateUrl([FolderPaths.StaticPath, FolderPaths.JobsFolder, jobid, file.filename]),
FolderPaths.StaticPath, thumbnail: GenerateUrl([FolderPaths.StaticPath, FolderPaths.JobsFolder, jobid, relativeThumbPath]),
FolderPaths.JobsFolder,
jobid,
file.filename,
]),
thumbnail: GenerateUrl([
FolderPaths.StaticPath,
FolderPaths.JobsFolder,
jobid,
relativeThumbPath,
]),
thumbnailHeight: 250, thumbnailHeight: 250,
thumbnailWidth: 250, thumbnailWidth: 250,
filename: file.filename, filename: file.filename,
relativeFilePath, relativeFilePath
}; };
}) })
); );
} else { } else {
const filesList: fs.Dirent[] = ( const filesList: fs.Dirent[] = (
await fs.readdir(PathToRoFolder(jobid), { await fs.readdir(PathToRoFolder(jobid), {
withFileTypes: true, withFileTypes: true
}) })
).filter((f) => f.isFile() && ListableChecker(f)); ).filter((f) => f.isFile() && ListableChecker(f));
ret = await Promise.all( ret = await Promise.all(
filesList.map(async (file) => { filesList.map(async (file) => {
const relativeFilePath: string = JobRelativeFilePath( const relativeFilePath: string = JobRelativeFilePath(jobid, file.name);
jobid,
file.name
);
const relativeThumbPath: string = await GenerateThumbnail( const relativeThumbPath: string = await GenerateThumbnail(relativeFilePath);
relativeFilePath const type: core.FileTypeResult | undefined = await ft.fileTypeFromFile(relativeFilePath);
);
const type: core.FileTypeResult | undefined = await ft.fromFile(
relativeFilePath
);
const fileSize = await fs.stat(relativeFilePath); const fileSize = await fs.stat(relativeFilePath);
return { return {
type, type,
size: fileSize.size, size: fileSize.size,
src: GenerateUrl([ src: GenerateUrl([FolderPaths.StaticPath, FolderPaths.JobsFolder, jobid, file.name]),
FolderPaths.StaticPath, thumbnail: GenerateUrl([FolderPaths.StaticPath, FolderPaths.JobsFolder, jobid, relativeThumbPath]),
FolderPaths.JobsFolder,
jobid,
file.name,
]),
thumbnail: GenerateUrl([
FolderPaths.StaticPath,
FolderPaths.JobsFolder,
jobid,
relativeThumbPath,
]),
thumbnailHeight: 250, thumbnailHeight: 250,
thumbnailWidth: 250, thumbnailWidth: 250,
filename: file.name, filename: file.name,
relativeFilePath, relativeFilePath
}; };
}) })
); );

View File

@@ -26,14 +26,14 @@ export async function JobsMoveMedia(req: Request, res: Response) {
// Setup lists for both file locations // Setup lists for both file locations
const jobFileList: string[] = ( const jobFileList: string[] = (
await fs.readdir(PathToRoFolder(from_jobid), { await fs.readdir(PathToRoFolder(from_jobid), {
withFileTypes: true, withFileTypes: true
}) })
) )
.filter((f) => f.isFile() && ListableChecker(f)) .filter((f) => f.isFile() && ListableChecker(f))
.map((dirent) => dirent.name); .map((dirent) => dirent.name);
const billFileList: string[] = ( const billFileList: string[] = (
await fs.readdir(PathToRoBillsFolder(from_jobid), { await fs.readdir(PathToRoBillsFolder(from_jobid), {
withFileTypes: true, withFileTypes: true
}) })
) )
.filter((f) => f.isFile() && ListableChecker(f)) .filter((f) => f.isFile() && ListableChecker(f))
@@ -47,38 +47,20 @@ export async function JobsMoveMedia(req: Request, res: Response) {
files.forEach((file) => { files.forEach((file) => {
if (jobFileList.includes(file)) { if (jobFileList.includes(file)) {
movingQueue.push( movingQueue.push(
fs.move( fs.move(path.join(FolderPaths.Jobs, from_jobid, file), path.join(FolderPaths.Jobs, jobid, file))
path.join(FolderPaths.Jobs, from_jobid, file),
path.join(FolderPaths.Jobs, jobid, file)
)
); );
movingQueue.push( movingQueue.push(
fs.move( fs.move(
path.join( path.join(FolderPaths.Jobs, from_jobid, FolderPaths.ThumbsSubDir, file.replace(/\.[^/.]+$/, ".png")),
FolderPaths.Jobs, path.join(FolderPaths.Jobs, jobid, FolderPaths.ThumbsSubDir, file.replace(/\.[^/.]+$/, ".png"))
from_jobid,
FolderPaths.ThumbsSubDir,
file.replace(/\.[^/.]+$/, ".png")
),
path.join(
FolderPaths.Jobs,
jobid,
FolderPaths.ThumbsSubDir,
file.replace(/\.[^/.]+$/, ".png")
)
) )
); );
} }
if (billFileList.includes(file)) { if (billFileList.includes(file)) {
movingQueue.push( movingQueue.push(
fs.move( fs.move(
path.join( path.join(FolderPaths.Jobs, from_jobid, FolderPaths.BillsSubDir, file),
FolderPaths.Jobs,
from_jobid,
FolderPaths.BillsSubDir,
file
),
path.join(FolderPaths.Jobs, jobid, FolderPaths.BillsSubDir, file) path.join(FolderPaths.Jobs, jobid, FolderPaths.BillsSubDir, file)
) )
); );
@@ -114,7 +96,7 @@ export async function JobsMoveMedia(req: Request, res: Response) {
from_jobid, from_jobid,
jobid, jobid,
files, files,
err, err
}); });
res.status(500).send(err); res.status(500).send(err);
} }

View File

@@ -15,20 +15,15 @@ export const JobMediaUploadMulter = multer({
const jobid: string = (req.body.jobid || "").trim(); const jobid: string = (req.body.jobid || "").trim();
const DestinationFolder: string = PathToRoFolder(jobid); const DestinationFolder: string = PathToRoFolder(jobid);
fs.ensureDirSync(DestinationFolder); fs.ensureDirSync(DestinationFolder);
cb( cb(jobid === "" || jobid === null ? new Error("Job ID not specified.") : null, DestinationFolder);
jobid === "" || jobid === null
? new Error("Job ID not specified.")
: null,
DestinationFolder
);
}, },
filename: function (req, file, cb) { filename: function (req, file, cb) {
logger.debug("Uploading file: ", { logger.debug("Uploading file: ", {
file: path.basename(file.originalname), file: path.basename(file.originalname)
}); });
cb(null, generateUniqueFilename(file)); cb(null, generateUniqueFilename(file));
}, }
}), })
}); });
export async function jobsUploadMedia(req: Request, res: Response) { export async function jobsUploadMedia(req: Request, res: Response) {
@@ -39,7 +34,7 @@ export async function jobsUploadMedia(req: Request, res: Response) {
logger.warning("Upload contained no files."); logger.warning("Upload contained no files.");
res.status(400).send({ res.status(400).send({
status: false, status: false,
message: "No file uploaded", message: "No file uploaded"
}); });
} else { } else {
//If we want to skip waiting for everything, just send it back that we're good. //If we want to skip waiting for everything, just send it back that we're good.
@@ -69,7 +64,7 @@ export async function jobsUploadMedia(req: Request, res: Response) {
} catch (error) { } catch (error) {
logger.error("Error uploading job media.", { logger.error("Error uploading job media.", {
jobid, jobid,
error: (error as Error).message, error: (error as Error).message
}); });
res.status(500).json((error as Error).message); res.status(500).json((error as Error).message);
} }

3558
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,48 +1,50 @@
{ {
"name": "bodyshop-media-server", "name": "bodyshop-media-server",
"version": "1.0.10", "version": "1.0.12",
"license": "UNLICENSED", "license": "UNLICENSED",
"engines": { "engines": {
"node": "^16.14.0" "node": ">=18.0.0"
}, },
"scripts": { "scripts": {
"server": "nodemon server.ts", "server": "nodemon server.ts",
"start": "node dist/server.js", "start": "node dist/server.js",
"build": "tsc -p ." "build": "tsc -p .",
"makeitpretty": "prettier --write \"**/*.{css,js,json,jsx,scss,ts}\""
}, },
"dependencies": { "dependencies": {
"axios": "^0.24.0", "axios": "^1.7.2",
"bluebird": "^3.7.2", "bluebird": "^3.7.2",
"body-parser": "^1.20.0", "body-parser": "^1.20.2",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "10.0.0", "dotenv": "16.4.5",
"express": "^4.17.3", "express": "^4.19.2",
"file-type": "^16.5.3", "file-type": "^19.2.0",
"fs-extra": "^10.1.0", "fs-extra": "^11.2.0",
"gm": "^1.23.1", "gm": "^1.25.0",
"helmet": "^5.0.2", "helmet": "^7.1.0",
"image-thumbnail": "^1.0.14", "image-thumbnail": "^1.0.15",
"jszip": "^3.10.0", "jszip": "^3.10.1",
"morgan": "^1.10.0", "morgan": "^1.10.0",
"multer": "^1.4.4", "multer": "^1.4.4",
"nocache": "^3.0.4", "nocache": "^4.0.0",
"response-time": "^2.3.2", "response-time": "^2.3.2",
"simple-thumbnail": "^1.6.5", "simple-thumbnail": "^1.6.5",
"winston": "^3.7.2", "winston": "^3.13.1",
"winston-daily-rotate-file": "^4.6.1" "winston-daily-rotate-file": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/cors": "^2.8.12", "@types/cors": "^2.8.17",
"@types/express": "^4.17.13", "@types/express": "^4.17.21",
"@types/fs-extra": "^9.0.13", "@types/fs-extra": "^11.0.4",
"@types/gm": "^1.18.11", "@types/gm": "^1.25.4",
"@types/image-thumbnail": "^1.0.1", "@types/image-thumbnail": "^1.0.4",
"@types/morgan": "^1.9.3", "@types/morgan": "^1.9.9",
"@types/multer": "^1.4.7", "@types/multer": "^1.4.11",
"@types/node": "^16.11.32", "@types/node": "^20.14.11",
"@types/response-time": "^2.3.5", "@types/response-time": "^2.3.8",
"nodemon": "^2.0.15", "nodemon": "^3.1.4",
"ts-node": "^10.7.0", "prettier": "^3.3.3",
"typescript": "^4.6.4" "ts-node": "^10.9.2",
"typescript": "^5.5.3"
} }
} }

View File

@@ -42,14 +42,13 @@ services:
command: # CLI arguments command: # CLI arguments
- --global.checkNewVersion=true - --global.checkNewVersion=true
- --global.sendAnonymousUsage=false - --global.sendAnonymousUsage=false
- --pilot.dashboard=false
- --entrypoints.https.address=:10443 - --entrypoints.https.address=:10443
- --entrypoints.https.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/12,172.64.0.0/13,131.0.72.0/22,2400:cb00::/32,2606:4700::/32,2803:f800::/32,2405:b500::/32,2405:8100::/32,2a06:98c0::/29,2c0f:f248::/32 - --entrypoints.https.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/12,172.64.0.0/13,131.0.72.0/22,2400:cb00::/32,2606:4700::/32,2803:f800::/32,2405:b500::/32,2405:8100::/32,2a06:98c0::/29,2c0f:f248::/32
- --log=true - --log=true
- --log.level=ERROR # (Default: error) DEBUG, INFO, WARN, ERROR, FATAL, PANIC - --log.level=ERROR # (Default: error) DEBUG, INFO, WARN, ERROR, FATAL, PANIC
- --providers.docker=true - --providers.docker=true
- --providers.docker.exposedbydefault=false - --providers.docker.exposedbydefault=false
- --providers.docker.network=t2_proxy - --providers.docker.network=traefik_proxy
- --certificatesResolvers.dns-cloudflare.acme.email=cloudflare@thinkimex.com - --certificatesResolvers.dns-cloudflare.acme.email=cloudflare@thinkimex.com
- --certificatesResolvers.dns-cloudflare.acme.storage=/acme.json - --certificatesResolvers.dns-cloudflare.acme.storage=/acme.json
- --certificatesResolvers.dns-cloudflare.acme.keyType=EC384 - --certificatesResolvers.dns-cloudflare.acme.keyType=EC384
@@ -57,7 +56,7 @@ services:
- --certificatesresolvers.dns-cloudflare.acme.dnschallenge.resolvers=1.1.1.1:53,1.0.0.1:53,2606:4700:4700::1111:53,2606:4700:4700::1001:53 - --certificatesresolvers.dns-cloudflare.acme.dnschallenge.resolvers=1.1.1.1:53,1.0.0.1:53,2606:4700:4700::1111:53,2606:4700:4700::1001:53
- --certificatesResolvers.dns-cloudflare.acme.dnsChallenge.delayBeforeCheck=90 # To delay DNS check and reduce LE hitrate - --certificatesResolvers.dns-cloudflare.acme.dnsChallenge.delayBeforeCheck=90 # To delay DNS check and reduce LE hitrate
networks: networks:
t2_proxy: traefik_proxy:
ipv4_address: 192.168.90.254 ipv4_address: 192.168.90.254
ports: ports:
- target: 10443 - target: 10443
@@ -77,7 +76,7 @@ services:
container_name: cf-ddns container_name: cf-ddns
image: oznu/cloudflare-ddns:latest image: oznu/cloudflare-ddns:latest
networks: networks:
- t2_proxy - traefik_proxy
restart: always restart: always
environment: environment:
- API_KEY=b8BWRbkJckVK0IG6600Iq5AYx4HYZ7dLzDWUOZ2D - API_KEY=b8BWRbkJckVK0IG6600Iq5AYx4HYZ7dLzDWUOZ2D
@@ -92,7 +91,7 @@ services:
ims: ims:
container_name: ims container_name: ims
networks: networks:
- t2_proxy - traefik_proxy
volumes: volumes:
- /mnt/ims:/media - /mnt/ims:/media
environment: environment:
@@ -117,7 +116,7 @@ services:
image: amir20/dozzle:latest image: amir20/dozzle:latest
restart: always restart: always
networks: networks:
- t2_proxy - traefik_proxy
ports: ports:
- "8080:8080" - "8080:8080"
security_opt: security_opt:
@@ -135,7 +134,7 @@ services:
container_name: watchtower-ims container_name: watchtower-ims
image: containrrr/watchtower image: containrrr/watchtower
networks: networks:
- t2_proxy - traefik_proxy
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
environment: environment:
@@ -154,8 +153,8 @@ services:
- "traefik.enable=false" - "traefik.enable=false"
networks: networks:
t2_proxy: traefik_proxy:
name: t2_proxy name: traefik_proxy
driver: bridge driver: bridge
ipam: ipam:
config: config:

View File

@@ -16,24 +16,17 @@ import cors from "cors";
import helmet from "helmet"; import helmet from "helmet";
import responseTime from "response-time"; import responseTime from "response-time";
import nocache from "nocache"; import nocache from "nocache";
import { import { BillsMediaUploadMulter, BillsUploadMedia } from "./bills/billsUploadMedia";
BillsMediaUploadMulter,
BillsUploadMedia,
} from "./bills/billsUploadMedia";
import ValidateImsToken from "./util/validateToken"; import ValidateImsToken from "./util/validateToken";
import { jobsDownloadMedia } from "./jobs/jobsDownloadMedia"; import { jobsDownloadMedia } from "./jobs/jobsDownloadMedia";
import { JobsDeleteMedia } from "./jobs/jobsDeleteMedia"; import { JobsDeleteMedia } from "./jobs/jobsDeleteMedia";
dotenv.config({ dotenv.config({
path: resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`), path: resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
}); });
export const logger = winston.createLogger({ export const logger = winston.createLogger({
format: winston.format.combine( format: winston.format.combine(winston.format.timestamp(), winston.format.json(), winston.format.prettyPrint()),
winston.format.timestamp(),
winston.format.json(),
winston.format.prettyPrint()
),
level: "http", level: "http",
levels: { ...winston.config.syslog.levels, http: 8 }, levels: { ...winston.config.syslog.levels, http: 8 },
exceptionHandlers: [ exceptionHandlers: [
@@ -42,14 +35,11 @@ export const logger = winston.createLogger({
datePattern: "YYYY-MM-DD-HH", datePattern: "YYYY-MM-DD-HH",
zippedArchive: true, zippedArchive: true,
maxSize: "20m", maxSize: "20m",
maxFiles: "14d", maxFiles: "14d"
}), }),
new winston.transports.Console({ new winston.transports.Console({
format: winston.format.combine( format: winston.format.combine(winston.format.colorize(), winston.format.simple())
winston.format.colorize(), })
winston.format.simple()
),
}),
], ],
rejectionHandlers: [ rejectionHandlers: [
new DailyRotateFile({ new DailyRotateFile({
@@ -57,14 +47,11 @@ export const logger = winston.createLogger({
datePattern: "YYYY-MM-DD-HH", datePattern: "YYYY-MM-DD-HH",
zippedArchive: true, zippedArchive: true,
maxSize: "20m", maxSize: "20m",
maxFiles: "14d", maxFiles: "14d"
}), }),
new winston.transports.Console({ new winston.transports.Console({
format: winston.format.combine( format: winston.format.combine(winston.format.colorize(), winston.format.simple())
winston.format.colorize(), })
winston.format.simple()
),
}),
], ],
transports: [ transports: [
new DailyRotateFile({ new DailyRotateFile({
@@ -73,7 +60,7 @@ export const logger = winston.createLogger({
zippedArchive: true, zippedArchive: true,
maxSize: "20m", maxSize: "20m",
maxFiles: "14d", maxFiles: "14d",
level: "error", level: "error"
}), }),
new DailyRotateFile({ new DailyRotateFile({
@@ -82,25 +69,22 @@ export const logger = winston.createLogger({
zippedArchive: true, zippedArchive: true,
maxSize: "20m", maxSize: "20m",
maxFiles: "14d", maxFiles: "14d",
level: "debug", level: "debug"
}), }),
new DailyRotateFile({ new DailyRotateFile({
filename: path.join(FolderPaths.Root, "logs", "ALL-%DATE%.log"), filename: path.join(FolderPaths.Root, "logs", "ALL-%DATE%.log"),
datePattern: "YYYY-MM-DD-HH", datePattern: "YYYY-MM-DD-HH",
zippedArchive: true, zippedArchive: true,
maxSize: "20m", maxSize: "20m",
maxFiles: "14d", maxFiles: "14d"
}), })
], ]
}); });
if (process.env.NODE_ENV !== "production") { if (process.env.NODE_ENV !== "production") {
logger.add( logger.add(
new winston.transports.Console({ new winston.transports.Console({
format: winston.format.combine( format: winston.format.combine(winston.format.colorize(), winston.format.simple())
winston.format.colorize(),
winston.format.simple()
),
}) })
); );
} }
@@ -118,27 +102,16 @@ const morganMiddleware = morgan(
"combined", //":method :url :status :res[content-length] - :response-time ms" "combined", //":method :url :status :res[content-length] - :response-time ms"
{ {
stream: { stream: {
write: (message) => logger.http(message.trim()), write: (message) => logger.http(message.trim())
}, }
} }
); );
app.use(morganMiddleware); app.use(morganMiddleware);
app.use(helmet({ crossOriginResourcePolicy: { policy: "cross-origin" } })); app.use(helmet({ crossOriginResourcePolicy: { policy: "cross-origin" } }));
app.post("/jobs/list", ValidateImsToken, JobRequestValidator, JobsListMedia); app.post("/jobs/list", ValidateImsToken, JobRequestValidator, JobsListMedia);
app.post( app.post("/jobs/upload", ValidateImsToken, JobMediaUploadMulter.array("file"), JobRequestValidator, jobsUploadMedia);
"/jobs/upload", app.post("/jobs/download", ValidateImsToken, JobRequestValidator, jobsDownloadMedia);
ValidateImsToken,
JobMediaUploadMulter.array("file"),
JobRequestValidator,
jobsUploadMedia
);
app.post(
"/jobs/download",
ValidateImsToken,
JobRequestValidator,
jobsDownloadMedia
);
app.post( app.post(
"/jobs/move", //JobRequestValidator, "/jobs/move", //JobRequestValidator,
ValidateImsToken, ValidateImsToken,
@@ -159,23 +132,13 @@ app.post(
BillsUploadMedia BillsUploadMedia
); );
app.get( app.get("/", ValidateImsToken, (req: express.Request, res: express.Response) => {
"/", res.send("IMS running.");
ValidateImsToken, });
(req: express.Request, res: express.Response) => {
res.send("IMS running.");
}
);
InitServer(); InitServer();
app.use( app.use(FolderPaths.StaticPath, express.static(FolderPaths.Root, { etag: false, maxAge: 30 * 1000 }));
FolderPaths.StaticPath, app.use("/assets", express.static("./assets", { etag: false, maxAge: 30 * 1000 }));
express.static(FolderPaths.Root, { etag: false, maxAge: 30 * 1000 })
);
app.use(
"/assets",
express.static("./assets", { etag: false, maxAge: 30 * 1000 })
);
app.listen(port, () => { app.listen(port, () => {
logger.info(`ImEX Media Server is running at http://localhost:${port}`); logger.info(`ImEX Media Server is running at http://localhost:${port}`);
}); });

View File

@@ -1,13 +1,13 @@
import fs from "fs-extra";
import { access } from "fs/promises";
import imageThumbnail from "image-thumbnail";
import path from "path";
import gm from "gm";
import ft from "file-type"; import ft from "file-type";
import core from "file-type/core"; import core from "file-type/core";
import fs from "fs-extra";
import { access } from "fs/promises";
import gm from "gm";
import imageThumbnail from "image-thumbnail";
import path from "path";
import { logger } from "../server";
import GenerateUrl from "./MediaUrlGen"; import GenerateUrl from "./MediaUrlGen";
import { AssetPaths, FolderPaths } from "./serverInit"; import { AssetPaths, FolderPaths } from "./serverInit";
import { logger } from "../server";
const simpleThumb = require("simple-thumbnail"); const simpleThumb = require("simple-thumbnail");
//const ffmpeg = require("ffmpeg-static"); //const ffmpeg = require("ffmpeg-static");
@@ -20,7 +20,7 @@ export default async function GenerateThumbnail(
file: string file: string
//thumbPath: string //thumbPath: string
) { ) {
const type: core.FileTypeResult | undefined = await ft.fromFile(file); const type: core.FileTypeResult | undefined = await ft.fileTypeFromFile(file);
let thumbnailExtension: string = GetThumbnailExtension(type); let thumbnailExtension: string = GetThumbnailExtension(type);
let thumbPath: string = path.join( let thumbPath: string = path.join(
path.dirname(file), path.dirname(file),
@@ -54,7 +54,7 @@ export default async function GenerateThumbnail(
responseType: "buffer", responseType: "buffer",
height: 250, height: 250,
width: 250, width: 250,
failOnError: false, failOnError: false
}); });
console.log("Image success."); console.log("Image success.");
await fs.writeFile(thumbPath, thumbnail); await fs.writeFile(thumbPath, thumbnail);
@@ -64,7 +64,7 @@ export default async function GenerateThumbnail(
logger.error("Error when genenerating thumbnail:", { logger.error("Error when genenerating thumbnail:", {
thumbPath, thumbPath,
err, err,
message: (err as Error).message, message: (err as Error).message
}); });
return path.relative(path.dirname(file), AssetPaths.File); return path.relative(path.dirname(file), AssetPaths.File);
} }

View File

@@ -1,16 +1,14 @@
import path from "path"; import path from "path";
export default function (file: Express.Multer.File) { export default function (file: Express.Multer.File) {
return `${path.parse(path.basename(file.originalname)).name}-${Math.floor( return `${path.parse(sanitizeFileName(path.basename(file.originalname))).name}-${Math.floor(Date.now() / 1000)}${path.extname(file.originalname)}`;
Date.now() / 1000
)}${path.extname(file.originalname)}`;
} }
export function generateUniqueBillFilename( export function generateUniqueBillFilename(file: Express.Multer.File, invoice_number: string) {
file: Express.Multer.File, return `${sanitizeFileName(invoice_number)}-${Math.floor(Date.now() / 1000)}${path.extname(file.originalname)}`;
invoice_number: string }
) {
return `${invoice_number}-${Math.floor(Date.now() / 1000)}${path.extname( function sanitizeFileName(fileName: string): string {
file.originalname const restrictedChars = /[<>:"/\\|?*\x00-\x1F]/g;
)}`; return fileName.replace(restrictedChars, "");
} }

View File

@@ -13,36 +13,25 @@ var imageMagick = gm.subClass({ imageMagick: true });
//gm.subClass(); //gm.subClass();
dotenv.config({ dotenv.config({
path: resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`), path: resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
}); });
export async function ConvertHeicFiles(files: Express.Multer.File[]) { export async function ConvertHeicFiles(files: Express.Multer.File[]) {
for (const file of files) { for (const file of files) {
const type: core.FileTypeResult | undefined = await ft.fromFile(file.path); const type: core.FileTypeResult | undefined = await ft.fileTypeFromFile(file.path);
if (type?.mime === "image/heic") { if (type?.mime === "image/heic") {
logger.log( logger.log("debug", `Converting ${file.filename} image to JPEG from HEIC.`);
"debug",
`Converting ${file.filename} image to JPEG from HEIC.`
);
const convertedFileName = `${ const convertedFileName = `${
path.parse(path.basename(file.originalname)).name path.parse(path.basename(file.originalname)).name
}-${Math.floor(Date.now() / 1000)}.jpeg`; }-${Math.floor(Date.now() / 1000)}.jpeg`;
try { try {
await ConvertToJpeg( await ConvertToJpeg(file.path, `${file.destination}/${convertedFileName}`);
file.path,
`${file.destination}/${convertedFileName}`
);
//Move the HEIC. //Move the HEIC.
if (process.env.KEEP_CONVERTED_ORIGINALS) { if (process.env.KEEP_CONVERTED_ORIGINALS) {
await fs.ensureDir( await fs.ensureDir(path.join(file.destination, FolderPaths.ConvertedOriginalSubDir));
path.join(file.destination, FolderPaths.ConvertedOriginalSubDir)
);
await fs.move( await fs.move(
file.path, file.path,
`${path.join( `${path.join(file.destination, FolderPaths.ConvertedOriginalSubDir)}/${file.filename}`
file.destination,
FolderPaths.ConvertedOriginalSubDir
)}/${file.filename}`
); );
} else { } else {
await fs.unlink(file.destination); await fs.unlink(file.destination);
@@ -53,12 +42,7 @@ export async function ConvertHeicFiles(files: Express.Multer.File[]) {
file.mimetype = "image/jpeg"; file.mimetype = "image/jpeg";
file.path = `${file.destination}/${convertedFileName}`; file.path = `${file.destination}/${convertedFileName}`;
} catch (error) { } catch (error) {
logger.log( logger.log("error", `Error converting ${file.filename} image to JPEG from HEIC. ${JSON.stringify(error)}`);
"error",
`Error converting ${
file.filename
} image to JPEG from HEIC. ${JSON.stringify(error)}`
);
} }
} }
} }

View File

@@ -5,7 +5,7 @@ import path, { resolve } from "path";
import { logger } from "../server"; import { logger } from "../server";
dotenv.config({ dotenv.config({
path: resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`), path: resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
}); });
const RootDirectory = process.env.MEDIA_PATH!.replace("~", os.homedir); const RootDirectory = process.env.MEDIA_PATH!.replace("~", os.homedir);
@@ -21,11 +21,11 @@ export const FolderPaths = {
ConvertedOriginalSubDir: "/ConvertedOriginal", ConvertedOriginalSubDir: "/ConvertedOriginal",
StaticPath: "/static", StaticPath: "/static",
JobsFolder, JobsFolder,
VendorsFolder, VendorsFolder
}; };
export const AssetPaths = { export const AssetPaths = {
File: "/assets/file.png", File: "/assets/file.png"
}; };
export function JobRelativeFilePath(jobid: string, filename: string) { export function JobRelativeFilePath(jobid: string, filename: string) {

View File

@@ -4,14 +4,10 @@ import { resolve } from "path";
import { logger } from "../server"; import { logger } from "../server";
dotenv.config({ dotenv.config({
path: resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`), path: resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
}); });
export default function ValidateImsToken( export default function ValidateImsToken(req: Request, res: Response, next: NextFunction) {
req: Request,
res: Response,
next: NextFunction
) {
const jobid: string = (req.body.jobid || "").trim(); const jobid: string = (req.body.jobid || "").trim();
const IMS_TOKEN: string = (process.env.IMS_TOKEN || "").trim(); const IMS_TOKEN: string = (process.env.IMS_TOKEN || "").trim();

1406
yarn.lock

File diff suppressed because it is too large Load Diff