From aa1eb6ba4217fb48ab10539ca0373b4a1f649192 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Tue, 5 May 2020 02:48:03 -0700
Subject: database, delete and google authentication simplifications and
 improvements, as well as formatted text box updates data state at field key
 not just data

---
 src/client/apis/GoogleAuthenticationManager.tsx | 125 ++++++++++++++++--------
 1 file changed, 82 insertions(+), 43 deletions(-)

(limited to 'src/client/apis/GoogleAuthenticationManager.tsx')

diff --git a/src/client/apis/GoogleAuthenticationManager.tsx b/src/client/apis/GoogleAuthenticationManager.tsx
index 417dc3c3b..018c980d8 100644
--- a/src/client/apis/GoogleAuthenticationManager.tsx
+++ b/src/client/apis/GoogleAuthenticationManager.tsx
@@ -1,10 +1,11 @@
-import { observable, action, reaction, runInAction } from "mobx";
+import { observable, action, reaction, runInAction, IReactionDisposer } from "mobx";
 import { observer } from "mobx-react";
 import * as React from "react";
 import MainViewModal from "../views/MainViewModal";
 import { Opt } from "../../new_fields/Doc";
 import { Networking } from "../Network";
 import "./GoogleAuthenticationManager.scss";
+import { Scripting } from "../util/Scripting";
 
 const AuthenticationUrl = "https://accounts.google.com/o/oauth2/v2/auth";
 const prompt = "Paste authorization code here...";
@@ -15,64 +16,89 @@ export default class GoogleAuthenticationManager extends React.Component<{}> {
     private authenticationLink: Opt<string> = undefined;
     @observable private openState = false;
     @observable private authenticationCode: Opt<string> = undefined;
-    @observable private clickedState = false;
+    @observable private showPasteTargetState = false;
     @observable private success: Opt<boolean> = undefined;
     @observable private displayLauncher = true;
-    @observable private avatar: Opt<string> = undefined;
-    @observable private username: Opt<string> = undefined;
+    @observable private credentials: any;
+    private disposer: Opt<IReactionDisposer>;
 
     private set isOpen(value: boolean) {
         runInAction(() => this.openState = value);
     }
 
-    private set hasBeenClicked(value: boolean) {
-        runInAction(() => this.clickedState = value);
+    private set shouldShowPasteTarget(value: boolean) {
+        runInAction(() => this.showPasteTargetState = value);
     }
 
-    public fetchOrGenerateAccessToken = async () => {
-        const response = await Networking.FetchFromServer("/readGoogleAccessToken");
+    public cancel() {
+        this.openState && this.resetState(0, 0);
+    }
+
+    public fetchOrGenerateAccessToken = async (displayIfFound = false) => {
+        let response: any = 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;
             this.authenticationLink = response;
             return new Promise<string>(async resolve => {
-                const disposer = reaction(
+                this.disposer?.();
+                this.disposer = reaction(
                     () => this.authenticationCode,
                     async authenticationCode => {
-                        if (authenticationCode) {
-                            disposer();
-                            const { access_token, avatar, name } = await Networking.PostToServer("/writeGoogleAccessToken", { authenticationCode });
+                        if (authenticationCode && /\d{1}\/[\w-]{55}/.test(authenticationCode)) {
+                            this.disposer?.();
+                            const response = await Networking.PostToServer("/writeGoogleAccessToken", { authenticationCode });
                             runInAction(() => {
-                                this.avatar = avatar;
-                                this.username = name;
-                                this.hasBeenClicked = false;
-                                this.success = false;
+                                this.success = true;
+                                this.credentials = response;
                             });
-                            this.beginFadeout();
-                            resolve(access_token);
+                            this.resetState();
+                            resolve(response.access_token);
                         }
                     }
                 );
             });
         }
-        // otherwise, we already have a valid, stored access token
-        return response;
+
+        // otherwise, we already have a valid, stored access token and user info
+        response = JSON.parse(response);
+        if (displayIfFound) {
+            runInAction(() => {
+                this.success = true;
+                this.credentials = response;
+            });
+            this.resetState(-1, -1);
+            this.isOpen = true;
+        }
+        return response.access_token;
     }
 
-    beginFadeout = action(() => {
-        this.success = true;
+    resetState = action((visibleForMS: number = 3000, fadesOutInMS: number = 500) => {
+        if (!visibleForMS && !fadesOutInMS) {
+            runInAction(() => {
+                this.isOpen = false;
+                this.success = undefined;
+                this.displayLauncher = true;
+                this.credentials = undefined;
+                this.shouldShowPasteTarget = false;
+                this.authenticationCode = undefined;
+            });
+            return;
+        }
         this.authenticationCode = undefined;
         this.displayLauncher = false;
-        this.hasBeenClicked = false;
-        setTimeout(action(() => {
-            this.isOpen = false;
+        this.shouldShowPasteTarget = false;
+        if (visibleForMS > 0 && fadesOutInMS > 0) {
             setTimeout(action(() => {
-                this.success = undefined;
-                this.displayLauncher = true;
-                this.avatar = undefined;
-                this.username = undefined;
-            }), 500);
-        }), 3000);
+                this.isOpen = false;
+                setTimeout(action(() => {
+                    this.success = undefined;
+                    this.displayLauncher = true;
+                    this.credentials = undefined;
+                }), fadesOutInMS);
+            }), visibleForMS);
+        }
     });
 
     constructor(props: {}) {
@@ -83,27 +109,38 @@ export default class GoogleAuthenticationManager extends React.Component<{}> {
     private get renderPrompt() {
         return (
             <div className={'authorize-container'}>
+
                 {this.displayLauncher ? <button
                     className={"dispatch"}
                     onClick={() => {
                         window.open(this.authenticationLink);
-                        setTimeout(() => this.hasBeenClicked = true, 500);
+                        setTimeout(() => this.shouldShowPasteTarget = true, 500);
                     }}
-                    style={{ marginBottom: this.clickedState ? 15 : 0 }}
+                    style={{ marginBottom: this.showPasteTargetState ? 15 : 0 }}
                 >Authorize a Google account...</button> : (null)}
-                {this.clickedState ? <input
+                {this.showPasteTargetState ? <input
                     className={'paste-target'}
                     onChange={action(e => this.authenticationCode = e.currentTarget.value)}
                     placeholder={prompt}
                 /> : (null)}
-                {this.avatar ? <img
-                    className={'avatar'}
-                    src={this.avatar}
-                /> : (null)}
-                {this.username ? <span
-                    className={'welcome'}
-                >Welcome to Dash, {this.username}
-                </span> : (null)}
+                {this.credentials ?
+                    <>
+                        <img
+                            className={'avatar'}
+                            src={this.credentials.userInfo.picture}
+                        />
+                        <span
+                            className={'welcome'}
+                        >Welcome to Dash, {this.credentials.userInfo.name}
+                        </span>
+                        <div
+                            className={'disconnect'}
+                            onClick={async () => {
+                                await Networking.FetchFromServer("/revokeGoogleAccessToken");
+                                this.resetState(0, 0);
+                            }}
+                        >Disconnect Account</div>
+                    </> : (null)}
             </div>
         );
     }
@@ -125,4 +162,6 @@ export default class GoogleAuthenticationManager extends React.Component<{}> {
         );
     }
 
-}
\ No newline at end of file
+}
+
+Scripting.addGlobal("GoogleAuthenticationManager", GoogleAuthenticationManager);
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 99028f27788740d377fec3504f9370412cd2947d Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 9 May 2020 16:57:23 -0400
Subject: fixed google docs prompt problem.

---
 src/client/apis/GoogleAuthenticationManager.tsx          |  1 -
 .../views/nodes/formattedText/FormattedTextBox.tsx       | 16 +++++++---------
 2 files changed, 7 insertions(+), 10 deletions(-)

(limited to 'src/client/apis/GoogleAuthenticationManager.tsx')

diff --git a/src/client/apis/GoogleAuthenticationManager.tsx b/src/client/apis/GoogleAuthenticationManager.tsx
index 018c980d8..22d6fb582 100644
--- a/src/client/apis/GoogleAuthenticationManager.tsx
+++ b/src/client/apis/GoogleAuthenticationManager.tsx
@@ -36,7 +36,6 @@ export default class GoogleAuthenticationManager extends React.Component<{}> {
 
     public fetchOrGenerateAccessToken = async (displayIfFound = false) => {
         let response: any = 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;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 63552321b..f3c277e20 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -790,15 +790,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     }
 
     checkState = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => {
-        GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken().then(() => {
-            if (exportState && this._editorView) {
-                const equalContent = isEqual(this._editorView.state.doc, exportState.state.doc);
-                const equalTitles = dataDoc.title === exportState.title;
-                const unchanged = equalContent && equalTitles;
-                dataDoc.unchanged = unchanged;
-                DocumentButtonBar.Instance.setPullState(unchanged);
-            }
-        });
+        if (exportState && this._editorView) {
+            const equalContent = isEqual(this._editorView.state.doc, exportState.state.doc);
+            const equalTitles = dataDoc.title === exportState.title;
+            const unchanged = equalContent && equalTitles;
+            dataDoc.unchanged = unchanged;
+            DocumentButtonBar.Instance.setPullState(unchanged);
+        }
     }
 
     clipboardTextSerializer = (slice: Slice): string => {
-- 
cgit v1.2.3-70-g09d2

