aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSam Wilkins <samwilkins333@gmail.com>2019-09-08 15:24:53 -0400
committerSam Wilkins <samwilkins333@gmail.com>2019-09-08 15:24:53 -0400
commit65e5366f59ef2933460aafdc98790f42611f149f (patch)
treef12b36999908412ade059c16fcae374d76376285 /src
parentf18e2265e5d468f1cbf6e82dd5f01d5f5216b851 (diff)
refactor of uploader to handle local and remote images
Diffstat (limited to 'src')
-rw-r--r--src/client/util/Import & Export/DirectoryImportBox.tsx2
-rw-r--r--src/server/apis/google/GooglePhotosUploadUtils.ts101
-rw-r--r--src/server/credentials/google_docs_token.json2
-rw-r--r--src/server/index.ts68
4 files changed, 89 insertions, 84 deletions
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index 75b0b52a7..35d6e3c60 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx
@@ -313,7 +313,7 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps>
style={{
pointerEvents: "none",
position: "absolute",
- right: isEditing ? 16.3 : 14.5,
+ right: isEditing ? 14 : 15,
top: isEditing ? 15.4 : 16,
opacity: uploading ? 0 : 1,
transition: "0.4s opacity ease"
diff --git a/src/server/apis/google/GooglePhotosUploadUtils.ts b/src/server/apis/google/GooglePhotosUploadUtils.ts
index 5ac3eaef7..d4a2a2bb3 100644
--- a/src/server/apis/google/GooglePhotosUploadUtils.ts
+++ b/src/server/apis/google/GooglePhotosUploadUtils.ts
@@ -93,65 +93,78 @@ export namespace DownloadUtils {
const size = "content-length";
const type = "content-type";
- export interface DownloadInformation {
+ export interface UploadInformation {
mediaPaths: string[];
fileNames: { [key: string]: string };
- contentSize?: string;
+ contentSize?: number;
contentType?: string;
}
const generate = (prefix: string, url: string) => `${prefix}upload_${Utils.GenerateGuid()}${path.extname(url).toLowerCase()}`;
const sanitize = (filename: string) => filename.replace(/\s+/g, "_");
- export const Download = async (url: string, filename?: string, prefix = ""): Promise<Opt<DownloadInformation>> => {
+ export const UploadImage = async (url: string, filename?: string, prefix = ""): Promise<Opt<UploadInformation>> => {
const resolved = filename ? sanitize(filename) : generate(prefix, url);
const extension = path.extname(url) || path.extname(resolved) || png;
- return new Promise<DownloadInformation>((resolve, reject) => {
- request.head(url, async (error, res) => {
- if (error) {
- return reject(error);
- }
- const information: DownloadInformation = {
- fileNames: { clean: resolved },
- contentSize: res.headers[size],
- contentType: res.headers[type],
- mediaPaths: []
- };
- 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 validated = true;
- if (pngs.includes(extension)) {
- resizers.forEach(element => element.resizer = element.resizer.png());
- } else if (jpg.includes(extension)) {
- resizers.forEach(element => element.resizer = element.resizer.jpeg());
- } else {
- validated = false;
- }
- if (validated) {
- 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;
- request(url)
- .pipe(resizer.resizer)
- .pipe(fs.createWriteStream(mediaPath))
- .on('close', resolve);
- });
+ let information: UploadInformation = {
+ mediaPaths: [],
+ fileNames: { clean: resolved }
+ };
+ const { isLocal, stream } = classify(url = path.normalize(url));
+ if (!isLocal) {
+ const metadata = (await new Promise<any>((resolve, reject) => {
+ request.head(url, async (error, res) => {
+ if (error) {
+ return reject(error);
}
- resolve(information);
+ resolve(res);
+ });
+ })).headers;
+ information.contentSize = parseInt(metadata[size]);
+ information.contentType = metadata[type];
+ }
+ 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 validated = true;
+ if (pngs.includes(extension)) {
+ resizers.forEach(element => element.resizer = element.resizer.png());
+ } else if (jpg.includes(extension)) {
+ resizers.forEach(element => element.resizer = element.resizer.jpeg());
+ } else {
+ validated = false;
+ }
+ if (validated) {
+ 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(url).pipe(resizer.resizer).pipe(fs.createWriteStream(mediaPath))
+ .on('close', resolve)
+ .on('error', reject);
+ });
}
- });
+ resolve(information);
+ }
});
};
+ const classify = (url: string) => {
+ const isLocal = /Dash-Web\\src\\server\\public\\files/g.test(url);
+ return {
+ isLocal,
+ stream: isLocal ? fs.createReadStream : request
+ };
+ };
+
export const createIfNotExists = async (path: string) => {
if (await new Promise<boolean>(resolve => fs.exists(path, resolve))) {
return true;
diff --git a/src/server/credentials/google_docs_token.json b/src/server/credentials/google_docs_token.json
index 4f911f7e0..66668aaef 100644
--- a/src/server/credentials/google_docs_token.json
+++ b/src/server/credentials/google_docs_token.json
@@ -1 +1 @@
-{"access_token":"ya29.Glx9B3_l5JbKNtvzx378Nsz917bP-OTKf6VZzc2K8QDBm-Y0j_-c8v7bL8LCEM3wF8d7JauF-5Z4Uq4v7wPwUQUlDO1uPyoHeSF6iz98xkgJr9OW4KzJo2Ij722gpQ","refresh_token":"1/HTv_xFHszu2Nf3iiFrUTaeKzC_Vp2-6bpIB06xW_WHI","scope":"https://www.googleapis.com/auth/presentations.readonly https://www.googleapis.com/auth/documents.readonly https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/documents https://www.googleapis.com/auth/photoslibrary https://www.googleapis.com/auth/photoslibrary.appendonly https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/presentations https://www.googleapis.com/auth/photoslibrary.sharing","token_type":"Bearer","expiry_date":1567931641928} \ No newline at end of file
+{"access_token":"ya29.Glx9BwKT8sxbXNR78f2Ks3pAe2DfsxOhrYMj8SACNi13xwJ0MtLU4WYb4_cbHAj2X8imZW9eUBlAsY9RXoMEPOmVpMlhMjxVZKBo_0lwJ6xSTunSdrR1e8P7vkRV4Q","refresh_token":"1/HTv_xFHszu2Nf3iiFrUTaeKzC_Vp2-6bpIB06xW_WHI","scope":"https://www.googleapis.com/auth/presentations.readonly https://www.googleapis.com/auth/documents.readonly https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/documents https://www.googleapis.com/auth/photoslibrary https://www.googleapis.com/auth/photoslibrary.appendonly https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/presentations https://www.googleapis.com/auth/photoslibrary.sharing","token_type":"Bearer","expiry_date":1567962258021} \ No newline at end of file
diff --git a/src/server/index.ts b/src/server/index.ts
index 013345a76..54525cd31 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -42,7 +42,7 @@ var AdmZip = require('adm-zip');
import * as YoutubeApi from "./apis/youtube/youtubeApiSample";
import { Response } from 'express-serve-static-core';
import { GoogleApiServerUtils } from "./apis/google/GoogleApiServerUtils";
-import { GooglePhotosUploadUtils, DownloadUtils } from './apis/google/GooglePhotosUploadUtils';
+import { GooglePhotosUploadUtils, DownloadUtils as UploadUtils } from './apis/google/GooglePhotosUploadUtils';
const MongoStore = require('connect-mongo')(session);
const mongoose = require('mongoose');
const probe = require("probe-image-size");
@@ -156,7 +156,8 @@ app.get("/buxton", (req, res) => {
const STATUS = {
OK: 200,
- BAD_REQUEST: 400
+ BAD_REQUEST: 400,
+ EXECUTION_ERROR: 500
};
const command_line = (command: string, fromDirectory?: string) => {
@@ -558,7 +559,6 @@ class NodeCanvasFactory {
}
const pngTypes = [".png", ".PNG"];
-const pdfTypes = [".pdf", ".PDF"];
const jpgTypes = [".jpg", ".JPG", ".jpeg", ".JPEG"];
const uploadDirectory = __dirname + "/public/files/";
// SETTERS
@@ -568,37 +568,11 @@ app.post(
let form = new formidable.IncomingForm();
form.uploadDir = uploadDirectory;
form.keepExtensions = true;
- // let path = req.body.path;
- console.log("upload");
- form.parse(req, (err, fields, files) => {
- console.log("parsing");
+ form.parse(req, async (_err, _fields, files) => {
let names: string[] = [];
for (const name in files) {
const file = path.basename(files[name].path);
- const ext = path.extname(file);
- let resizers = [
- { resizer: sharp().rotate(), suffix: "_o" },
- { resizer: sharp().resize(100, undefined, { withoutEnlargement: true }).rotate(), suffix: "_s" },
- { resizer: sharp().resize(400, undefined, { withoutEnlargement: true }).rotate(), suffix: "_m" },
- { resizer: sharp().resize(900, undefined, { withoutEnlargement: true }).rotate(), suffix: "_l" },
- ];
- let isImage = false;
- if (pngTypes.includes(ext)) {
- resizers.forEach(element => {
- element.resizer = element.resizer.png();
- });
- isImage = true;
- } else if (jpgTypes.includes(ext)) {
- resizers.forEach(element => {
- element.resizer = element.resizer.jpeg();
- });
- isImage = true;
- }
- if (isImage) {
- resizers.forEach(resizer => {
- fs.createReadStream(uploadDirectory + file).pipe(resizer.resizer).pipe(fs.createWriteStream(uploadDirectory + file.substring(0, file.length - ext.length) + resizer.suffix + ext));
- });
- }
+ await UploadUtils.UploadImage(uploadDirectory + file, file);
names.push(`/files/` + file);
}
res.send(names);
@@ -845,11 +819,11 @@ app.post(RouteStore.googlePhotosMediaUpload, async (req, res) => {
};
}));
if (!newMediaItems.every(item => item)) {
- return res.send(tokenError);
+ return res.status(STATUS.EXECUTION_ERROR).send(tokenError);
}
GooglePhotosUploadUtils.CreateMediaItems(newMediaItems, req.body.album).then(
- success => res.send(success),
- () => res.send(mediaError)
+ success => res.status(STATUS.OK).send(success),
+ () => res.status(STATUS.EXECUTION_ERROR).send(mediaError)
);
});
@@ -859,18 +833,36 @@ interface MediaItem {
}
const prefix = "google_photos_";
+const downloadError = "Encountered an error while executing downloads.";
+const requestError = "Unable to execute download: the body's media items were malformed.";
+
app.post(RouteStore.googlePhotosMediaDownload, async (req, res) => {
const contents: { mediaItems: MediaItem[] } = req.body;
if (contents) {
- const downloads = contents.mediaItems.map(item =>
- DownloadUtils.Download(item.baseUrl, item.filename, prefix)
+ const pending = contents.mediaItems.map(item =>
+ UploadUtils.UploadImage(item.baseUrl, item.filename, prefix)
);
- res.status(STATUS.OK).send(await Promise.all(downloads));
+ const completed = await Promise.all(pending).catch(error => _error(res, downloadError, error));
+ _success(res, completed);
return;
}
- res.status(STATUS.BAD_REQUEST).send();
+ _invalid(res, requestError);
});
+const _error = (res: Response, message: string, error: any) => {
+ res.statusMessage = message;
+ res.status(STATUS.EXECUTION_ERROR).send(error);
+};
+
+const _success = (res: Response, body: any) => {
+ res.status(STATUS.OK).send(body);
+};
+
+const _invalid = (res: Response, message: string) => {
+ res.statusMessage = message;
+ res.status(STATUS.BAD_REQUEST).send();
+};
+
const suffixMap: { [type: string]: (string | [string, string | ((json: any) => any)]) } = {
"number": "_n",
"string": "_t",