Update media file interface and how bills are returned.

This commit is contained in:
Patrick Fic
2022-05-05 15:45:42 -07:00
parent 7754dc4653
commit 270be1d360
10 changed files with 101 additions and 1987 deletions

View File

@@ -5,7 +5,7 @@ export default function BillRequestValidator(
res: Response, res: Response,
next: NextFunction next: NextFunction
) { ) {
const vendor: string = (req.body.vendor || "").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

@@ -10,43 +10,80 @@ import { FolderPaths } from "../util/serverInit";
/** @description Bills will use the hierarchy of PDFs stored under the Job first, and then the Bills folder. */ /** @description Bills will use the hierarchy of PDFs stored under the Job first, and then the Bills folder. */
export async function BillsListMedia(req: Request, res: Response) { export async function BillsListMedia(req: Request, res: Response) {
const jobid: string = (req.body.jobid || "").trim(); const jobid: string = (req.body.jobid || "").trim();
const vendor: string = (req.body.vendor || "").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();
let ret: MediaFile[];
//Ensure all directories exist. //Ensure all directories exist.
await fs.ensureDir(PathToRoBillsFolder(jobid)); await fs.ensureDir(PathToRoBillsFolder(jobid));
const filesList: fs.Dirent[] = ( if (req.files) {
await fs.readdir(PathToRoBillsFolder(jobid), { ret = await Promise.all(
withFileTypes: true, (req.files as Express.Multer.File[]).map(async (file) => {
}) const relativeThumbPath: string = await GenerateThumbnail(
).filter((f) => f.isFile() && !/(^|\/)\.[^\/\.]/g.test(f.name)); path.join(PathToRoBillsFolder(jobid), file.filename)
);
return {
src: GenerateUrl([
FolderPaths.StaticPath,
FolderPaths.JobsFolder,
jobid,
FolderPaths.BillsSubDir,
file.filename,
]),
thumbnail: GenerateUrl([
FolderPaths.StaticPath,
FolderPaths.JobsFolder,
jobid,
FolderPaths.BillsSubDir,
relativeThumbPath,
]),
thumbnailHeight: 250,
thumbnailWidth: 250,
filename: file.filename,
};
})
);
} else {
let filesList: fs.Dirent[] = (
await fs.readdir(PathToRoBillsFolder(jobid), {
withFileTypes: true,
})
).filter(
(f) =>
f.isFile() &&
!/(^|\/)\.[^\/\.]/g.test(f.name) &&
(invoice_number !== ""
? f.name.toLowerCase().includes(invoice_number.toLowerCase())
: true)
);
const ret: MediaFile[] = await Promise.all( ret = await Promise.all(
filesList.map(async (file) => { filesList.map(async (file) => {
const relativeThumbPath: string = await GenerateThumbnail( const relativeThumbPath: string = await GenerateThumbnail(
path.join(PathToRoBillsFolder(jobid), file.name) path.join(PathToRoBillsFolder(jobid), file.name)
); );
return { return {
src: GenerateUrl([ src: GenerateUrl([
FolderPaths.StaticPath, FolderPaths.StaticPath,
FolderPaths.JobsFolder, FolderPaths.JobsFolder,
jobid, jobid,
FolderPaths.BillsSubDir, FolderPaths.BillsSubDir,
file.name, 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,
}) };
); })
);
}
res.json(ret); res.json(ret);
} }

View File

@@ -56,13 +56,13 @@ export async function BillsUploadMedia(req: Request, res: Response) {
//for each file.path, generate the thumbnail. //for each file.path, generate the thumbnail.
(req.files as Express.Multer.File[]).forEach((file) => { (req.files as Express.Multer.File[]).forEach((file) => {
const vendor: string = (req.body.vendor || "").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();
copyQueue.push( copyQueue.push(
(async () => { (async () => {
const target: string = path.join( const target: string = path.join(
PathToVendorBillsFile(vendor), PathToVendorBillsFile(vendorid),
file.filename file.filename
); );
await fs.ensureDir(path.dirname(target)); await fs.ensureDir(path.dirname(target));
@@ -72,9 +72,8 @@ export async function BillsUploadMedia(req: Request, res: Response) {
//Copy Queue is not awaited - we don't care if it finishes before we serve up the thumbnails from the jobs directory. //Copy Queue is not awaited - we don't care if it finishes before we serve up the thumbnails from the jobs directory.
}); });
} }
res.sendStatus(200);
// BillsListMedia(req, res); BillsListMedia(req, res);
} }
} catch (err) { } catch (err) {
res.status(500).send(err); res.status(500).send(err);

View File

@@ -33,6 +33,7 @@ export async function JobsListMedia(req: Request, res: Response) {
]), ]),
thumbnailHeight: 250, thumbnailHeight: 250,
thumbnailWidth: 250, thumbnailWidth: 250,
filename: file.filename,
}; };
}) })
); );
@@ -63,6 +64,7 @@ export async function JobsListMedia(req: Request, res: Response) {
]), ]),
thumbnailHeight: 250, thumbnailHeight: 250,
thumbnailWidth: 250, thumbnailWidth: 250,
filename: file.name,
}; };
}) })
); );

View File

@@ -10,13 +10,13 @@ import { PathToRoFolder } from "../util/pathGenerators";
export async function JobsMoveMedia(req: Request, res: Response) { export async function JobsMoveMedia(req: Request, res: Response) {
const jobid: string = (req.body.jobid || "").trim(); const jobid: string = (req.body.jobid || "").trim();
const from_ro: string = (req.body.from_ro || "").trim(); const from_jobid: string = (req.body.from_jobid || "").trim();
const files: string[] = req.body.files; //Just file names. const files: string[] = req.body.files; //Just file names.
//Validate the request is valid and contains everything that it needs. //Validate the request is valid and contains everything that it needs.
if (from_ro === "") { if (from_jobid === "") {
res.status(400).json({ error: "from_ro must be specified. " }); res.status(400).json({ error: "from_jobid must be specified. " });
return; return;
} }
if (files.length === 0) { if (files.length === 0) {
@@ -31,14 +31,14 @@ export async function JobsMoveMedia(req: Request, res: Response) {
files.forEach((file) => { files.forEach((file) => {
movingQueue.push( movingQueue.push(
fs.move( fs.move(
path.join(FolderPaths.Jobs, from_ro, file), path.join(FolderPaths.Jobs, from_jobid, file),
path.join(FolderPaths.Jobs, jobid, file) path.join(FolderPaths.Jobs, jobid, file)
) )
); );
movingQueue.push( movingQueue.push(
fs.move( fs.move(
path.join(FolderPaths.Jobs, from_ro, FolderPaths.ThumbsSubDir, file), path.join(FolderPaths.Jobs, from_jobid, FolderPaths.ThumbsSubDir, file),
path.join(FolderPaths.Jobs, jobid, FolderPaths.ThumbsSubDir, file) path.join(FolderPaths.Jobs, jobid, FolderPaths.ThumbsSubDir, file)
) )
); );

View File

@@ -10,5 +10,6 @@ environment: - MEDIA_PATH=/media
## Bills ## Bills
By default, it will query from the job files. Anything duplicated to the vendor files is purely for reference. By default, it will query from the job files. Anything duplicated to the vendor files is purely for reference.
If an invoice number is included, it will be default fetch that file only.
## Jobs ## Jobs

View File

@@ -23,7 +23,11 @@ dotenv.config({
}); });
export const logger = winston.createLogger({ export const logger = winston.createLogger({
format: winston.format.prettyPrint(), format: winston.format.combine(
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: [
@@ -34,6 +38,12 @@ export const logger = winston.createLogger({
maxSize: "20m", maxSize: "20m",
maxFiles: "14d", maxFiles: "14d",
}), }),
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
),
}),
], ],
rejectionHandlers: [ rejectionHandlers: [
new DailyRotateFile({ new DailyRotateFile({
@@ -43,6 +53,12 @@ export const logger = winston.createLogger({
maxSize: "20m", maxSize: "20m",
maxFiles: "14d", maxFiles: "14d",
}), }),
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
),
}),
], ],
transports: [ transports: [
new DailyRotateFile({ new DailyRotateFile({

View File

@@ -5,6 +5,7 @@ interface MediaFile {
thumbnail: string; thumbnail: string;
thumbnailHeight: number; thumbnailHeight: number;
thumbnailWidth: number; thumbnailWidth: number;
filename: string;
} }
export default MediaFile; export default MediaFile;

View File

@@ -8,6 +8,6 @@ export function PathToRoFolder(jobid: string) {
export function PathToRoBillsFolder(jobid: string) { export function PathToRoBillsFolder(jobid: string) {
return path.join(FolderPaths.Jobs, jobid, FolderPaths.BillsSubDir); return path.join(FolderPaths.Jobs, jobid, FolderPaths.BillsSubDir);
} }
export function PathToVendorBillsFile(vendor: string) { export function PathToVendorBillsFile(vendorid: string) {
return path.join(FolderPaths.Vendors, vendor); return path.join(FolderPaths.Vendors, vendorid);
} }

File diff suppressed because it is too large Load Diff