New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ability to import Google docs into posts #8756
Conversation
a5f6445
to
1882813
Compare
A question–will it not also overwrite saved changes? |
it takes 1 sec before the button become non-disabled, any chance that could be faster? It's long enough for me to get confused that it's not working: Screen.Recording.2024-02-20.at.13.56.05.mov |
If I delete the text in the input the button doesn't go back to disabled unless I refresh: Screen.Recording.2024-02-20.at.14.00.20.mov |
…/ForumMagnum into wh-google-doc-import-2024-02
This is a bit of a semantic issue that is hard to get across in a short sentence, basically:
So I think the current wording is correct if you take overwrite to mean "delete in a way you can't recover easily"
It's not really possible to make this faster unfortunately without changing how it works. I expect it to be a bit faster on production though (maybe twice as fast, part of the time is looking things up in our database which will be faster, the rest is looking up the doc with google which will be the same). If we did change how it works we could do something like un-disabling the button as soon as it gets a valid url (whether or not we have access to it), but then failing when you click the button if we don't have access (and still showing the message)
Fixed this 👍 |
Comments from Lizka:
Seems good 👍 , I've updated this
Hmm I prefer the original (bc it's fewer words), interested in what @agnesstenlund thinks. I think I'm assuming people will basically have a good understanding of how google doc permissions work so will get the idea without much explanation. Here's a side by side of the two wordings:
Good catch, I've changed it so it doesn't update automatically. Unfortunately this means we now might be at risk of hitting a rate limit, although according to my calculation it should be able to tolerate ~80 users using it concurrently, which should hopefully be way more than we need
Yup this is for admins (and only devs basically), users won't see this |
Agree that the rewrite is too long. Since we say Google doc above I don't think it's necessary + the length of that line makes me slightly more confused about it? |
could do something like "Paste your Google doc link here. It needs to be public or shared with eaforum.posts@gmail.com" if we think we should mention google doc |
Eh 🤷♂️, I think it's hopefully obvious from the placeholder and button text |
const googleClientId = googleClientIdSetting.get(); | ||
const googleOAuthSecret = googleOAuthSecretSetting.get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've set up a dev and prod client in the google cloud console (see here)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I know what you did here, but @Will-Howard, can you elaborate on the kind of credentials you set up?
The part I need to figure out is the consent screen, I think. How did that work for you?
@oetherington btw the error in the console is a (non-serious) bug in the google api library, for which there is a fix that will be merged soon |
I love that when you link to that fix it puts a backlink in the referenced issue. Like, "we're waiting on you bro". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
I left quite a few comments but I don't think anything is necessarily blocking, except maybe admin gating the auth routes (if I'm understanding correctly how those are supposed to work).
const clientIdSetting = new DatabaseServerSetting<string | null>('googleDocImport.oAuth.clientId', null) | ||
const clientSecretSetting = new DatabaseServerSetting<string | null>('googleDocImport.oAuth.secret', null) | ||
|
||
let _oAuthClient: OAuth2Client | null = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think a preceding underscore is the correct naming convention for globals. Generally you'd use OAUTH_CLIENT
or g_oAuthClient
. A preceding underscore has the special meaning of implying that the variable is unused, and making linters ignore it if that's the case.
@@ -398,7 +478,7 @@ export const addAuthMiddlewares = (addConnectHandler: AddMiddlewareType) => { | |||
}); | |||
} | |||
|
|||
addConnectHandler('/auth/google/callback', (req: Request, res: Response, next: NextFunction) => { | |||
addConnectHandler('/auth/google/callback', (req: AnyBecauseTodo, res: AnyBecauseTodo, next: AnyBecauseTodo) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this line is an incorrect merge conflict resolution
return ( | ||
<div className={classes.root}> | ||
<Link to={"/admin/googleServiceAccount"}> | ||
{message} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: indentation
@@ -74,6 +74,7 @@ const AdminHome = ({ classes }: { | |||
<li><Link className={classes.link} to="/admin/synonyms">Search Synonyms</Link></li> | |||
<li><Link className={classes.link} to="/admin/tagMerge">{taggingNameCapitalSetting.get()} Merging Tool</Link></li> | |||
<li><span className={classes.link} onClick={refreshDbSettings}>Refresh DB Settings</span></li> | |||
<li><Link className={classes.link} to="/admin/googleServiceAccount">Google Doc import service account</Link></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the <Loading />
on the line below corresponse to the "Refresh DB Settings" option above, so this probably shouldn't go in between them (it's a bit janky but, hey, it's an admin page).
@@ -209,6 +209,7 @@ | |||
"express-session": "^1.17.1", | |||
"feedparser-promised": "^1.2.2", | |||
"fp-ts": "^2.13.1", | |||
"googleapis": "^133.0.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WRT the error in the package.json for this library, it might be worth making a manual patch (which should be very straight forward). The issue has existed for 6 weeks and the PR to fix it has already been open for 3 weeks, and I have less than 0 faith in Google being competant enough to actually fix it in a timely manner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll give them a couple more weeks, but I'll set a reminder with a deadline so we don't just get stuck with this forever
@@ -20,6 +20,9 @@ import { Request, Response, NextFunction, json } from "express"; | |||
import { AUTH0_SCOPE, loginAuth0User, signupAuth0User } from './authentication/auth0'; | |||
import { IdFromProfile, UserDataFromProfile, getOrCreateForumUser } from './authentication/getOrCreateForumUser'; | |||
import { promisify } from 'util'; | |||
import { OAuth2Client } from 'google-auth-library'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that this file already has multiple oauth clients, maybe this should be OAuth2Client as GoogleOAuth2Client
const callbackUrl = "google_oauth2callback" | ||
const oauth2Client = new OAuth2Client(googleClientId, googleOAuthSecret, `${getSiteUrl()}${callbackUrl}`); | ||
|
||
addConnectHandler('/auth/linkgdrive', (req: Request, res: Response) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these two handlers be admin gated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes they should! Great catch
/** | ||
* Convert the footnotes we get in google doc html to a format ckeditor can understand. This is mirroring the logic | ||
* in the footnotes plugin (see e.g. public/lesswrong-editor/src/ckeditor5-footnote/src/footnoteEditing/googleDocsFootnotesNormalizer.js) | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we put a comment in that JS file as well so if it gets updated those updates are more likely to be copied here too?
return null; | ||
} | ||
|
||
return await canAccessGoogleDoc(fileUrl) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: superfluous async/await
const { html: withRehostedImages } = await convertImagesInHTML(html, postId, url => url.includes("googleusercontent")) | ||
const withConvertedFootnotes = googleDocConvertFootnotes(withRehostedImages) | ||
const withNormalisedRedirects = googleDocRemoveRedirects(withConvertedFootnotes) | ||
const ckEditorMarkup = await dataToCkEditor(withNormalisedRedirects, "html") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of import issues I noticed that probably need to be handled here:
- The document title got imported as normal text at the top of the document, but maybe we should use it to set the post title and remove it from the document body?
- Bold, italics and underline don't work
- Internal links still point to the google doc, maybe we can fix this now or is it still difficult?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The document title got imported as normal text at the top of the document, but maybe we should use it to set the post title and remove it from the document body?
When creating a new post it already sets the actual title of the doc as the title, I guess it will often be repeated in the main body but it doesn't seem that costly for people to remove it manually
Bold, italics and underline don't work
Thanks, will fix. If it's not completely straightforward I might do it as a followup (but still today)
Internal links still point to the google doc, maybe we can fix this now or is it still difficult?
We can fix that now, I will do this one as a followup, probably also today
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I did the bold/italics one, and made a ticket for internal links
Based on these designs. There are a few differences from the designs, some of which are based on this slack thread, and some of which are things I changed (@agnesstenlund I can change them back if you want).
The changes from the thread are:
The additional changes I made:
Summary of the logic
Clicking "Import Google doc" does the following:
eaforum.posts@gmail.com
. I decided to go with a plain gmail account to avoid any risk of exposing CEA files (because you'll be able to download any doc this account has access to), also it's a bit shorterconvertImportedGoogleDoc
) of the html to make it work with ckeditor, this is mostly to replicate things we do on paste in ckeditorScreenshots
Things left to do, that I will aim to do before merging:
convertImportedGoogleDoc
function (which replicates the logic in ckeditor)┆Issue is synchronized with this Asana task by Unito