mirror of
				https://github.com/gristlabs/grist-core.git
				synced 2025-06-13 20:53:59 +00:00 
			
		
		
		
	(core) Removing temporary pro site
Summary: Creating a pro team site after Stripe checkout. Previously a stub site was always created and never removed, even if a user cancels the checkout process, which resulted in multiple 'ghost' sites that can't be removed. Test Plan: Updated and added Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D3985
This commit is contained in:
		
							parent
							
								
									f1a0b61e15
								
							
						
					
					
						commit
						fad421b7c0
					
				@ -229,7 +229,8 @@ export class BillingAPIImpl extends BaseAPI implements BillingAPI {
 | 
			
		||||
      body: JSON.stringify({
 | 
			
		||||
        domain,
 | 
			
		||||
        name,
 | 
			
		||||
        planType: 'team'
 | 
			
		||||
        planType: 'team',
 | 
			
		||||
        next: window.location.href
 | 
			
		||||
      })
 | 
			
		||||
    });
 | 
			
		||||
    return data.checkoutUrl;
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,8 @@ import {Request} from 'express';
 | 
			
		||||
import {ApiError} from 'app/common/ApiError';
 | 
			
		||||
import {FullUser} from 'app/common/LoginSessionAPI';
 | 
			
		||||
import {OrganizationProperties} from 'app/common/UserAPI';
 | 
			
		||||
import {User} from 'app/gen-server/entity/User';
 | 
			
		||||
import {BillingOptions, HomeDBManager, QueryResult, Scope} from 'app/gen-server/lib/HomeDBManager';
 | 
			
		||||
import {getAuthorizedUserId, getUserId, getUserProfiles, RequestWithLogin} from 'app/server/lib/Authorizer';
 | 
			
		||||
import {getSessionUser, linkOrgWithEmail} from 'app/server/lib/BrowserSession';
 | 
			
		||||
import {expressWrap} from 'app/server/lib/expressWrap';
 | 
			
		||||
@ -16,9 +18,6 @@ import log from 'app/server/lib/log';
 | 
			
		||||
import {addPermit, clearSessionCacheIfNeeded, getDocScope, getScope, integerParam,
 | 
			
		||||
        isParameterOn, optStringParam, sendOkReply, sendReply, stringParam} from 'app/server/lib/requestUtils';
 | 
			
		||||
import {IWidgetRepository} from 'app/server/lib/WidgetRepository';
 | 
			
		||||
 | 
			
		||||
import {User} from './entity/User';
 | 
			
		||||
import {HomeDBManager, QueryResult, Scope} from './lib/HomeDBManager';
 | 
			
		||||
import {getCookieDomain} from 'app/server/lib/gristSessions';
 | 
			
		||||
 | 
			
		||||
// exposed for testing purposes
 | 
			
		||||
@ -64,7 +63,7 @@ export function getOrgKey(req: Request): string|number {
 | 
			
		||||
  return orgKey;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Adds an non-personal org with a new billingAccout, with the given name and domain.
 | 
			
		||||
// Adds an non-personal org with a new billingAccount, with the given name and domain.
 | 
			
		||||
// Returns a QueryResult with the orgId on success.
 | 
			
		||||
export function addOrg(
 | 
			
		||||
  dbManager: HomeDBManager,
 | 
			
		||||
@ -72,6 +71,7 @@ export function addOrg(
 | 
			
		||||
  props: Partial<OrganizationProperties>,
 | 
			
		||||
  options?: {
 | 
			
		||||
    planType?: string,
 | 
			
		||||
    billing?: BillingOptions,
 | 
			
		||||
  }
 | 
			
		||||
): Promise<number> {
 | 
			
		||||
  return dbManager.connection.transaction(async manager => {
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,7 @@ import {
 | 
			
		||||
} from "app/common/UserAPI";
 | 
			
		||||
import {AclRule, AclRuleDoc, AclRuleOrg, AclRuleWs} from "app/gen-server/entity/AclRule";
 | 
			
		||||
import {Alias} from "app/gen-server/entity/Alias";
 | 
			
		||||
import {BillingAccount, ExternalBillingOptions} from "app/gen-server/entity/BillingAccount";
 | 
			
		||||
import {BillingAccount} from "app/gen-server/entity/BillingAccount";
 | 
			
		||||
import {BillingAccountManager} from "app/gen-server/entity/BillingAccountManager";
 | 
			
		||||
import {Document} from "app/gen-server/entity/Document";
 | 
			
		||||
import {Group} from "app/gen-server/entity/Group";
 | 
			
		||||
@ -260,6 +260,20 @@ interface CreateWorkspaceOptions {
 | 
			
		||||
  ownerId?: number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Available options for creating a new org with a new billing account.
 | 
			
		||||
 */
 | 
			
		||||
export type BillingOptions = Partial<Pick<BillingAccount,
 | 
			
		||||
  'product' |
 | 
			
		||||
  'stripeCustomerId' |
 | 
			
		||||
  'stripeSubscriptionId' |
 | 
			
		||||
  'stripePlanId' |
 | 
			
		||||
  'externalId' |
 | 
			
		||||
  'externalOptions' |
 | 
			
		||||
  'inGoodStanding' |
 | 
			
		||||
  'status'
 | 
			
		||||
>>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * HomeDBManager handles interaction between the ApiServer and the Home database,
 | 
			
		||||
 * encapsulating the typeorm logic.
 | 
			
		||||
@ -1348,14 +1362,13 @@ export class HomeDBManager extends EventEmitter {
 | 
			
		||||
   *   NOTE: Currently it is always a true - billing account is one to one with org.
 | 
			
		||||
   * @param planType: if set, controls the type of plan used for the org. Only
 | 
			
		||||
   *   meaningful for team sites currently.
 | 
			
		||||
   *
 | 
			
		||||
   * @param billing: if set, controls the billing account settings for the org.
 | 
			
		||||
   */
 | 
			
		||||
  public async addOrg(user: User, props: Partial<OrganizationProperties>,
 | 
			
		||||
                      options: { setUserAsOwner: boolean,
 | 
			
		||||
                                 useNewPlan: boolean,
 | 
			
		||||
                                 planType?: string,
 | 
			
		||||
                                 externalId?: string,
 | 
			
		||||
                                 externalOptions?: ExternalBillingOptions },
 | 
			
		||||
                                 billing?: BillingOptions},
 | 
			
		||||
                      transaction?: EntityManager): Promise<QueryResult<number>> {
 | 
			
		||||
    const notifications: Array<() => void> = [];
 | 
			
		||||
    const name = props.name;
 | 
			
		||||
@ -1405,12 +1418,26 @@ export class HomeDBManager extends EventEmitter {
 | 
			
		||||
        billingAccountManager.user = user;
 | 
			
		||||
        billingAccountManager.billingAccount = billingAccount;
 | 
			
		||||
        billingAccountEntities.push(billingAccountManager);
 | 
			
		||||
        if (options.externalId) {
 | 
			
		||||
          // save will fail if externalId is a duplicate.
 | 
			
		||||
          billingAccount.externalId = options.externalId;
 | 
			
		||||
        }
 | 
			
		||||
        if (options.externalOptions) {
 | 
			
		||||
          billingAccount.externalOptions = options.externalOptions;
 | 
			
		||||
        // Apply billing settings if requested, but not all of them.
 | 
			
		||||
        if (options.billing) {
 | 
			
		||||
          const billing = options.billing;
 | 
			
		||||
          const allowedKeys: Array<keyof BillingOptions> = [
 | 
			
		||||
            'product',
 | 
			
		||||
            'stripeCustomerId',
 | 
			
		||||
            'stripeSubscriptionId',
 | 
			
		||||
            'stripePlanId',
 | 
			
		||||
            // save will fail if externalId is a duplicate.
 | 
			
		||||
            'externalId',
 | 
			
		||||
            'externalOptions',
 | 
			
		||||
            'inGoodStanding',
 | 
			
		||||
            'status'
 | 
			
		||||
          ];
 | 
			
		||||
          Object.keys(billing).forEach(key => {
 | 
			
		||||
            if (!allowedKeys.includes(key as any)) {
 | 
			
		||||
              delete (billing as any)[key];
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
          Object.assign(billingAccount, billing);
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        log.warn("Creating org with shared billing account");
 | 
			
		||||
@ -1421,7 +1448,7 @@ export class HomeDBManager extends EventEmitter {
 | 
			
		||||
          .leftJoinAndSelect('billing_accounts.orgs', 'orgs')
 | 
			
		||||
          .where('orgs.owner_id = :userId', {userId: user.id})
 | 
			
		||||
          .getOne();
 | 
			
		||||
        if (options.externalId && billingAccount?.externalId !== options.externalId) {
 | 
			
		||||
        if (options.billing?.externalId && billingAccount?.externalId !== options.billing?.externalId) {
 | 
			
		||||
          throw new ApiError('Conflicting external identifier', 400);
 | 
			
		||||
        }
 | 
			
		||||
        if (!billingAccount) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user