mirror of
				https://github.com/gristlabs/grist-core.git
				synced 2025-06-13 20:53:59 +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