Process quota emails in account-portal
This commit is contained in:
parent
46f9f14e3d
commit
af24f72166
|
@ -62,6 +62,7 @@
|
|||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chance": "1.1.3",
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/koa": "2.0.52",
|
||||
"@types/lodash": "4.14.180",
|
||||
|
@ -73,6 +74,7 @@
|
|||
"@types/tar-fs": "2.0.1",
|
||||
"@types/uuid": "8.3.4",
|
||||
"ioredis-mock": "5.8.0",
|
||||
"chance": "1.1.3",
|
||||
"jest": "27.5.1",
|
||||
"koa": "2.7.0",
|
||||
"nodemon": "2.0.16",
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
import { generator, uuid } from "."
|
||||
import { AuthType, CloudAccount, Hosting } from "@budibase/types"
|
||||
import * as db from "../../../src/db/utils"
|
||||
|
||||
export const cloudAccount = (): CloudAccount => {
|
||||
return {
|
||||
accountId: uuid(),
|
||||
createdAt: Date.now(),
|
||||
verified: true,
|
||||
verificationSent: true,
|
||||
tier: "",
|
||||
email: generator.email(),
|
||||
tenantId: generator.word(),
|
||||
hosting: Hosting.CLOUD,
|
||||
authType: AuthType.PASSWORD,
|
||||
password: generator.word(),
|
||||
tenantName: generator.word(),
|
||||
name: generator.name(),
|
||||
size: "10+",
|
||||
profession: "Software Engineer",
|
||||
budibaseUserId: db.generateGlobalUserID(),
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export { v4 as uuid } from "uuid"
|
|
@ -1 +1,8 @@
|
|||
export * from "./common"
|
||||
|
||||
import Chance from "chance"
|
||||
export const generator = new Chance()
|
||||
|
||||
export * as koa from "./koa"
|
||||
export * as accounts from "./accounts"
|
||||
export * as licenses from "./licenses"
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import { AccountPlan, License, PlanType, Quotas } from "@budibase/types"
|
||||
|
||||
const newPlan = (type: PlanType = PlanType.FREE): AccountPlan => {
|
||||
return {
|
||||
type,
|
||||
}
|
||||
}
|
||||
|
||||
export const newLicense = (opts: {
|
||||
quotas: Quotas
|
||||
planType?: PlanType
|
||||
}): License => {
|
||||
return {
|
||||
features: [],
|
||||
quotas: opts.quotas,
|
||||
plan: newPlan(opts.planType),
|
||||
}
|
||||
}
|
|
@ -663,6 +663,11 @@
|
|||
"@types/connect" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/chance@1.1.3":
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/chance/-/chance-1.1.3.tgz#d19fe9391288d60fdccd87632bfc9ab2b4523fea"
|
||||
integrity sha512-X6c6ghhe4/sQh4XzcZWSFaTAUOda38GQHmq9BUanYkOE/EO7ZrkazwKmtsj3xzTjkLWmwULE++23g3d3CCWaWw==
|
||||
|
||||
"@types/connect@*":
|
||||
version "3.4.35"
|
||||
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1"
|
||||
|
@ -1555,6 +1560,11 @@ chalk@^4.0.0, chalk@^4.1.0:
|
|||
ansi-styles "^4.1.0"
|
||||
supports-color "^7.1.0"
|
||||
|
||||
chance@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/chance/-/chance-1.1.3.tgz#414f08634ee479c7a316b569050ea20751b82dd3"
|
||||
integrity sha512-XeJsdoVAzDb1WRPRuMBesRSiWpW1uNTo5Fd7mYxPJsAfgX71+jfuCOHOdbyBz2uAUZ8TwKcXgWk3DMedFfJkbg==
|
||||
|
||||
char-regex@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
|
||||
|
|
|
@ -17,7 +17,6 @@ import {
|
|||
getProdAppDB,
|
||||
getDevAppDB,
|
||||
} from "@budibase/backend-core/context"
|
||||
import { quotas } from "@budibase/pro"
|
||||
import { events } from "@budibase/backend-core"
|
||||
|
||||
// the max time we can wait for an invalidation to complete before considering it failed
|
||||
|
|
|
@ -3,9 +3,3 @@ import { QuotaUsage } from "../../documents"
|
|||
export interface GetLicenseRequest {
|
||||
quotaUsage: QuotaUsage
|
||||
}
|
||||
|
||||
export interface QuotaUsageTriggeredRequest {
|
||||
percentage: number
|
||||
name: string
|
||||
resetDate: string
|
||||
}
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
import { Feature, Hosting, PlanType, Quotas } from "../../sdk"
|
||||
import { QuotaUsage } from "../global"
|
||||
import {
|
||||
Feature,
|
||||
Hosting,
|
||||
MonthlyQuotaName,
|
||||
PlanType,
|
||||
Quotas,
|
||||
StaticQuotaName,
|
||||
} from "../../sdk"
|
||||
import { MonthlyUsage, QuotaUsage, StaticUsage } from "../global"
|
||||
|
||||
export interface CreateAccount {
|
||||
email: string
|
||||
|
@ -43,7 +50,7 @@ export interface Account extends CreateAccount {
|
|||
licenseKey?: string
|
||||
licenseKeyActivatedAt?: number
|
||||
licenseOverrides?: LicenseOverrides
|
||||
quotaUsage?: QuotaUsage
|
||||
quotaUsage?: AccountQuotaUsage
|
||||
}
|
||||
|
||||
export interface PasswordAccount extends Account {
|
||||
|
@ -86,3 +93,26 @@ export interface OAuthTokens {
|
|||
accessToken: string
|
||||
refreshToken: string
|
||||
}
|
||||
|
||||
export type QuotaTriggers = {
|
||||
[key: string]: string | null
|
||||
}
|
||||
|
||||
export interface AccountStaticUsage extends StaticUsage {
|
||||
triggers?: {
|
||||
[key in StaticQuotaName]?: QuotaTriggers
|
||||
}
|
||||
}
|
||||
|
||||
export interface AccountMonthlyUsage extends MonthlyUsage {
|
||||
triggers?: {
|
||||
[key in MonthlyQuotaName]?: QuotaTriggers
|
||||
}
|
||||
}
|
||||
|
||||
export interface AccountQuotaUsage extends QuotaUsage {
|
||||
usageQuota: AccountStaticUsage
|
||||
monthly: {
|
||||
[key: string]: AccountMonthlyUsage
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,14 @@ export interface UsageBreakdown {
|
|||
}
|
||||
}
|
||||
|
||||
export type MonthlyUsage = {
|
||||
export interface StaticUsage {
|
||||
[StaticQuotaName.APPS]: number
|
||||
[StaticQuotaName.PLUGINS]: number
|
||||
[StaticQuotaName.USER_GROUPS]: number
|
||||
[StaticQuotaName.ROWS]: number
|
||||
}
|
||||
|
||||
export interface MonthlyUsage {
|
||||
[MonthlyQuotaName.QUERIES]: number
|
||||
[MonthlyQuotaName.AUTOMATIONS]: number
|
||||
[MonthlyQuotaName.DAY_PASSES]: number
|
||||
|
@ -34,9 +41,7 @@ export type MonthlyUsage = {
|
|||
}
|
||||
|
||||
export interface BaseQuotaUsage {
|
||||
usageQuota: {
|
||||
[key in StaticQuotaName]: number
|
||||
}
|
||||
usageQuota: StaticUsage
|
||||
monthly: {
|
||||
[key: string]: MonthlyUsage
|
||||
}
|
||||
|
|
|
@ -61,26 +61,33 @@ export type PlanQuotas = {
|
|||
[PlanType.ENTERPRISE]: Quotas
|
||||
}
|
||||
|
||||
export type Quotas = {
|
||||
[QuotaType.USAGE]: {
|
||||
[QuotaUsageType.MONTHLY]: {
|
||||
export type MonthlyQuotas = {
|
||||
[MonthlyQuotaName.QUERIES]: Quota
|
||||
[MonthlyQuotaName.AUTOMATIONS]: Quota
|
||||
[MonthlyQuotaName.DAY_PASSES]: Quota
|
||||
}
|
||||
[QuotaUsageType.STATIC]: {
|
||||
}
|
||||
|
||||
export type StaticQuotas = {
|
||||
[StaticQuotaName.ROWS]: Quota
|
||||
[StaticQuotaName.APPS]: Quota
|
||||
[StaticQuotaName.USER_GROUPS]: Quota
|
||||
[StaticQuotaName.PLUGINS]: Quota
|
||||
}
|
||||
}
|
||||
[QuotaType.CONSTANT]: {
|
||||
}
|
||||
|
||||
export type ConstantQuotas = {
|
||||
[ConstantQuotaName.AUTOMATION_LOG_RETENTION_DAYS]: Quota
|
||||
}
|
||||
|
||||
export type Quotas = {
|
||||
[QuotaType.USAGE]: {
|
||||
[QuotaUsageType.MONTHLY]: MonthlyQuotas
|
||||
[QuotaUsageType.STATIC]: StaticQuotas
|
||||
}
|
||||
[QuotaType.CONSTANT]: ConstantQuotas
|
||||
}
|
||||
|
||||
export interface Quota {
|
||||
name: string
|
||||
value: number
|
||||
triggers: number[]
|
||||
}
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
const { StaticDatabases, doWithDB } = require("@budibase/backend-core/db")
|
||||
const { getTenantId } = require("@budibase/backend-core/tenancy")
|
||||
const { deleteTenant } = require("@budibase/backend-core/deprovision")
|
||||
const { quotas } = require("@budibase/pro")
|
||||
|
||||
exports.exists = async ctx => {
|
||||
const tenantId = ctx.request.params
|
||||
ctx.body = {
|
||||
exists: await doWithDB(StaticDatabases.PLATFORM_INFO.name, async db => {
|
||||
let exists = false
|
||||
try {
|
||||
const tenantsDoc = await db.get(
|
||||
StaticDatabases.PLATFORM_INFO.docs.tenants
|
||||
)
|
||||
if (tenantsDoc) {
|
||||
exists = tenantsDoc.tenantIds.indexOf(tenantId) !== -1
|
||||
}
|
||||
} catch (err) {
|
||||
// if error it doesn't exist
|
||||
}
|
||||
return exists
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
exports.fetch = async ctx => {
|
||||
ctx.body = await doWithDB(StaticDatabases.PLATFORM_INFO.name, async db => {
|
||||
let tenants = []
|
||||
try {
|
||||
const tenantsDoc = await db.get(
|
||||
StaticDatabases.PLATFORM_INFO.docs.tenants
|
||||
)
|
||||
if (tenantsDoc) {
|
||||
tenants = tenantsDoc.tenantIds
|
||||
}
|
||||
} catch (err) {
|
||||
// if error it doesn't exist
|
||||
}
|
||||
return tenants
|
||||
})
|
||||
}
|
||||
|
||||
exports.delete = async ctx => {
|
||||
const tenantId = getTenantId()
|
||||
|
||||
if (ctx.params.tenantId !== tenantId) {
|
||||
ctx.throw(403, "Unauthorized")
|
||||
}
|
||||
|
||||
try {
|
||||
await deleteTenant(tenantId)
|
||||
await quotas.bustCache()
|
||||
ctx.status = 204
|
||||
} catch (err) {
|
||||
ctx.log.error(err)
|
||||
throw err
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
const { StaticDatabases, doWithDB } = require("@budibase/backend-core/db")
|
||||
const { getTenantId } = require("@budibase/backend-core/tenancy")
|
||||
const { deleteTenant } = require("@budibase/backend-core/deprovision")
|
||||
import { quotas } from "@budibase/pro"
|
||||
|
||||
export const exists = async (ctx: any) => {
|
||||
const tenantId = ctx.request.params
|
||||
ctx.body = {
|
||||
exists: await doWithDB(
|
||||
StaticDatabases.PLATFORM_INFO.name,
|
||||
async (db: any) => {
|
||||
let exists = false
|
||||
try {
|
||||
const tenantsDoc = await db.get(
|
||||
StaticDatabases.PLATFORM_INFO.docs.tenants
|
||||
)
|
||||
if (tenantsDoc) {
|
||||
exists = tenantsDoc.tenantIds.indexOf(tenantId) !== -1
|
||||
}
|
||||
} catch (err) {
|
||||
// if error it doesn't exist
|
||||
}
|
||||
return exists
|
||||
}
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
export const fetch = async (ctx: any) => {
|
||||
ctx.body = await doWithDB(
|
||||
StaticDatabases.PLATFORM_INFO.name,
|
||||
async (db: any) => {
|
||||
let tenants = []
|
||||
try {
|
||||
const tenantsDoc = await db.get(
|
||||
StaticDatabases.PLATFORM_INFO.docs.tenants
|
||||
)
|
||||
if (tenantsDoc) {
|
||||
tenants = tenantsDoc.tenantIds
|
||||
}
|
||||
} catch (err) {
|
||||
// if error it doesn't exist
|
||||
}
|
||||
return tenants
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const _delete = async (ctx: any) => {
|
||||
const tenantId = getTenantId()
|
||||
|
||||
if (ctx.params.tenantId !== tenantId) {
|
||||
ctx.throw(403, "Unauthorized")
|
||||
}
|
||||
|
||||
try {
|
||||
await deleteTenant(tenantId)
|
||||
await quotas.bustCache()
|
||||
ctx.status = 204
|
||||
} catch (err) {
|
||||
ctx.log.error(err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
export { _delete as delete }
|
|
@ -1,7 +1,6 @@
|
|||
import env from "../../environment"
|
||||
import { events, accounts, tenancy } from "@budibase/backend-core"
|
||||
import { User, UserRoles, CloudAccount } from "@budibase/types"
|
||||
import { users as pro } from "@budibase/pro"
|
||||
|
||||
export const handleDeleteEvents = async (user: any) => {
|
||||
await events.user.deleted(user)
|
||||
|
|
Loading…
Reference in New Issue