aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--src/server/ApiManagers/UploadManager.ts44
-rw-r--r--src/server/DashUploadUtils.ts342
-rw-r--r--src/server/public/files/.gitignore2
4 files changed, 195 insertions, 194 deletions
diff --git a/.gitignore b/.gitignore
index 5161268ac..e5048cfc4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ dist/
.env
ClientUtils.ts
solr-8.1.1/server/
+src/server/public/files/ \ No newline at end of file
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index aca63a918..2a9faacd8 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -3,7 +3,7 @@ import { Method, _success } from "../RouteManager";
import * as formidable from 'formidable';
import v4 = require('uuid/v4');
var AdmZip = require('adm-zip');
-import * as path from 'path';
+import { extname, basename, dirname } from 'path';
import { createReadStream, createWriteStream, unlink, readFileSync } from "fs";
import { publicDirectory, filesDirectory } from "..";
import { Database } from "../database";
@@ -81,17 +81,17 @@ export default class UploadManager extends ApiManager {
const zip = new AdmZip(path_2);
zip.getEntries().forEach((entry: any) => {
if (!entry.entryName.startsWith("files/")) return;
- let dirname = path.dirname(entry.entryName) + "/";
- let extname = path.extname(entry.entryName);
- let basename = path.basename(entry.entryName).split(".")[0];
+ let directory = dirname(entry.entryName) + "/";
+ let extension = extname(entry.entryName);
+ let base = basename(entry.entryName).split(".")[0];
try {
zip.extractEntryTo(entry.entryName, publicDirectory, true, false);
- dirname = "/" + dirname;
+ directory = "/" + directory;
- createReadStream(publicDirectory + dirname + basename + extname).pipe(createWriteStream(publicDirectory + dirname + basename + "_o" + extname));
- createReadStream(publicDirectory + dirname + basename + extname).pipe(createWriteStream(publicDirectory + dirname + basename + "_s" + extname));
- createReadStream(publicDirectory + dirname + basename + extname).pipe(createWriteStream(publicDirectory + dirname + basename + "_m" + extname));
- createReadStream(publicDirectory + dirname + basename + extname).pipe(createWriteStream(publicDirectory + dirname + basename + "_l" + extname));
+ createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_o" + extension));
+ createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_s" + extension));
+ createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_m" + extension));
+ createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_l" + extension));
} catch (e) {
console.log(e);
}
@@ -133,29 +133,9 @@ export default class UploadManager extends ApiManager {
form.keepExtensions = true;
return new Promise<void>(resolve => {
form.parse(req, async (_err, _fields, files) => {
- let results: DashUploadUtils.ImageFileResponse[] = [];
+ let results: any[] = [];
for (const key in files) {
- const { type, path: location, name } = files[key];
- const filename = path.basename(location);
- let uploadInformation: Opt<DashUploadUtils.UploadInformation>;
- if (filename.endsWith(".pdf")) {
- let dataBuffer = readFileSync(filesDirectory + filename);
- const result: ParsedPDF = await pdf(dataBuffer);
- await new Promise<void>((resolve, reject) => {
- const path = filesDirectory + DashUploadUtils.Partitions.pdf_text + "/" + filename.substring(0, filename.length - ".pdf".length) + ".txt";
- createWriteStream(path).write(result.text, error => {
- if (!error) {
- resolve();
- } else {
- reject(error);
- }
- });
- });
- } else {
- uploadInformation = await DashUploadUtils.UploadImage(filesDirectory + filename, filename);
- }
- const exif = uploadInformation ? uploadInformation.exifData : undefined;
- results.push({ name, type, path: `/files/${filename}`, exif });
+ results.push(DashUploadUtils.upload(files[key]));
}
_success(res, results);
resolve();
@@ -188,7 +168,7 @@ export default class UploadManager extends ApiManager {
return;
}
return imageDataUri.outputFile(uri, filesDirectory + filename).then((savedName: string) => {
- const ext = path.extname(savedName).toLowerCase();
+ const ext = extname(savedName).toLowerCase();
const { pngs, jpgs } = SharedMediaTypes;
let resizers = [
{ resizer: sharp().resize(100, undefined, { withoutEnlargement: true }), suffix: "_s" },
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 8a429b81b..839aada4b 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -7,6 +7,8 @@ import { ExifData, ExifImage } from 'exif';
import { Opt } from '../new_fields/Doc';
import { SharedMediaTypes } from './SharedMediaTypes';
import { filesDirectory } from '.';
+import { File } from 'formidable';
+import { extname, basename } from "path";
const uploadDirectory = path.join(__dirname, './public/files/');
@@ -45,175 +47,195 @@ export namespace DashUploadUtils {
contentType?: string;
}
- const generate = (prefix: string, url: string) => `${prefix}upload_${Utils.GenerateGuid()}${sanitizeExtension(url)}`;
- const sanitize = (filename: string) => filename.replace(/\s+/g, "_");
- const sanitizeExtension = (source: string) => {
- let extension = path.extname(source);
- extension = extension.toLowerCase();
- extension = extension.split("?")[0];
- return extension;
- };
-
- /**
- * Uploads an image specified by the @param source to Dash's /public/files/
- * directory, and returns information generated during that upload
- *
- * @param {string} source is either the absolute path of an already uploaded image or
- * the url of a remote image
- * @param {string} filename dictates what to call the image. If not specified,
- * the name {@param prefix}_upload_{GUID}
- * @param {string} prefix is a string prepended to the generated image name in the
- * event that @param filename is not specified
- *
- * @returns {UploadInformation} This method returns
- * 1) the paths to the uploaded images (plural due to resizing)
- * 2) the file name of each of the resized images
- * 3) the size of the image, in bytes (4432130)
- * 4) the content type of the image, i.e. image/(jpeg | png | ...)
- */
- export const UploadImage = async (source: string, filename?: string, prefix: string = ""): Promise<UploadInformation> => {
- const metadata = await InspectImage(source);
- return UploadInspectedImage(metadata, filename, prefix);
- };
-
- export interface InspectionResults {
- isLocal: boolean;
- stream: any;
- normalizedUrl: string;
- exifData: EnrichedExifData;
- contentSize?: number;
- contentType?: string;
- }
-
- export interface EnrichedExifData {
- data: ExifData;
- error?: string;
- }
-
- export enum Partitions {
- pdf_text,
- images,
- videos
- }
-
- export async function buildFilePartitions() {
- const pending = Object.keys(Partitions).map(sub => createIfNotExists(filesDirectory + sub));
- return Promise.all(pending);
- }
-
- /**
- * Based on the url's classification as local or remote, gleans
- * as much information as possible about the specified image
- *
- * @param source is the path or url to the image in question
- */
- export const InspectImage = async (source: string): Promise<InspectionResults> => {
- const { isLocal, stream, normalized: normalizedUrl } = classify(source);
- const exifData = await parseExifData(source);
- const results = {
- exifData,
- isLocal,
- stream,
- normalizedUrl
- };
- // stop here if local, since request.head() can't handle local paths, only urls on the web
- if (isLocal) {
- return results;
+ export function upload(file: File): any {
+ const { type, path, name } = file;
+ const filename = basename(path);
+ const extension = extname(path).toLowerCase();
+ if (extension === ".pdf") {
+
+ } else if {
+ let partition: Opt<string>;
+ if(imageFormats.includes(extension)) {
+ partition = DashUploadUtils.Partitions.images;
+ } else if (videoFormats.includes(extension)) {
+ partition = DashUploadUtils.Partitions.videos;
}
- const metadata = (await new Promise<any>((resolve, reject) => {
- request.head(source, async (error, res) => {
- if (error) {
- return reject(error);
- }
- resolve(res);
- });
- })).headers;
- return {
- contentSize: parseInt(metadata[size]),
- contentType: metadata[type],
- ...results
- };
+ let uploadInformation: Opt<DashUploadUtils.UploadInformation>;
+ if (partition) {
+ uploadInformation = await DashUploadUtils.UploadImage(`${filesDirectory}/${partition}/${filename}`, filename);
+ } else {
+ console.log(`Unable to accommodate, and ignored, the following file upload: ${filename}`);
+ }
+ }
+ const exif = uploadInformation ? uploadInformation.exifData : undefined;
+ results.push({ name, type, path: `/files/${filename}`, exif });
+
+}
+
+const generate = (prefix: string, url: string) => `${prefix}upload_${Utils.GenerateGuid()}${sanitizeExtension(url)}`;
+const sanitize = (filename: string) => filename.replace(/\s+/g, "_");
+const sanitizeExtension = (source: string) => {
+ let extension = path.extname(source);
+ extension = extension.toLowerCase();
+ extension = extension.split("?")[0];
+ return extension;
+};
+
+/**
+ * Uploads an image specified by the @param source to Dash's /public/files/
+ * directory, and returns information generated during that upload
+ *
+ * @param {string} source is either the absolute path of an already uploaded image or
+ * the url of a remote image
+ * @param {string} filename dictates what to call the image. If not specified,
+ * the name {@param prefix}_upload_{GUID}
+ * @param {string} prefix is a string prepended to the generated image name in the
+ * event that @param filename is not specified
+ *
+ * @returns {UploadInformation} This method returns
+ * 1) the paths to the uploaded images (plural due to resizing)
+ * 2) the file name of each of the resized images
+ * 3) the size of the image, in bytes (4432130)
+ * 4) the content type of the image, i.e. image/(jpeg | png | ...)
+ */
+export const UploadImage = async (source: string, filename?: string, prefix: string = ""): Promise<UploadInformation> => {
+ const metadata = await InspectImage(source);
+ return UploadInspectedImage(metadata, filename, prefix);
+};
+
+export interface InspectionResults {
+ isLocal: boolean;
+ stream: any;
+ normalizedUrl: string;
+ exifData: EnrichedExifData;
+ contentSize?: number;
+ contentType?: string;
+}
+
+export interface EnrichedExifData {
+ data: ExifData;
+ error?: string;
+}
+
+export enum Partitions {
+ pdf_text = "pdf_text",
+ images = "images",
+ videos = "videos"
+}
+
+export async function buildFilePartitions() {
+ const pending = Object.keys(Partitions).map(sub => createIfNotExists(filesDirectory + sub));
+ return Promise.all(pending);
+}
+
+/**
+ * Based on the url's classification as local or remote, gleans
+ * as much information as possible about the specified image
+ *
+ * @param source is the path or url to the image in question
+ */
+export const InspectImage = async (source: string): Promise<InspectionResults> => {
+ const { isLocal, stream, normalized: normalizedUrl } = classify(source);
+ const exifData = await parseExifData(source);
+ const results = {
+ exifData,
+ isLocal,
+ stream,
+ normalizedUrl
};
-
- export const UploadInspectedImage = async (metadata: InspectionResults, filename?: string, prefix = ""): Promise<UploadInformation> => {
- const { isLocal, stream, normalizedUrl, contentSize, contentType, exifData } = metadata;
- const resolved = filename ? sanitize(filename) : generate(prefix, normalizedUrl);
- const extension = sanitizeExtension(normalizedUrl || resolved);
- let information: UploadInformation = {
- mediaPaths: [],
- fileNames: { clean: resolved },
- exifData,
- contentSize,
- contentType,
- };
- const { pngs, imageFormats, jpgs, videoFormats } = SharedMediaTypes;
- return new Promise<UploadInformation>(async (resolve, reject) => {
- const resizers = [
- { resizer: sharp().rotate(), suffix: "_o" },
- ...Object.values(Sizes).map(size => ({
- resizer: sharp().resize(size.width, undefined, { withoutEnlargement: true }).rotate(),
- suffix: size.suffix
- }))
- ];
- let nonVisual = false;
- if (pngs.includes(extension)) {
- resizers.forEach(element => element.resizer = element.resizer.png());
- } else if (jpgs.includes(extension)) {
- resizers.forEach(element => element.resizer = element.resizer.jpeg());
- } else if (![...imageFormats, ...videoFormats].includes(extension.toLowerCase())) {
- nonVisual = true;
- }
- if (imageFormats.includes(extension)) {
- for (let resizer of resizers) {
- const suffix = resizer.suffix;
- let mediaPath: string;
- await new Promise<void>(resolve => {
- const filename = resolved.substring(0, resolved.length - extension.length) + suffix + extension;
- information.mediaPaths.push(mediaPath = uploadDirectory + filename);
- information.fileNames[suffix] = filename;
- stream(normalizedUrl).pipe(resizer.resizer).pipe(fs.createWriteStream(mediaPath))
- .on('close', resolve)
- .on('error', reject);
- });
- }
- }
- if (!isLocal || nonVisual) {
- await new Promise<void>(resolve => {
- stream(normalizedUrl).pipe(fs.createWriteStream(uploadDirectory + resolved)).on('close', resolve);
- });
+ // stop here if local, since request.head() can't handle local paths, only urls on the web
+ if (isLocal) {
+ return results;
+ }
+ const metadata = (await new Promise<any>((resolve, reject) => {
+ request.head(source, async (error, res) => {
+ if (error) {
+ return reject(error);
}
- resolve(information);
+ resolve(res);
});
+ })).headers;
+ return {
+ contentSize: parseInt(metadata[size]),
+ contentType: metadata[type],
+ ...results
};
-
- const classify = (url: string) => {
- const isLocal = /Dash-Web(\\|\/)src(\\|\/)server(\\|\/)public(\\|\/)files/g.test(url);
- return {
- isLocal,
- stream: isLocal ? fs.createReadStream : request,
- normalized: isLocal ? path.normalize(url) : url
- };
+};
+
+export const UploadInspectedImage = async (metadata: InspectionResults, filename?: string, prefix = ""): Promise<UploadInformation> => {
+ const { isLocal, stream, normalizedUrl, contentSize, contentType, exifData } = metadata;
+ const resolved = filename ? sanitize(filename) : generate(prefix, normalizedUrl);
+ const extension = sanitizeExtension(normalizedUrl || resolved);
+ let information: UploadInformation = {
+ mediaPaths: [],
+ fileNames: { clean: resolved },
+ exifData,
+ contentSize,
+ contentType,
};
-
- const parseExifData = async (source: string): Promise<EnrichedExifData> => {
- return new Promise<EnrichedExifData>(resolve => {
- new ExifImage(source, (error, data) => {
- let reason: Opt<string> = undefined;
- if (error) {
- reason = (error as any).code;
- }
- resolve({ data, error: reason });
+ const { pngs, jpgs } = SharedMediaTypes;
+ return new Promise<UploadInformation>(async (resolve, reject) => {
+ const resizers = [
+ { resizer: sharp().rotate(), suffix: "_o" },
+ ...Object.values(Sizes).map(size => ({
+ resizer: sharp().resize(size.width, undefined, { withoutEnlargement: true }).rotate(),
+ suffix: size.suffix
+ }))
+ ];
+ if (pngs.includes(extension)) {
+ resizers.forEach(element => element.resizer = element.resizer.png());
+ } else if (jpgs.includes(extension)) {
+ resizers.forEach(element => element.resizer = element.resizer.jpeg());
+ }
+ for (let resizer of resizers) {
+ const suffix = resizer.suffix;
+ let mediaPath: string;
+ await new Promise<void>(resolve => {
+ const filename = resolved.substring(0, resolved.length - extension.length) + suffix + extension;
+ information.mediaPaths.push(mediaPath = uploadDirectory + filename);
+ information.fileNames[suffix] = filename;
+ stream(normalizedUrl).pipe(resizer.resizer).pipe(fs.createWriteStream(mediaPath))
+ .on('close', resolve)
+ .on('error', reject);
+ });
+ }
+ if (!isLocal) {
+ await new Promise<void>(resolve => {
+ stream(normalizedUrl).pipe(fs.createWriteStream(uploadDirectory + resolved)).on('close', resolve);
});
- });
- };
-
- export const createIfNotExists = async (path: string) => {
- if (await new Promise<boolean>(resolve => fs.exists(path, resolve))) {
- return true;
}
- return new Promise<boolean>(resolve => fs.mkdir(path, error => resolve(error === null)));
+ resolve(information);
+ });
+};
+
+const classify = (url: string) => {
+ const isLocal = /Dash-Web(\\|\/)src(\\|\/)server(\\|\/)public(\\|\/)files/g.test(url);
+ return {
+ isLocal,
+ stream: isLocal ? fs.createReadStream : request,
+ normalized: isLocal ? path.normalize(url) : url
};
+};
+
+const parseExifData = async (source: string): Promise<EnrichedExifData> => {
+ return new Promise<EnrichedExifData>(resolve => {
+ new ExifImage(source, (error, data) => {
+ let reason: Opt<string> = undefined;
+ if (error) {
+ reason = (error as any).code;
+ }
+ resolve({ data, error: reason });
+ });
+ });
+};
+
+export const createIfNotExists = async (path: string) => {
+ if (await new Promise<boolean>(resolve => fs.exists(path, resolve))) {
+ return true;
+ }
+ return new Promise<boolean>(resolve => fs.mkdir(path, error => resolve(error === null)));
+};
- export const Destroy = (mediaPath: string) => new Promise<boolean>(resolve => fs.unlink(mediaPath, error => resolve(error === null)));
+export const Destroy = (mediaPath: string) => new Promise<boolean>(resolve => fs.unlink(mediaPath, error => resolve(error === null)));
} \ No newline at end of file
diff --git a/src/server/public/files/.gitignore b/src/server/public/files/.gitignore
deleted file mode 100644
index c96a04f00..000000000
--- a/src/server/public/files/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore \ No newline at end of file