diff options
| author | Stanley Yip <stanley_yip@brown.edu> | 2020-01-08 13:47:29 -0500 |
|---|---|---|
| committer | Stanley Yip <stanley_yip@brown.edu> | 2020-01-08 13:47:29 -0500 |
| commit | abfa42b6f2cf863deee19aac19328a23687464cb (patch) | |
| tree | b481f23ffa7bccbde7a31de34f50d765b6b73162 /src/client/apis | |
| parent | d8fc218f3481728f221ceacc60ac4bc553f8e295 (diff) | |
| parent | 19a71cb2788b9c1c8d8ced4af285bf91033ba626 (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.tsx | 40 | ||||
| -rw-r--r-- | src/client/apis/google_docs/GoogleApiClientUtils.ts | 35 | ||||
| -rw-r--r-- | src/client/apis/google_docs/GooglePhotosClientUtils.ts | 27 | ||||
| -rw-r--r-- | src/client/apis/youtube/YoutubeBox.tsx | 102 |
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} > |
