mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) add a /welcome/start endpoint that forwards sensibly
Summary: This adds a nuanced redirecting endpoint. For example, on docs.getgrist.com it does: 1) If logged in and no team site -> https://docs.getgrist.com/ 2) If logged in and has team sites -> https://docs.getgrist.com/welcome/teams 3) If logged out but has a cookie -> /login, then 1 or 2 4) If entirely unknown -> /signup Test Plan: added a test; tested behavior through logins manually Reviewers: dsagal Reviewed By: dsagal Subscribers: dsagal Differential Revision: https://phab.getgrist.com/D3828
This commit is contained in:
parent
a9ff6b9a84
commit
12f9567ff4
@ -7,7 +7,7 @@ import {getOrgUrlInfo} from 'app/common/gristUrls';
|
||||
import {UserProfile} from 'app/common/LoginSessionAPI';
|
||||
import {tbind} from 'app/common/tbind';
|
||||
import * as version from 'app/common/version';
|
||||
import {ApiServer} from 'app/gen-server/ApiServer';
|
||||
import {ApiServer, getOrgFromRequest} from 'app/gen-server/ApiServer';
|
||||
import {Document} from "app/gen-server/entity/Document";
|
||||
import {Organization} from "app/gen-server/entity/Organization";
|
||||
import {Workspace} from 'app/gen-server/entity/Workspace';
|
||||
@ -20,8 +20,8 @@ import {Usage} from 'app/gen-server/lib/Usage';
|
||||
import {AccessTokens, IAccessTokens} from 'app/server/lib/AccessTokens';
|
||||
import {attachAppEndpoint} from 'app/server/lib/AppEndpoint';
|
||||
import {appSettings} from 'app/server/lib/AppSettings';
|
||||
import {addRequestUser, getUser, getUserId, isSingleUserMode,
|
||||
redirectToLoginUnconditionally} from 'app/server/lib/Authorizer';
|
||||
import {addRequestUser, getUser, getUserId, isAnonymousUser,
|
||||
isSingleUserMode, redirectToLoginUnconditionally} from 'app/server/lib/Authorizer';
|
||||
import {redirectToLogin, RequestWithLogin, signInStatusMiddleware} from 'app/server/lib/Authorizer';
|
||||
import {forceSessionChange} from 'app/server/lib/BrowserSession';
|
||||
import {Comm} from 'app/server/lib/Comm';
|
||||
@ -963,32 +963,16 @@ export class FlexServer implements GristServer {
|
||||
// should be factored out of it.
|
||||
this.addComm();
|
||||
|
||||
async function redirectToLoginOrSignup(
|
||||
this: FlexServer, signUp: boolean|null, req: express.Request, resp: express.Response,
|
||||
) {
|
||||
const mreq = req as RequestWithLogin;
|
||||
|
||||
// This will ensure that express-session will set our cookie if it hasn't already -
|
||||
// we'll need it when we redirect back.
|
||||
forceSessionChange(mreq.session);
|
||||
// Redirect to the requested URL after successful login.
|
||||
const nextPath = optStringParam(req.query.next);
|
||||
const nextUrl = new URL(getOrgUrl(req, nextPath));
|
||||
if (signUp === null) {
|
||||
// Like redirectToLogin in Authorizer, redirect to sign up if it doesn't look like the
|
||||
// user has ever logged in on this browser.
|
||||
signUp = (mreq.session.users === undefined);
|
||||
}
|
||||
const getRedirectUrl = signUp ? this._getSignUpRedirectUrl : this._getLoginRedirectUrl;
|
||||
resp.redirect(await getRedirectUrl(req, nextUrl));
|
||||
}
|
||||
|
||||
const signinMiddleware = this._loginMiddleware.getLoginOrSignUpMiddleware ?
|
||||
this._loginMiddleware.getLoginOrSignUpMiddleware() :
|
||||
[];
|
||||
this.app.get('/login', ...signinMiddleware, expressWrap(redirectToLoginOrSignup.bind(this, false)));
|
||||
this.app.get('/signup', ...signinMiddleware, expressWrap(redirectToLoginOrSignup.bind(this, true)));
|
||||
this.app.get('/signin', ...signinMiddleware, expressWrap(redirectToLoginOrSignup.bind(this, null)));
|
||||
this.app.get('/login', ...signinMiddleware, expressWrap(this._redirectToLoginOrSignup.bind(this, {
|
||||
signUp: false,
|
||||
})));
|
||||
this.app.get('/signup', ...signinMiddleware, expressWrap(this._redirectToLoginOrSignup.bind(this, {
|
||||
signUp: true,
|
||||
})));
|
||||
this.app.get('/signin', ...signinMiddleware, expressWrap(this._redirectToLoginOrSignup.bind(this, {})));
|
||||
|
||||
if (allowTestLogin()) {
|
||||
// This is an endpoint for the dev environment that lets you log in as anyone.
|
||||
@ -1212,6 +1196,37 @@ export class FlexServer implements GristServer {
|
||||
return this._sendAppPage(req, resp, {path: 'app.html', status: 200, config: {}, googleTagManager: 'anon'});
|
||||
}));
|
||||
|
||||
/**
|
||||
* A nuanced redirecting endpoint. For example, on docs.getgrist.com it does:
|
||||
* 1) If logged in and no team site -> https://docs.getgrist.com/
|
||||
* 2) If logged in and has team sites -> https://docs.getgrist.com/welcome/teams
|
||||
* 3) If logged out but has a cookie -> /login, then 1 or 2
|
||||
* 4) If entirely unknown -> /signup
|
||||
*/
|
||||
this.app.get('/welcome/start', [
|
||||
this._redirectToHostMiddleware,
|
||||
this._userIdMiddleware,
|
||||
], expressWrap(async (req, resp, next) => {
|
||||
if (isAnonymousUser(req)) {
|
||||
return this._redirectToLoginOrSignup({
|
||||
nextUrl: new URL(getOrgUrl(req, '/welcome/start')),
|
||||
}, req, resp);
|
||||
} else {
|
||||
const userId = getUserId(req);
|
||||
const domain = getOrgFromRequest(req);
|
||||
const orgs = this._dbManager.unwrapQueryResult(
|
||||
await this._dbManager.getOrgs(userId, domain, {
|
||||
ignoreEveryoneShares: true,
|
||||
})
|
||||
);
|
||||
if (orgs.length > 1) {
|
||||
resp.redirect(getOrgUrl(req, '/welcome/teams'));
|
||||
} else {
|
||||
resp.redirect(getOrgUrl(req));
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
this.app.post('/welcome/info', ...middleware, expressWrap(async (req, resp, next) => {
|
||||
const userId = getUserId(req);
|
||||
const user = getUser(req);
|
||||
@ -1726,6 +1741,40 @@ export class FlexServer implements GristServer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If signUp is true, redirect to signUp.
|
||||
* If signUp is false, redirect to login.
|
||||
* If signUp is not set, redirect to signUp if no cookie found, else login.
|
||||
*
|
||||
* If nextUrl is not supplied, it will be constructed from a path in
|
||||
* the "next" query parameter.
|
||||
*/
|
||||
private async _redirectToLoginOrSignup(
|
||||
options: {
|
||||
signUp?: boolean, nextUrl?: URL,
|
||||
},
|
||||
req: express.Request, resp: express.Response,
|
||||
) {
|
||||
let {nextUrl, signUp} = options;
|
||||
|
||||
const mreq = req as RequestWithLogin;
|
||||
|
||||
// This will ensure that express-session will set our cookie if it hasn't already -
|
||||
// we'll need it when we redirect back.
|
||||
forceSessionChange(mreq.session);
|
||||
// Redirect to the requested URL after successful login.
|
||||
if (!nextUrl) {
|
||||
const nextPath = optStringParam(req.query.next);
|
||||
nextUrl = new URL(getOrgUrl(req, nextPath));
|
||||
}
|
||||
if (signUp === undefined) {
|
||||
// Like redirectToLogin in Authorizer, redirect to sign up if it doesn't look like the
|
||||
// user has ever logged in on this browser.
|
||||
signUp = (mreq.session.users === undefined);
|
||||
}
|
||||
const getRedirectUrl = signUp ? this._getSignUpRedirectUrl : this._getLoginRedirectUrl;
|
||||
resp.redirect(await getRedirectUrl(req, nextUrl));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,7 +2,7 @@
|
||||
"ACUserManager": {
|
||||
"Enter email address": "Enter e-mail address",
|
||||
"Invite new member": "Invite new member",
|
||||
"We'll email an invite to {{email}}": "An invite will be e-mailed to {{email}}"
|
||||
"We'll email an invite to {{email}}": "We'll email an invite to {{email}}"
|
||||
},
|
||||
"AccessRules": {
|
||||
"Add Column Rule": "Add Column Rule",
|
||||
@ -366,7 +366,7 @@
|
||||
"Hide {{count}} columns_one": "Hide column",
|
||||
"Hide {{count}} columns_other": "Hide {{count}} columns",
|
||||
"Insert column to the {{to}}": "Insert column to the {{to}}",
|
||||
"More sort options ...": "More sorting options…",
|
||||
"More sort options ...": "More sort options…",
|
||||
"Rename column": "Rename column",
|
||||
"Reset {{count}} columns_one": "Reset column",
|
||||
"Reset {{count}} columns_other": "Reset {{count}} columns",
|
||||
@ -534,7 +534,7 @@
|
||||
"Select Widget": "Select Widget",
|
||||
"Series_one": "Series",
|
||||
"Series_other": "Series",
|
||||
"Sort & Filter": "Sort and Filter",
|
||||
"Sort & Filter": "Sort & Filter",
|
||||
"TRANSFORM": "TRANSFORM",
|
||||
"Theme": "Theme",
|
||||
"WIDGET TITLE": "WIDGET TITLE",
|
||||
@ -637,7 +637,7 @@
|
||||
"No Default Access": "No Default Access",
|
||||
"None": "None",
|
||||
"Owner": "Owner",
|
||||
"View & Edit": "View and Edit",
|
||||
"View & Edit": "View & Edit",
|
||||
"View Only": "View Only",
|
||||
"Viewer": "Viewer"
|
||||
},
|
||||
@ -661,7 +661,7 @@
|
||||
"Unmark On-Demand": "Unmark On-Demand"
|
||||
},
|
||||
"ViewLayoutMenu": {
|
||||
"Advanced Sort & Filter": "Advanced Sorting and Filtering",
|
||||
"Advanced Sort & Filter": "Advanced Sort & Filter",
|
||||
"Copy anchor link": "Copy anchor link",
|
||||
"Data selection": "Data selection",
|
||||
"Delete record": "Delete record",
|
||||
|
Loading…
Reference in New Issue
Block a user