aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/DashUploadUtils.ts2
-rw-r--r--src/server/RouteStore.ts3
-rw-r--r--src/server/apis/google/GoogleApiServerUtils.ts79
-rw-r--r--src/server/apis/google/GooglePhotosUploadUtils.ts4
-rw-r--r--src/server/authentication/models/current_user_utils.ts22
-rw-r--r--src/server/index.ts31
6 files changed, 89 insertions, 52 deletions
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 619cba3c6..46d897339 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -24,7 +24,7 @@ export namespace DashUploadUtils {
const gifs = [".gif"];
const pngs = [".png"];
const jpgs = [".jpg", ".jpeg"];
- const imageFormats = [...pngs, ...jpgs, ...gifs];
+ export const imageFormats = [...pngs, ...jpgs, ...gifs];
const videoFormats = [".mov", ".mp4"];
const size = "content-length";
diff --git a/src/server/RouteStore.ts b/src/server/RouteStore.ts
index 8a9a6baae..b2a1af8d3 100644
--- a/src/server/RouteStore.ts
+++ b/src/server/RouteStore.ts
@@ -34,7 +34,8 @@ export enum RouteStore {
// APIS
cognitiveServices = "/cognitiveservices",
googleDocs = "/googleDocs",
- googlePhotosAccessToken = "/googlePhotosAccessToken",
+ readGooglePhotosAccessToken = "/readGooglePhotosAccessToken",
+ writeGooglePhotosAccessToken = "/writeGooglePhotosAccessToken",
googlePhotosMediaUpload = "/googlePhotosMediaUpload",
googlePhotosMediaDownload = "/googlePhotosMediaDownload",
googleDocsGet = "/googleDocsGet"
diff --git a/src/server/apis/google/GoogleApiServerUtils.ts b/src/server/apis/google/GoogleApiServerUtils.ts
index c899c2ef2..963c7736a 100644
--- a/src/server/apis/google/GoogleApiServerUtils.ts
+++ b/src/server/apis/google/GoogleApiServerUtils.ts
@@ -75,6 +75,42 @@ export namespace GoogleApiServerUtils {
});
};
+ const RetrieveOAuthClient = async (information: CredentialInformation) => {
+ return new Promise<OAuth2Client>((resolve, reject) => {
+ readFile(information.credentialsPath, async (err, credentials) => {
+ if (err) {
+ reject(err);
+ return console.log('Error loading client secret file:', err);
+ }
+ const { client_secret, client_id, redirect_uris } = parseBuffer(credentials).installed;
+ resolve(new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]));
+ });
+ });
+ };
+
+ export const GenerateAuthenticationUrl = async (information: CredentialInformation) => {
+ const client = await RetrieveOAuthClient(information);
+ return client.generateAuthUrl({
+ access_type: 'offline',
+ scope: SCOPES.map(relative => prefix + relative),
+ });
+ };
+
+ export const ProcessClientSideCode = async (information: CredentialInformation, authenticationCode: string): Promise<TokenResult> => {
+ const oAuth2Client = await RetrieveOAuthClient(information);
+ return new Promise<TokenResult>((resolve, reject) => {
+ oAuth2Client.getToken(authenticationCode, async (err, token) => {
+ if (err || !token) {
+ reject(err);
+ return console.error('Error retrieving access token', err);
+ }
+ oAuth2Client.setCredentials(token);
+ await Database.Auxiliary.GoogleAuthenticationToken.Write(information.userId, token);
+ resolve({ token, client: oAuth2Client });
+ });
+ });
+ };
+
export const RetrieveCredentials = (information: CredentialInformation) => {
return new Promise<TokenResult>((resolve, reject) => {
readFile(information.credentialsPath, async (err, credentials) => {
@@ -107,17 +143,13 @@ export namespace GoogleApiServerUtils {
return new Promise<TokenResult>((resolve, reject) => {
// Attempting to authorize user (${userId})
Database.Auxiliary.GoogleAuthenticationToken.Fetch(userId).then(token => {
- if (!token) {
- // No token registered, so awaiting input from user
- return getNewToken(oAuth2Client, userId).then(resolve, reject);
- }
- if (token.expiry_date! < new Date().getTime()) {
+ if (token!.expiry_date! < new Date().getTime()) {
// Token has expired, so submitting a request for a refreshed access token
- return refreshToken(token, client_id, client_secret, oAuth2Client, userId).then(resolve, reject);
+ return refreshToken(token!, client_id, client_secret, oAuth2Client, userId).then(resolve, reject);
}
// Authentication successful!
- oAuth2Client.setCredentials(token);
- resolve({ token, client: oAuth2Client });
+ oAuth2Client.setCredentials(token!);
+ resolve({ token: token!, client: oAuth2Client });
});
});
}
@@ -145,35 +177,4 @@ export namespace GoogleApiServerUtils {
});
};
- /**
- * Get and store new token after prompting for user authorization, and then
- * execute the given callback with the authorized OAuth2 client.
- * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
- * @param {getEventsCallback} callback The callback for the authorized client.
- */
- function getNewToken(oAuth2Client: OAuth2Client, userId: string) {
- return new Promise<TokenResult>((resolve, reject) => {
- const authUrl = oAuth2Client.generateAuthUrl({
- access_type: 'offline',
- scope: SCOPES.map(relative => prefix + relative),
- });
- console.log('Authorize this app by visiting this url:', authUrl);
- const rl = createInterface({
- input: process.stdin,
- output: process.stdout,
- });
- rl.question('Enter the code from that page here: ', (code) => {
- rl.close();
- oAuth2Client.getToken(code, async (err, token) => {
- if (err || !token) {
- reject(err);
- return console.error('Error retrieving access token', err);
- }
- oAuth2Client.setCredentials(token);
- await Database.Auxiliary.GoogleAuthenticationToken.Write(userId, token);
- resolve({ token, client: oAuth2Client });
- });
- });
- });
- }
} \ No newline at end of file
diff --git a/src/server/apis/google/GooglePhotosUploadUtils.ts b/src/server/apis/google/GooglePhotosUploadUtils.ts
index 16c4f6c3a..4a67e57cc 100644
--- a/src/server/apis/google/GooglePhotosUploadUtils.ts
+++ b/src/server/apis/google/GooglePhotosUploadUtils.ts
@@ -4,6 +4,7 @@ import * as path from 'path';
import { MediaItemCreationResult } from './SharedTypes';
import { NewMediaItem } from "../../index";
import { BatchedArray, TimeUnit } from 'array-batcher';
+import { DashUploadUtils } from '../../DashUploadUtils';
export namespace GooglePhotosUploadUtils {
@@ -32,6 +33,9 @@ export namespace GooglePhotosUploadUtils {
};
export const DispatchGooglePhotosUpload = async (url: string) => {
+ if (!DashUploadUtils.imageFormats.includes(path.extname(url))) {
+ return undefined;
+ }
const body = await request(url, { encoding: null });
const parameters = {
method: 'POST',
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 24bad694d..0fbfbf2f3 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -46,15 +46,19 @@ export class CurrentUserUtils {
// setup workspaces library item
if (doc.workspaces === undefined) {
- const workspaces = Docs.Create.TreeDocument([], { title: "Workspaces", height: 100 });
+ const workspaces = Docs.Create.TreeDocument([], { title: "Workspaces".toUpperCase(), height: 100 });
workspaces.boxShadow = "0 0";
doc.workspaces = workspaces;
}
PromiseValue(Cast(doc.workspaces, Doc)).then(workspaces => {
if (workspaces) {
+ workspaces.backgroundColor = "#eeeeee";
workspaces.preventTreeViewOpen = true;
workspaces.forceActive = true;
workspaces.lockedPosition = true;
+ if (StrCast(workspaces.title) === "Workspaces") {
+ workspaces.title = "WORKSPACES";
+ }
}
});
@@ -71,15 +75,19 @@ export class CurrentUserUtils {
// setup Recently Closed library item
if (doc.recentlyClosed === undefined) {
- const recentlyClosed = Docs.Create.TreeDocument([], { title: "Recently Closed", height: 75 });
+ const recentlyClosed = Docs.Create.TreeDocument([], { title: "Recently Closed".toUpperCase(), height: 75 });
recentlyClosed.boxShadow = "0 0";
doc.recentlyClosed = recentlyClosed;
}
PromiseValue(Cast(doc.recentlyClosed, Doc)).then(recent => {
if (recent) {
+ recent.backgroundColor = "#eeeeee";
recent.preventTreeViewOpen = true;
recent.forceActive = true;
recent.lockedPosition = true;
+ if (StrCast(recent.title) === "Recently Closed") {
+ recent.title = "RECENTLY CLOSED";
+ }
}
});
@@ -97,10 +105,14 @@ export class CurrentUserUtils {
sidebar.gridGap = 5;
sidebar.xMargin = 5;
sidebar.yMargin = 5;
- Doc.GetProto(sidebar).backgroundColor = "#aca3a6";
sidebar.boxShadow = "1 1 3";
doc.sidebar = sidebar;
}
+ PromiseValue(Cast(doc.sidebar, Doc)).then(sidebar => {
+ if (sidebar) {
+ sidebar.backgroundColor = "lightgrey";
+ }
+ });
if (doc.overlays === undefined) {
const overlays = Docs.Create.FreeformDocument([], { title: "Overlays" });
@@ -112,7 +124,9 @@ export class CurrentUserUtils {
PromiseValue(Cast(doc.overlays, Doc)).then(overlays => overlays && Doc.AddDocToList(overlays, "data", doc.linkFollowBox = Docs.Create.LinkFollowBoxDocument({ x: 250, y: 20, width: 500, height: 370, title: "Link Follower" })));
}
- StrCast(doc.title).indexOf("@") !== -1 && (doc.title = StrCast(doc.title).split("@")[0] + "'s Library");
+ StrCast(doc.title).indexOf("@") !== -1 && (doc.title = (StrCast(doc.title).split("@")[0] + "'s Library").toUpperCase());
+ StrCast(doc.title).indexOf("'s Library") !== -1 && (doc.title = StrCast(doc.title).toUpperCase());
+ doc.backgroundColor = "#eeeeee";
doc.width = 100;
doc.preventTreeViewOpen = true;
doc.forceActive = true;
diff --git a/src/server/index.ts b/src/server/index.ts
index 526cc6cce..30513ef36 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -946,7 +946,22 @@ app.post(RouteStore.googleDocs + "/:sector/:action", (req, res) => {
});
});
-app.get(RouteStore.googlePhotosAccessToken, (req, res) => GoogleApiServerUtils.RetrieveAccessToken({ credentialsPath, userId: req.header("userId")! }).then(token => res.send(token)));
+app.get(RouteStore.readGooglePhotosAccessToken, async (req, res) => {
+ const userId = req.header("userId")!;
+ const token = await Database.Auxiliary.GoogleAuthenticationToken.Fetch(userId);
+ const information = { credentialsPath, userId };
+ if (!token) {
+ return res.send(await GoogleApiServerUtils.GenerateAuthenticationUrl(information));
+ }
+ GoogleApiServerUtils.RetrieveAccessToken(information).then(token => res.send(token));
+});
+
+app.post(RouteStore.writeGooglePhotosAccessToken, async (req, res) => {
+ const userId = req.header("userId")!;
+ const information = { credentialsPath, userId };
+ const { token } = await GoogleApiServerUtils.ProcessClientSideCode(information, req.body.authenticationCode);
+ res.send(token.access_token);
+});
const tokenError = "Unable to successfully upload bytes for all images!";
const mediaError = "Unable to convert all uploaded bytes to media items!";
@@ -969,16 +984,17 @@ app.post(RouteStore.googlePhotosMediaUpload, async (req, res) => {
await GooglePhotosUploadUtils.initialize({ credentialsPath, userId });
- let failed = 0;
+ let failed: number[] = [];
const newMediaItems = await BatchedArray.from<GooglePhotosUploadUtils.MediaInput>(media, { batchSize: 25 }).batchedMapPatientInterval(
{ magnitude: 100, unit: TimeUnit.Milliseconds },
async (batch: GooglePhotosUploadUtils.MediaInput[]) => {
const newMediaItems: NewMediaItem[] = [];
- for (let element of batch) {
+ for (let index = 0; index < batch.length; index++) {
+ const element = batch[index];
const uploadToken = await GooglePhotosUploadUtils.DispatchGooglePhotosUpload(element.url);
if (!uploadToken) {
- failed++;
+ failed.push(index);
} else {
newMediaItems.push({
description: element.description,
@@ -990,12 +1006,13 @@ app.post(RouteStore.googlePhotosMediaUpload, async (req, res) => {
}
);
- if (failed) {
- return _error(res, tokenError);
+ const failedCount = failed.length;
+ if (failedCount) {
+ console.log(`Unable to upload ${failedCount} image${failedCount === 1 ? "" : "s"} to Google's servers`);
}
GooglePhotosUploadUtils.CreateMediaItems(newMediaItems, req.body.album).then(
- result => _success(res, result.newMediaItemResults),
+ result => _success(res, { results: result.newMediaItemResults, failed }),
error => _error(res, mediaError, error)
);
});