mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +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({
|
body: JSON.stringify({
|
||||||
domain,
|
domain,
|
||||||
name,
|
name,
|
||||||
planType: 'team'
|
planType: 'team',
|
||||||
|
next: window.location.href
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
return data.checkoutUrl;
|
return data.checkoutUrl;
|
||||||
|
@ -7,6 +7,8 @@ import {Request} from 'express';
|
|||||||
import {ApiError} from 'app/common/ApiError';
|
import {ApiError} from 'app/common/ApiError';
|
||||||
import {FullUser} from 'app/common/LoginSessionAPI';
|
import {FullUser} from 'app/common/LoginSessionAPI';
|
||||||
import {OrganizationProperties} from 'app/common/UserAPI';
|
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 {getAuthorizedUserId, getUserId, getUserProfiles, RequestWithLogin} from 'app/server/lib/Authorizer';
|
||||||
import {getSessionUser, linkOrgWithEmail} from 'app/server/lib/BrowserSession';
|
import {getSessionUser, linkOrgWithEmail} from 'app/server/lib/BrowserSession';
|
||||||
import {expressWrap} from 'app/server/lib/expressWrap';
|
import {expressWrap} from 'app/server/lib/expressWrap';
|
||||||
@ -16,9 +18,6 @@ import log from 'app/server/lib/log';
|
|||||||
import {addPermit, clearSessionCacheIfNeeded, getDocScope, getScope, integerParam,
|
import {addPermit, clearSessionCacheIfNeeded, getDocScope, getScope, integerParam,
|
||||||
isParameterOn, optStringParam, sendOkReply, sendReply, stringParam} from 'app/server/lib/requestUtils';
|
isParameterOn, optStringParam, sendOkReply, sendReply, stringParam} from 'app/server/lib/requestUtils';
|
||||||
import {IWidgetRepository} from 'app/server/lib/WidgetRepository';
|
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';
|
import {getCookieDomain} from 'app/server/lib/gristSessions';
|
||||||
|
|
||||||
// exposed for testing purposes
|
// exposed for testing purposes
|
||||||
@ -64,7 +63,7 @@ export function getOrgKey(req: Request): string|number {
|
|||||||
return orgKey;
|
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.
|
// Returns a QueryResult with the orgId on success.
|
||||||
export function addOrg(
|
export function addOrg(
|
||||||
dbManager: HomeDBManager,
|
dbManager: HomeDBManager,
|
||||||
@ -72,6 +71,7 @@ export function addOrg(
|
|||||||
props: Partial<OrganizationProperties>,
|
props: Partial<OrganizationProperties>,
|
||||||
options?: {
|
options?: {
|
||||||
planType?: string,
|
planType?: string,
|
||||||
|
billing?: BillingOptions,
|
||||||
}
|
}
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
return dbManager.connection.transaction(async manager => {
|
return dbManager.connection.transaction(async manager => {
|
||||||
|
@ -27,7 +27,7 @@ import {
|
|||||||
} from "app/common/UserAPI";
|
} from "app/common/UserAPI";
|
||||||
import {AclRule, AclRuleDoc, AclRuleOrg, AclRuleWs} from "app/gen-server/entity/AclRule";
|
import {AclRule, AclRuleDoc, AclRuleOrg, AclRuleWs} from "app/gen-server/entity/AclRule";
|
||||||
import {Alias} from "app/gen-server/entity/Alias";
|
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 {BillingAccountManager} from "app/gen-server/entity/BillingAccountManager";
|
||||||
import {Document} from "app/gen-server/entity/Document";
|
import {Document} from "app/gen-server/entity/Document";
|
||||||
import {Group} from "app/gen-server/entity/Group";
|
import {Group} from "app/gen-server/entity/Group";
|
||||||
@ -260,6 +260,20 @@ interface CreateWorkspaceOptions {
|
|||||||
ownerId?: number
|
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,
|
* HomeDBManager handles interaction between the ApiServer and the Home database,
|
||||||
* encapsulating the typeorm logic.
|
* 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.
|
* 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
|
* @param planType: if set, controls the type of plan used for the org. Only
|
||||||
* meaningful for team sites currently.
|
* 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>,
|
public async addOrg(user: User, props: Partial<OrganizationProperties>,
|
||||||
options: { setUserAsOwner: boolean,
|
options: { setUserAsOwner: boolean,
|
||||||
useNewPlan: boolean,
|
useNewPlan: boolean,
|
||||||
planType?: string,
|
planType?: string,
|
||||||
externalId?: string,
|
billing?: BillingOptions},
|
||||||
externalOptions?: ExternalBillingOptions },
|
|
||||||
transaction?: EntityManager): Promise<QueryResult<number>> {
|
transaction?: EntityManager): Promise<QueryResult<number>> {
|
||||||
const notifications: Array<() => void> = [];
|
const notifications: Array<() => void> = [];
|
||||||
const name = props.name;
|
const name = props.name;
|
||||||
@ -1405,12 +1418,26 @@ export class HomeDBManager extends EventEmitter {
|
|||||||
billingAccountManager.user = user;
|
billingAccountManager.user = user;
|
||||||
billingAccountManager.billingAccount = billingAccount;
|
billingAccountManager.billingAccount = billingAccount;
|
||||||
billingAccountEntities.push(billingAccountManager);
|
billingAccountEntities.push(billingAccountManager);
|
||||||
if (options.externalId) {
|
// 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.
|
// save will fail if externalId is a duplicate.
|
||||||
billingAccount.externalId = options.externalId;
|
'externalId',
|
||||||
|
'externalOptions',
|
||||||
|
'inGoodStanding',
|
||||||
|
'status'
|
||||||
|
];
|
||||||
|
Object.keys(billing).forEach(key => {
|
||||||
|
if (!allowedKeys.includes(key as any)) {
|
||||||
|
delete (billing as any)[key];
|
||||||
}
|
}
|
||||||
if (options.externalOptions) {
|
});
|
||||||
billingAccount.externalOptions = options.externalOptions;
|
Object.assign(billingAccount, billing);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.warn("Creating org with shared billing account");
|
log.warn("Creating org with shared billing account");
|
||||||
@ -1421,7 +1448,7 @@ export class HomeDBManager extends EventEmitter {
|
|||||||
.leftJoinAndSelect('billing_accounts.orgs', 'orgs')
|
.leftJoinAndSelect('billing_accounts.orgs', 'orgs')
|
||||||
.where('orgs.owner_id = :userId', {userId: user.id})
|
.where('orgs.owner_id = :userId', {userId: user.id})
|
||||||
.getOne();
|
.getOne();
|
||||||
if (options.externalId && billingAccount?.externalId !== options.externalId) {
|
if (options.billing?.externalId && billingAccount?.externalId !== options.billing?.externalId) {
|
||||||
throw new ApiError('Conflicting external identifier', 400);
|
throw new ApiError('Conflicting external identifier', 400);
|
||||||
}
|
}
|
||||||
if (!billingAccount) {
|
if (!billingAccount) {
|
||||||
|
Loading…
Reference in New Issue
Block a user