aboutsummaryrefslogtreecommitdiff
path: root/src/client/apis
diff options
context:
space:
mode:
authorStanley Yip <stanley_yip@brown.edu>2020-01-08 13:47:29 -0500
committerStanley Yip <stanley_yip@brown.edu>2020-01-08 13:47:29 -0500
commitabfa42b6f2cf863deee19aac19328a23687464cb (patch)
treeb481f23ffa7bccbde7a31de34f50d765b6b73162 /src/client/apis
parentd8fc218f3481728f221ceacc60ac4bc553f8e295 (diff)
parent19a71cb2788b9c1c8d8ced4af285bf91033ba626 (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into pen
Diffstat (limited to 'src/client/apis')
-rw-r--r--src/client/apis/GoogleAuthenticationManager.tsx40
-rw-r--r--src/client/apis/google_docs/GoogleApiClientUtils.ts35
-rw-r--r--src/client/apis/google_docs/GooglePhotosClientUtils.ts27
-rw-r--r--src/client/apis/youtube/YoutubeBox.tsx102
4 files changed, 103 insertions, 101 deletions
diff --git a/src/client/apis/GoogleAuthenticationManager.tsx b/src/client/apis/GoogleAuthenticationManager.tsx
index 01dac3996..ce1277667 100644
--- a/src/client/apis/GoogleAuthenticationManager.tsx
+++ b/src/client/apis/GoogleAuthenticationManager.tsx
@@ -3,8 +3,7 @@ import { observer } from "mobx-react";
import * as React from "react";
import MainViewModal from "../views/MainViewModal";
import { Opt } from "../../new_fields/Doc";
-import { Identified } from "../Network";
-import { RouteStore } from "../../server/RouteStore";
+import { Networking } from "../Network";
import "./GoogleAuthenticationManager.scss";
const AuthenticationUrl = "https://accounts.google.com/o/oauth2/v2/auth";
@@ -31,7 +30,7 @@ export default class GoogleAuthenticationManager extends React.Component<{}> {
}
public fetchOrGenerateAccessToken = async () => {
- let response = await Identified.FetchFromServer(RouteStore.readGoogleAccessToken);
+ const response = await Networking.FetchFromServer("/readGoogleAccessToken");
// if this is an authentication url, activate the UI to register the new access token
if (new RegExp(AuthenticationUrl).test(response)) {
this.isOpen = true;
@@ -39,24 +38,25 @@ export default class GoogleAuthenticationManager extends React.Component<{}> {
return new Promise<string>(async resolve => {
const disposer = reaction(
() => this.authenticationCode,
- authenticationCode => {
- if (authenticationCode) {
- Identified.PostToServer(RouteStore.writeGoogleAccessToken, { authenticationCode }).then(
- ({ access_token, avatar, name }) => {
- runInAction(() => {
- this.avatar = avatar;
- this.username = name;
- });
- this.beginFadeout();
- disposer();
- resolve(access_token);
- },
- action(() => {
- this.hasBeenClicked = false;
- this.success = false;
- })
- );
+ async authenticationCode => {
+ if (!authenticationCode) {
+ return;
}
+ const { access_token, avatar, name } = await Networking.PostToServer(
+ "/writeGoogleAccessToken",
+ { authenticationCode }
+ );
+ runInAction(() => {
+ this.avatar = avatar;
+ this.username = name;
+ });
+ this.beginFadeout();
+ disposer();
+ resolve(access_token);
+ action(() => {
+ this.hasBeenClicked = false;
+ this.success = false;
+ });
}
);
});
diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts
index 1cf01fc3d..d2a79f189 100644
--- a/src/client/apis/google_docs/GoogleApiClientUtils.ts
+++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts
@@ -1,9 +1,8 @@
-import { docs_v1, slides_v1 } from "googleapis";
-import { RouteStore } from "../../../server/RouteStore";
+import { docs_v1 } from "googleapis";
import { Opt } from "../../../new_fields/Doc";
import { isArray } from "util";
import { EditorState } from "prosemirror-state";
-import { Identified } from "../../Network";
+import { Networking } from "../../Network";
export const Pulls = "googleDocsPullCount";
export const Pushes = "googleDocsPushCount";
@@ -77,14 +76,14 @@ export namespace GoogleApiClientUtils {
* @returns the documentId of the newly generated document, or undefined if the creation process fails.
*/
export const create = async (options: CreateOptions): Promise<CreationResult> => {
- const path = `${RouteStore.googleDocs}/Documents/${Actions.Create}`;
+ const path = `/googleDocs/Documents/${Actions.Create}`;
const parameters = {
requestBody: {
title: options.title || `Dash Export (${new Date().toDateString()})`
}
};
try {
- const schema: docs_v1.Schema$Document = await Identified.PostToServer(path, parameters);
+ const schema: docs_v1.Schema$Document = await Networking.PostToServer(path, parameters);
return schema.documentId;
} catch {
return undefined;
@@ -95,7 +94,7 @@ export namespace GoogleApiClientUtils {
export type ExtractResult = { text: string, paragraphs: DeconstructedParagraph[] };
export const extractText = (document: docs_v1.Schema$Document, removeNewlines = false): ExtractResult => {
- let paragraphs = extractParagraphs(document);
+ const paragraphs = extractParagraphs(document);
let text = paragraphs.map(paragraph => paragraph.contents.filter(content => !("inlineObjectId" in content)).map(run => run as docs_v1.Schema$TextRun).join("")).join("");
text = text.substring(0, text.length - 1);
removeNewlines && text.ReplaceAll("\n", "");
@@ -108,14 +107,14 @@ export namespace GoogleApiClientUtils {
const fragments: DeconstructedParagraph[] = [];
if (document.body && document.body.content) {
for (const element of document.body.content) {
- let runs: ContentArray = [];
+ const runs: ContentArray = [];
let bullet: Opt<number>;
if (element.paragraph) {
if (element.paragraph.elements) {
for (const inner of element.paragraph.elements) {
if (inner) {
if (inner.textRun) {
- let run = inner.textRun;
+ const run = inner.textRun;
(run.content || !filterEmpty) && runs.push(inner.textRun);
} else if (inner.inlineObjectElement) {
runs.push(inner.inlineObjectElement);
@@ -154,10 +153,10 @@ export namespace GoogleApiClientUtils {
}
export const retrieve = async (options: RetrieveOptions): Promise<RetrievalResult> => {
- const path = `${RouteStore.googleDocs}/Documents/${Actions.Retrieve}`;
+ const path = `/googleDocs/Documents/${Actions.Retrieve}`;
try {
const parameters = { documentId: options.documentId };
- const schema: RetrievalResult = await Identified.PostToServer(path, parameters);
+ const schema: RetrievalResult = await Networking.PostToServer(path, parameters);
return schema;
} catch {
return undefined;
@@ -165,7 +164,7 @@ export namespace GoogleApiClientUtils {
};
export const update = async (options: UpdateOptions): Promise<UpdateResult> => {
- const path = `${RouteStore.googleDocs}/Documents/${Actions.Update}`;
+ const path = `/googleDocs/Documents/${Actions.Update}`;
const parameters = {
documentId: options.documentId,
requestBody: {
@@ -173,7 +172,7 @@ export namespace GoogleApiClientUtils {
}
};
try {
- const replies: UpdateResult = await Identified.PostToServer(path, parameters);
+ const replies: UpdateResult = await Networking.PostToServer(path, parameters);
return replies;
} catch {
return undefined;
@@ -183,8 +182,8 @@ export namespace GoogleApiClientUtils {
export const read = async (options: ReadOptions): Promise<Opt<ReadResult>> => {
return retrieve({ documentId: options.documentId }).then(document => {
if (document) {
- let title = document.title!;
- let body = Utils.extractText(document, options.removeNewlines).text;
+ const title = document.title!;
+ const body = Utils.extractText(document, options.removeNewlines).text;
return { title, body };
}
});
@@ -193,7 +192,7 @@ export namespace GoogleApiClientUtils {
export const readLines = async (options: ReadOptions): Promise<Opt<ReadLinesResult>> => {
return retrieve({ documentId: options.documentId }).then(document => {
if (document) {
- let title = document.title;
+ const title = document.title;
let bodyLines = Utils.extractText(document).text.split("\n");
options.removeNewlines && (bodyLines = bodyLines.filter(line => line.length));
return { title, bodyLines };
@@ -202,7 +201,7 @@ export namespace GoogleApiClientUtils {
};
export const setStyle = async (options: UpdateOptions) => {
- let replies: any = await update({
+ const replies: any = await update({
documentId: options.documentId,
requests: options.requests
});
@@ -222,7 +221,7 @@ export namespace GoogleApiClientUtils {
let index = options.index;
const mode = options.mode;
if (!(index && mode === WriteMode.Insert)) {
- let schema = await retrieve({ documentId });
+ const schema = await retrieve({ documentId });
if (!schema || !(index = Utils.endOf(schema))) {
return undefined;
}
@@ -249,7 +248,7 @@ export namespace GoogleApiClientUtils {
return undefined;
}
requests.push(...options.content.requests);
- let replies: any = await update({ documentId: documentId, requests });
+ const replies: any = await update({ documentId: documentId, requests });
if ("errors" in replies) {
console.log("Write operation failed:");
console.log(replies.errors.map((error: any) => error.message));
diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts
index e93fa6eb4..966d8053a 100644
--- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts
+++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts
@@ -1,5 +1,4 @@
import { Utils } from "../../../Utils";
-import { RouteStore } from "../../../server/RouteStore";
import { ImageField } from "../../../new_fields/URLField";
import { Cast, StrCast } from "../../../new_fields/Types";
import { Doc, Opt, DocListCastAsync } from "../../../new_fields/Doc";
@@ -13,7 +12,7 @@ import { Docs, DocumentOptions } from "../../documents/Documents";
import { NewMediaItemResult, MediaItem } from "../../../server/apis/google/SharedTypes";
import { AssertionError } from "assert";
import { DocumentView } from "../../views/nodes/DocumentView";
-import { Identified } from "../../Network";
+import { Networking } from "../../Network";
import GoogleAuthenticationManager from "../GoogleAuthenticationManager";
export namespace GooglePhotos {
@@ -78,6 +77,7 @@ export namespace GooglePhotos {
}
export const CollectionToAlbum = async (options: AlbumCreationOptions): Promise<Opt<AlbumCreationResult>> => {
+ await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
const { collection, title, descriptionKey, tag } = options;
const dataDocument = Doc.GetProto(collection);
const images = ((await DocListCastAsync(dataDocument.data)) || []).filter(doc => Cast(doc.data, ImageField));
@@ -127,10 +127,11 @@ export namespace GooglePhotos {
export type CollectionConstructor = (data: Array<Doc>, options: DocumentOptions, ...args: any) => Doc;
export const CollectionFromSearch = async (constructor: CollectionConstructor, requested: Opt<Partial<Query.SearchOptions>>): Promise<Doc> => {
- let response = await Query.ContentSearch(requested);
- let uploads = await Transactions.WriteMediaItemsToServer(response);
+ await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
+ const response = await Query.ContentSearch(requested);
+ const uploads = await Transactions.WriteMediaItemsToServer(response);
const children = uploads.map((upload: Transactions.UploadInformation) => {
- let document = Docs.Create.ImageDocument(Utils.fileUrl(upload.fileNames.clean));
+ const document = Docs.Create.ImageDocument(Utils.fileUrl(upload.fileNames.clean));
document.fillColumn = true;
document.contentSize = upload.contentSize;
return document;
@@ -147,6 +148,7 @@ export namespace GooglePhotos {
const comparator = (a: string, b: string) => (a < b) ? -1 : (a > b ? 1 : 0);
export const TagChildImages = async (collection: Doc) => {
+ await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
const idMapping = await Cast(collection.googlePhotosIdMapping, Doc);
if (!idMapping) {
throw new Error("Appending image metadata requires that the targeted collection have already been mapped to an album!");
@@ -155,12 +157,12 @@ export namespace GooglePhotos {
const images = (await DocListCastAsync(collection.data))!.map(Doc.GetProto);
images && images.forEach(image => tagMapping.set(image[Id], ContentCategories.NONE));
const values = Object.values(ContentCategories);
- for (let value of values) {
+ for (const value of values) {
if (value !== ContentCategories.NONE) {
const results = await ContentSearch({ included: [value] });
if (results.mediaItems) {
const ids = results.mediaItems.map(item => item.id);
- for (let id of ids) {
+ for (const id of ids) {
const image = await Cast(idMapping[id], Doc);
if (image) {
const key = image[Id];
@@ -218,9 +220,9 @@ export namespace GooglePhotos {
export const AlbumSearch = async (albumId: string, pageSize = 100): Promise<MediaItem[]> => {
const photos = await endpoint();
- let mediaItems: MediaItem[] = [];
+ const mediaItems: MediaItem[] = [];
let nextPageTokenStored: Opt<string> = undefined;
- let found = 0;
+ const found = 0;
do {
const response: any = await photos.mediaItems.search(albumId, pageSize, nextPageTokenStored);
mediaItems.push(...response.mediaItems);
@@ -304,7 +306,7 @@ export namespace GooglePhotos {
};
export const WriteMediaItemsToServer = async (body: { mediaItems: any[] }): Promise<UploadInformation[]> => {
- const uploads = await Identified.PostToServer(RouteStore.googlePhotosMediaDownload, body);
+ const uploads = await Networking.PostToServer("/googlePhotosMediaDownload", body);
return uploads;
};
@@ -325,11 +327,12 @@ export namespace GooglePhotos {
}
export const UploadImages = async (sources: Doc[], album?: AlbumReference, descriptionKey = "caption"): Promise<Opt<ImageUploadResults>> => {
+ await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
if (album && "title" in album) {
album = await Create.Album(album.title);
}
const media: MediaInput[] = [];
- for (let source of sources) {
+ for (const source of sources) {
const data = Cast(Doc.GetProto(source).data, ImageField);
if (!data) {
return;
@@ -341,7 +344,7 @@ export namespace GooglePhotos {
media.push({ url, description });
}
if (media.length) {
- const results = await Identified.PostToServer(RouteStore.googlePhotosMediaUpload, { media, album });
+ const results = await Networking.PostToServer("/googlePhotosMediaUpload", { media, album });
return results;
}
};
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index bed812852..fd3d9e2f1 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -48,44 +48,44 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
*/
async componentWillMount() {
//DocServer.getYoutubeChannels();
- let castedSearchBackUp = Cast(this.props.Document.cachedSearchResults, Doc);
- let awaitedBackUp = await castedSearchBackUp;
- let castedDetailBackUp = Cast(this.props.Document.cachedDetails, Doc);
- let awaitedDetails = await castedDetailBackUp;
+ const castedSearchBackUp = Cast(this.props.Document.cachedSearchResults, Doc);
+ const awaitedBackUp = await castedSearchBackUp;
+ const castedDetailBackUp = Cast(this.props.Document.cachedDetails, Doc);
+ const awaitedDetails = await castedDetailBackUp;
if (awaitedBackUp) {
- let jsonList = await DocListCastAsync(awaitedBackUp.json);
- let jsonDetailList = await DocListCastAsync(awaitedDetails!.json);
+ const jsonList = await DocListCastAsync(awaitedBackUp.json);
+ const jsonDetailList = await DocListCastAsync(awaitedDetails!.json);
if (jsonList!.length !== 0) {
runInAction(() => this.searchResultsFound = true);
let index = 0;
//getting the necessary information from backUps and building templates that will be used to map in render
- for (let video of jsonList!) {
-
- let videoId = await Cast(video.id, Doc);
- let id = StrCast(videoId!.videoId);
- let snippet = await Cast(video.snippet, Doc);
- let videoTitle = this.filterYoutubeTitleResult(StrCast(snippet!.title));
- let thumbnail = await Cast(snippet!.thumbnails, Doc);
- let thumbnailMedium = await Cast(thumbnail!.medium, Doc);
- let thumbnailUrl = StrCast(thumbnailMedium!.url);
- let videoDescription = StrCast(snippet!.description);
- let pusblishDate = (this.roundPublishTime(StrCast(snippet!.publishedAt)))!;
- let channelTitle = StrCast(snippet!.channelTitle);
+ for (const video of jsonList!) {
+
+ const videoId = await Cast(video.id, Doc);
+ const id = StrCast(videoId!.videoId);
+ const snippet = await Cast(video.snippet, Doc);
+ const videoTitle = this.filterYoutubeTitleResult(StrCast(snippet!.title));
+ const thumbnail = await Cast(snippet!.thumbnails, Doc);
+ const thumbnailMedium = await Cast(thumbnail!.medium, Doc);
+ const thumbnailUrl = StrCast(thumbnailMedium!.url);
+ const videoDescription = StrCast(snippet!.description);
+ const pusblishDate = (this.roundPublishTime(StrCast(snippet!.publishedAt)))!;
+ const channelTitle = StrCast(snippet!.channelTitle);
let duration: string = "";
let viewCount: string = "";
if (jsonDetailList!.length !== 0) {
- let contentDetails = await Cast(jsonDetailList![index].contentDetails, Doc);
- let statistics = await Cast(jsonDetailList![index].statistics, Doc);
+ const contentDetails = await Cast(jsonDetailList![index].contentDetails, Doc);
+ const statistics = await Cast(jsonDetailList![index].statistics, Doc);
duration = this.convertIsoTimeToDuration(StrCast(contentDetails!.duration));
viewCount = this.abbreviateViewCount(parseInt(StrCast(statistics!.viewCount)))!;
}
index = index + 1;
- let newTemplate: VideoTemplate = { videoId: id, videoTitle: videoTitle, thumbnailUrl: thumbnailUrl, publishDate: pusblishDate, channelTitle: channelTitle, videoDescription: videoDescription, duration: duration, viewCount: viewCount };
+ const newTemplate: VideoTemplate = { videoId: id, videoTitle: videoTitle, thumbnailUrl: thumbnailUrl, publishDate: pusblishDate, channelTitle: channelTitle, videoDescription: videoDescription, duration: duration, viewCount: viewCount };
runInAction(() => this.curVideoTemplates.push(newTemplate));
}
}
@@ -115,7 +115,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
*/
onEnterKeyDown = (e: React.KeyboardEvent) => {
if (e.keyCode === 13) {
- let submittedTitle = this.YoutubeSearchElement!.value;
+ const submittedTitle = this.YoutubeSearchElement!.value;
this.YoutubeSearchElement!.value = "";
this.YoutubeSearchElement!.blur();
DocServer.getYoutubeVideos(submittedTitle, this.processesVideoResults);
@@ -184,23 +184,23 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
* difference between today's date and that date, in terms of "ago" to imitate youtube.
*/
roundPublishTime = (publishTime: string) => {
- let date = new Date(publishTime).getTime();
- let curDate = new Date().getTime();
- let timeDif = curDate - date;
- let totalSeconds = timeDif / 1000;
- let totalMin = totalSeconds / 60;
- let totalHours = totalMin / 60;
- let totalDays = totalHours / 24;
- let totalMonths = totalDays / 30.417;
- let totalYears = totalMonths / 12;
-
-
- let truncYears = Math.trunc(totalYears);
- let truncMonths = Math.trunc(totalMonths);
- let truncDays = Math.trunc(totalDays);
- let truncHours = Math.trunc(totalHours);
- let truncMin = Math.trunc(totalMin);
- let truncSec = Math.trunc(totalSeconds);
+ const date = new Date(publishTime).getTime();
+ const curDate = new Date().getTime();
+ const timeDif = curDate - date;
+ const totalSeconds = timeDif / 1000;
+ const totalMin = totalSeconds / 60;
+ const totalHours = totalMin / 60;
+ const totalDays = totalHours / 24;
+ const totalMonths = totalDays / 30.417;
+ const totalYears = totalMonths / 12;
+
+
+ const truncYears = Math.trunc(totalYears);
+ const truncMonths = Math.trunc(totalMonths);
+ const truncDays = Math.trunc(totalDays);
+ const truncHours = Math.trunc(totalHours);
+ const truncMin = Math.trunc(totalMin);
+ const truncSec = Math.trunc(totalSeconds);
let pluralCase = "";
@@ -230,7 +230,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
*/
convertIsoTimeToDuration = (isoDur: string) => {
- let convertedTime = isoDur.replace(/D|H|M/g, ":").replace(/P|T|S/g, "").split(":");
+ const convertedTime = isoDur.replace(/D|H|M/g, ":").replace(/P|T|S/g, "").split(":");
if (1 === convertedTime.length) {
2 !== convertedTime[0].length && (convertedTime[0] = "0" + convertedTime[0]), convertedTime[0] = "0:" + convertedTime[0];
@@ -269,10 +269,10 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
if (this.searchResults.length !== 0) {
return <ul>
{this.searchResults.map((video, index) => {
- let filteredTitle = this.filterYoutubeTitleResult(video.snippet.title);
- let channelTitle = video.snippet.channelTitle;
- let videoDescription = video.snippet.description;
- let pusblishDate = this.roundPublishTime(video.snippet.publishedAt);
+ const filteredTitle = this.filterYoutubeTitleResult(video.snippet.title);
+ const channelTitle = video.snippet.channelTitle;
+ const videoDescription = video.snippet.description;
+ const pusblishDate = this.roundPublishTime(video.snippet.publishedAt);
let duration;
let viewCount;
if (this.videoDetails.length !== 0) {
@@ -331,26 +331,26 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
*/
@action
embedVideoOnClick = (videoId: string, filteredTitle: string) => {
- let embeddedUrl = "https://www.youtube.com/embed/" + videoId;
+ const embeddedUrl = "https://www.youtube.com/embed/" + videoId;
this.selectedVideoUrl = embeddedUrl;
- let addFunction = this.props.addDocument!;
- let newVideoX = NumCast(this.props.Document.x);
- let newVideoY = NumCast(this.props.Document.y) + NumCast(this.props.Document.height);
+ const addFunction = this.props.addDocument!;
+ const newVideoX = NumCast(this.props.Document.x);
+ const newVideoY = NumCast(this.props.Document.y) + NumCast(this.props.Document.height);
addFunction(Docs.Create.VideoDocument(embeddedUrl, { title: filteredTitle, width: 400, height: 315, x: newVideoX, y: newVideoY }));
this.videoClicked = true;
}
render() {
- let content =
+ const content =
<div className="youtubeBox-cont" style={{ width: "100%", height: "100%", position: "absolute" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
<input type="text" placeholder="Search for a video" onKeyDown={this.onEnterKeyDown} style={{ height: 40, width: "100%", border: "1px solid black", padding: 5, textAlign: "center" }} ref={(e) => this.YoutubeSearchElement = e!} />
{this.renderSearchResultsOrVideo()}
</div>;
- let frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
+ const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
- let classname = "webBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
+ const classname = "webBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
return (
<>
<div className={classname} >