diff options
author | Sam Wilkins <samwilkins333@gmail.com> | 2019-09-26 22:17:15 -0400 |
---|---|---|
committer | Sam Wilkins <samwilkins333@gmail.com> | 2019-09-26 22:17:15 -0400 |
commit | 20540a35be82c34cc3962de4f957d1aa43f8a2b0 (patch) | |
tree | a4d67686a1d323bab947fcf3a6d6c2575b576c3e /src | |
parent | e95387732e1fbff49ec035c3bec4b03324d814c8 (diff) |
finally transferred google credential management to database
Diffstat (limited to 'src')
-rw-r--r-- | src/client/Network.ts | 46 | ||||
-rw-r--r-- | src/client/apis/google_docs/GooglePhotosClientUtils.ts | 17 | ||||
-rw-r--r-- | src/client/documents/Documents.ts | 22 | ||||
-rw-r--r-- | src/client/util/Import & Export/DirectoryImportBox.tsx | 5 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 7 | ||||
-rw-r--r-- | src/server/apis/google/GoogleApiServerUtils.ts | 27 | ||||
-rw-r--r-- | src/server/database.ts | 32 | ||||
-rw-r--r-- | src/server/index.ts | 6 |
8 files changed, 93 insertions, 69 deletions
diff --git a/src/client/Network.ts b/src/client/Network.ts index cb46105f8..75ccb5e99 100644 --- a/src/client/Network.ts +++ b/src/client/Network.ts @@ -2,24 +2,32 @@ import { Utils } from "../Utils"; import { CurrentUserUtils } from "../server/authentication/models/current_user_utils"; import requestPromise = require('request-promise'); -export async function PostToServer(relativeRoute: string, body?: any) { - let options = { - uri: Utils.prepend(relativeRoute), - method: "POST", - headers: { userId: CurrentUserUtils.id }, - body, - json: true - }; - return requestPromise.post(options); -} +export namespace Identified { + + export async function FetchFromServer(relativeRoute: string) { + return (await fetch(relativeRoute, { headers: { userId: CurrentUserUtils.id } })).text(); + } + + export async function PostToServer(relativeRoute: string, body?: any) { + let options = { + uri: Utils.prepend(relativeRoute), + method: "POST", + headers: { userId: CurrentUserUtils.id }, + body, + json: true + }; + return requestPromise.post(options); + } + + export async function PostFormDataToServer(relativeRoute: string, formData: FormData) { + const parameters = { + method: 'POST', + headers: { userId: CurrentUserUtils.id }, + body: formData, + }; + const response = await fetch(relativeRoute, parameters); + const text = await response.json(); + return text; + } -export async function PostFormDataToServer(relativeRoute: string, formData: FormData) { - const parameters = { - method: 'POST', - headers: { userId: CurrentUserUtils.id }, - body: formData, - }; - const response = await fetch(relativeRoute, parameters); - const text = await response.json(); - return text; }
\ No newline at end of file diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts index b1b29210a..29cc042b6 100644 --- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts +++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts @@ -14,11 +14,14 @@ import { NewMediaItemResult, MediaItem } from "../../../server/apis/google/Share import { AssertionError } from "assert"; import { DocumentView } from "../../views/nodes/DocumentView"; import { DocumentManager } from "../../util/DocumentManager"; -import { PostToServer } from "../../Network"; +import { Identified } from "../../Network"; export namespace GooglePhotos { - const endpoint = async () => new Photos(await PostToServer(RouteStore.googlePhotosAccessToken)); + const endpoint = async () => { + const accessToken = await Identified.FetchFromServer(RouteStore.googlePhotosAccessToken); + return new Photos(accessToken); + }; export enum MediaType { ALL_MEDIA = 'ALL_MEDIA', @@ -296,7 +299,7 @@ export namespace GooglePhotos { }; export const WriteMediaItemsToServer = async (body: { mediaItems: any[] }): Promise<UploadInformation[]> => { - const uploads = await PostToServer(RouteStore.googlePhotosMediaDownload, body); + const uploads = await Identified.PostToServer(RouteStore.googlePhotosMediaDownload, body); return uploads; }; @@ -316,7 +319,7 @@ export namespace GooglePhotos { album = await Create.Album(album.title); } const media: MediaInput[] = []; - sources.forEach(source => { + for (let source of sources) { const data = Cast(Doc.GetProto(source).data, ImageField); if (!data) { return; @@ -324,11 +327,11 @@ export namespace GooglePhotos { const url = data.url.href; const target = Doc.MakeAlias(source); const description = parseDescription(target, descriptionKey); - DocumentView.makeCustomViewClicked(target, undefined); + await DocumentView.makeCustomViewClicked(target, undefined); media.push({ url, description }); - }); + } if (media.length) { - const uploads: NewMediaItemResult[] = await PostToServer(RouteStore.googlePhotosMediaUpload, { media, album }); + const uploads: NewMediaItemResult[] = await Identified.PostToServer(RouteStore.googlePhotosMediaUpload, { media, album }); return uploads; } }; diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a7a006f47..0369e89a6 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -337,16 +337,18 @@ export namespace Docs { let extension = path.extname(target); target = `${target.substring(0, target.length - extension.length)}_o${extension}`; } - requestImageSize(target) - .then((size: any) => { - let aspect = size.height / size.width; - if (!inst.proto!.nativeWidth) { - inst.proto!.nativeWidth = size.width; - } - inst.proto!.nativeHeight = Number(inst.proto!.nativeWidth!) * aspect; - inst.proto!.height = NumCast(inst.proto!.width) * aspect; - }) - .catch((err: any) => console.log(err)); + if (target !== "http://www.cs.brown.edu/") { + requestImageSize(target) + .then((size: any) => { + let aspect = size.height / size.width; + if (!inst.proto!.nativeWidth) { + inst.proto!.nativeWidth = size.width; + } + inst.proto!.nativeHeight = Number(inst.proto!.nativeWidth!) * aspect; + inst.proto!.height = NumCast(inst.proto!.width) * aspect; + }) + .catch((err: any) => console.log(err)); + } return inst; } export function PresDocument(initial: List<Doc> = new List(), options: DocumentOptions = {}) { diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index d0291aec4..de5287456 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -21,7 +21,7 @@ import { GooglePhotos } from "../../apis/google_docs/GooglePhotosClientUtils"; import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; import "./DirectoryImportBox.scss"; import BatchedArray from "array-batcher"; -import { PostFormDataToServer } from "../../Network"; +import { Identified } from "../../Network"; const unsupported = ["text/html", "text/plain"]; interface FileResponse { @@ -114,7 +114,7 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps> formData.append(Utils.GenerateGuid(), file); }); - const responses = await PostFormDataToServer(RouteStore.upload, formData); + const responses = await Identified.PostFormDataToServer(RouteStore.upload, formData); runInAction(() => this.completed += batch.length); return responses as FileResponse[]; }); @@ -279,7 +279,6 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps> }} /> <label htmlFor={"selector"} - onClick={console.log} style={{ opacity: isEditing ? 0 : 1, pointerEvents: isEditing ? "none" : "all", diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 78fcaad27..a6d350ca2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -295,10 +295,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu deleteClicked = (): void => { SelectionManager.DeselectAll(); this.props.removeDocument && this.props.removeDocument(this.props.Document); } @undoBatch - static makeNativeViewClicked = (doc: Doc): void => { swapViews(doc, "layoutNative", "layoutCustom"); } + static makeNativeViewClicked = async (doc: Doc): Promise<void> => swapViews(doc, "layoutNative", "layoutCustom") - @undoBatch static makeCustomViewClicked = async (doc: Doc, dataDoc: Opt<Doc>) => { + const batch = UndoManager.StartBatch("CustomViewClicked"); if (doc.layoutCustom === undefined) { Doc.GetProto(dataDoc || doc).layoutNative = Doc.MakeTitled("layoutNative"); await swapViews(doc, "", "layoutNative"); @@ -320,8 +320,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu Doc.ApplyTemplateTo(docTemplate, doc, undefined); Doc.GetProto(dataDoc || doc).layoutCustom = Doc.MakeTitled("layoutCustom"); } else { - swapViews(doc, "layoutCustom", "layoutNative"); + await swapViews(doc, "layoutCustom", "layoutNative"); } + batch.end(); } @undoBatch diff --git a/src/server/apis/google/GoogleApiServerUtils.ts b/src/server/apis/google/GoogleApiServerUtils.ts index 665dcf862..f2ce51395 100644 --- a/src/server/apis/google/GoogleApiServerUtils.ts +++ b/src/server/apis/google/GoogleApiServerUtils.ts @@ -103,21 +103,21 @@ export namespace GoogleApiServerUtils { */ export function authorize(credentials: any, userId: string): Promise<TokenResult> { const { client_secret, client_id, redirect_uris } = credentials.installed; - const oAuth2Client = new google.auth.OAuth2( - client_id, client_secret, redirect_uris[0]); - + const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]); return new Promise<TokenResult>((resolve, reject) => { + // Attempting to authorize user (${userId}) Database.Auxiliary.GoogleAuthenticationToken.Fetch(userId).then(token => { - // Check if we have previously stored a token for this userId. if (!token) { + // No token registered, so awaiting input from user return getNewToken(oAuth2Client, userId).then(resolve, reject); } - let parsed: Credentials = parseBuffer(token); - if (parsed.expiry_date! < new Date().getTime()) { - return refreshToken(parsed, client_id, client_secret, oAuth2Client, userId).then(resolve, reject); + 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); } - oAuth2Client.setCredentials(parsed); - resolve({ token: parsed, client: oAuth2Client }); + // Authentication successful! + oAuth2Client.setCredentials(token); + resolve({ token, client: oAuth2Client }); }); }); } @@ -134,11 +134,12 @@ export namespace GoogleApiServerUtils { }; let url = `${refreshEndpoint}?${qs.stringify(queryParameters)}`; request.post(url, headerParameters).then(async response => { - let parsed = JSON.parse(response); - credentials.access_token = parsed.access_token; - credentials.expiry_date = new Date().getTime() + (parsed.expires_in * 1000); + let { access_token, expires_in } = JSON.parse(response); + const expiry_date = new Date().getTime() + (expires_in * 1000); + await Database.Auxiliary.GoogleAuthenticationToken.Update(userId, access_token, expiry_date); + credentials.access_token = access_token; + credentials.expiry_date = expiry_date; oAuth2Client.setCredentials(credentials); - await Database.Auxiliary.GoogleAuthenticationToken.Write(userId, credentials); resolve({ token: credentials, client: oAuth2Client }); }); }); diff --git a/src/server/database.ts b/src/server/database.ts index 890ac6b32..bc9a9ab23 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -1,7 +1,7 @@ import * as mongodb from 'mongodb'; import { Transferable } from './Message'; import { Opt } from '../new_fields/Doc'; -import { Utils } from '../Utils'; +import { Utils, emptyFunction } from '../Utils'; import { DashUploadUtils } from './DashUploadUtils'; export namespace Database { @@ -21,7 +21,7 @@ export namespace Database { }); } - public update(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, upsert = true, collectionName = Database.DocumentsCollection) { + public async update(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, upsert = true, collectionName = Database.DocumentsCollection) { if (this.db) { let collection = this.db.collection(collectionName); const prom = this.currentWrites[id]; @@ -40,6 +40,7 @@ export namespace Database { }; newProm = prom ? prom.then(run) : run(); this.currentWrites[id] = newProm; + return newProm; } else { this.onConnect.push(() => this.update(id, value, callback, upsert, collectionName)); } @@ -226,23 +227,22 @@ export namespace Database { export namespace Auxiliary { export enum AuxiliaryCollections { - GooglePhotosUploadHistory = "UploadedFromGooglePhotos" + GooglePhotosUploadHistory = "uploadedFromGooglePhotos" } - const GoogleAuthentication = "GoogleAuthentication"; - const SanitizedCappedQuery = async (query: { [key: string]: any }, collection: string, cap: number) => { + const SanitizedCappedQuery = async (query: { [key: string]: any }, collection: string, cap: number, removeId = true) => { const cursor = await Instance.query(query, undefined, collection); const results = await cursor.toArray(); const slice = results.slice(0, Math.min(cap, results.length)); - return slice.map(result => { + return removeId ? slice.map(result => { delete result._id; return result; - }); + }) : slice; }; - const SanitizedSingletonQuery = async (query: { [key: string]: any }, collection: string) => { - const results = await SanitizedCappedQuery(query, collection, 1); + const SanitizedSingletonQuery = async (query: { [key: string]: any }, collection: string, removeId = true) => { + const results = await SanitizedCappedQuery(query, collection, 1, removeId); return results.length ? results[0] : undefined; }; @@ -252,14 +252,24 @@ export namespace Database { export namespace GoogleAuthenticationToken { - export const Fetch = async (userId: string) => { - return SanitizedSingletonQuery({ userId }, GoogleAuthentication); + const GoogleAuthentication = "googleAuthentication"; + + export const Fetch = async (userId: string, removeId = true) => { + return SanitizedSingletonQuery({ userId }, GoogleAuthentication, removeId); }; export const Write = async (userId: string, token: any) => { return Instance.insert({ userId, ...token }, GoogleAuthentication); }; + export const Update = async (userId: string, access_token: string, expiry_date: number) => { + const entry = await Fetch(userId, false); + if (entry) { + const parameters = { $set: { access_token, expiry_date } }; + return Instance.update(entry._id, parameters, emptyFunction, true, GoogleAuthentication); + } + }; + } export const LogUpload = async (information: DashUploadUtils.UploadInformation) => { diff --git a/src/server/index.ts b/src/server/index.ts index 2ff63ab78..33d098e2c 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -824,7 +824,7 @@ app.post(RouteStore.googleDocs + "/:sector/:action", (req, res) => { }); }); -app.get(RouteStore.googlePhotosAccessToken, (req, res) => GoogleApiServerUtils.RetrieveAccessToken({ credentialsPath, userId: req.headers.userId as string }).then(token => res.send(token))); +app.get(RouteStore.googlePhotosAccessToken, (req, res) => GoogleApiServerUtils.RetrieveAccessToken({ credentialsPath, userId: req.header("userId")! }).then(token => res.send(token))); const tokenError = "Unable to successfully upload bytes for all images!"; const mediaError = "Unable to convert all uploaded bytes to media items!"; @@ -839,9 +839,9 @@ export interface NewMediaItem { app.post(RouteStore.googlePhotosMediaUpload, async (req, res) => { const { media } = req.body; - const { userId } = req.headers; + const userId = req.header("userId"); - if (!userId || Array.isArray(userId)) { + if (!userId) { return _error(res, userIdError); } |