developer and published apps usage quota migrations
This commit is contained in:
parent
9a9b4019ea
commit
953a5f881c
|
@ -16,11 +16,11 @@
|
|||
easing: easing,
|
||||
})
|
||||
|
||||
$: if (value) $progress = value
|
||||
$: if (value || value === 0) $progress = value
|
||||
</script>
|
||||
|
||||
<div
|
||||
class:spectrum-ProgressBar--indeterminate={!value}
|
||||
class:spectrum-ProgressBar--indeterminate={!value && value !== 0}
|
||||
class:spectrum-ProgressBar--sideLabel={sideLabel}
|
||||
class="spectrum-ProgressBar spectrum-ProgressBar--size{size}"
|
||||
value={$progress}
|
||||
|
@ -37,7 +37,7 @@
|
|||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
{#if value}
|
||||
{#if value || value === 0}
|
||||
<div
|
||||
class="spectrum-FieldLabel spectrum-ProgressBar-percentage spectrum-FieldLabel--size{size}"
|
||||
>
|
||||
|
@ -47,7 +47,7 @@
|
|||
<div class="spectrum-ProgressBar-track">
|
||||
<div
|
||||
class="spectrum-ProgressBar-fill"
|
||||
style={value ? `width: ${$progress}%` : ""}
|
||||
style={value || value === 0 ? `width: ${$progress}%` : ""}
|
||||
/>
|
||||
</div>
|
||||
<div class="spectrum-ProgressBar-label" hidden="" />
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
const { createUserBuildersView } = require("@budibase/backend-core/db")
|
||||
import * as syncDevelopers from "./usageQuotas/syncDevelopers"
|
||||
|
||||
/**
|
||||
* Date:
|
||||
* March 2022
|
||||
*
|
||||
* Description:
|
||||
* Create the builder users view.
|
||||
* Create the builder users view and sync the developer count
|
||||
*/
|
||||
|
||||
export const run = async (db: any) => {
|
||||
await createUserBuildersView(db)
|
||||
await syncDevelopers.run()
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import * as syncPublishedApps from "./usageQuotas/syncPublishedApps"
|
||||
|
||||
/**
|
||||
* Date:
|
||||
* March 2022
|
||||
*
|
||||
* Description:
|
||||
* Sync the published apps count
|
||||
*/
|
||||
|
||||
export const run = async (db: any) => {
|
||||
await syncPublishedApps.run()
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import { getTenantId } from "@budibase/backend-core/tenancy"
|
||||
import { utils } from "@budibase/backend-core"
|
||||
import * as Pro from "@budibase/pro"
|
||||
|
||||
export const run = async () => {
|
||||
// get developer count
|
||||
const developerCount = await utils.getBuildersCount()
|
||||
|
||||
// sync developer count
|
||||
const tenantId = getTenantId()
|
||||
console.log(
|
||||
`[Tenant: ${tenantId}] Syncing developer count: ${developerCount}`
|
||||
)
|
||||
await Pro.Licensing.Quotas.setUsage(
|
||||
developerCount,
|
||||
Pro.StaticQuotaName.DEVELOPERS,
|
||||
Pro.QuotaUsageType.STATIC
|
||||
)
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import { getTenantId } from "@budibase/backend-core/tenancy"
|
||||
import { getAllApps } from "@budibase/backend-core/db"
|
||||
import * as Pro from "@budibase/pro"
|
||||
|
||||
export const run = async () => {
|
||||
// get app count
|
||||
const opts: any = { dev: false }
|
||||
const prodApps = await getAllApps(opts)
|
||||
const prodAppCount = prodApps ? prodApps.length : 0
|
||||
|
||||
// sync app count
|
||||
const tenantId = getTenantId()
|
||||
console.log(
|
||||
`[Tenant: ${tenantId}] Syncing published app count: ${prodAppCount}`
|
||||
)
|
||||
await Pro.Licensing.Quotas.setUsage(
|
||||
prodAppCount,
|
||||
Pro.StaticQuotaName.PUBLISHED_APPS,
|
||||
Pro.QuotaUsageType.STATIC
|
||||
)
|
||||
}
|
|
@ -8,7 +8,8 @@ const {
|
|||
import * as userEmailViewCasing from "./functions/userEmailViewCasing"
|
||||
import * as quota1 from "./functions/quotas1"
|
||||
import * as appUrls from "./functions/appUrls"
|
||||
import * as userBuildersView from "./functions/userBuildersView"
|
||||
import * as developerQuota from "./functions/developerQuota"
|
||||
import * as publishedAppsQuota from "./functions/publishedAppsQuota"
|
||||
|
||||
export interface Migration {
|
||||
type: string
|
||||
|
@ -52,8 +53,13 @@ export const MIGRATIONS: Migration[] = [
|
|||
},
|
||||
{
|
||||
type: MIGRATION_TYPES.GLOBAL,
|
||||
name: "user_builders_view",
|
||||
fn: userBuildersView.run,
|
||||
name: "developer_quota",
|
||||
fn: developerQuota.run,
|
||||
},
|
||||
{
|
||||
type: MIGRATION_TYPES.GLOBAL,
|
||||
name: "published_apps_quota",
|
||||
fn: publishedAppsQuota.run,
|
||||
},
|
||||
]
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
const {
|
||||
getGlobalUserParams,
|
||||
StaticDatabases,
|
||||
generateNewUsageQuotaDoc,
|
||||
} = require("@budibase/backend-core/db")
|
||||
const {
|
||||
hash,
|
||||
|
@ -9,9 +8,9 @@ const {
|
|||
saveUser,
|
||||
platformLogout,
|
||||
} = require("@budibase/backend-core/utils")
|
||||
const { EmailTemplatePurpose } = require("../../../constants")
|
||||
const { checkInviteCode } = require("../../../utilities/redis")
|
||||
const { sendEmail } = require("../../../utilities/email")
|
||||
import { EmailTemplatePurpose } from "../../../constants"
|
||||
import { checkInviteCode } from "../../../utilities/redis"
|
||||
import { sendEmail } from "../../../utilities/email"
|
||||
const { user: userCache } = require("@budibase/backend-core/cache")
|
||||
const { invalidateSessions } = require("@budibase/backend-core/sessions")
|
||||
const accounts = require("@budibase/backend-core/accounts")
|
||||
|
@ -22,36 +21,37 @@ const {
|
|||
doesTenantExist,
|
||||
} = require("@budibase/backend-core/tenancy")
|
||||
const { removeUserFromInfoDB } = require("@budibase/backend-core/deprovision")
|
||||
const env = require("../../../environment")
|
||||
const { syncUserInApps } = require("../../../utilities/appService")
|
||||
import env from "../../../environment"
|
||||
import { syncUserInApps } from "../../../utilities/appService"
|
||||
const { errors } = require("@budibase/backend-core")
|
||||
import * as Pro from "@budibase/pro"
|
||||
|
||||
async function allUsers() {
|
||||
const allUsers = async () => {
|
||||
const db = getGlobalDB()
|
||||
const response = await db.allDocs(
|
||||
getGlobalUserParams(null, {
|
||||
include_docs: true,
|
||||
})
|
||||
)
|
||||
return response.rows.map(row => row.doc)
|
||||
return response.rows.map((row: any) => row.doc)
|
||||
}
|
||||
|
||||
exports.save = async ctx => {
|
||||
export const save = async (ctx: any) => {
|
||||
try {
|
||||
const user = await saveUser(ctx.request.body, getTenantId())
|
||||
// let server know to sync user
|
||||
await syncUserInApps(user._id)
|
||||
ctx.body = user
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
ctx.throw(err.status || 400, err)
|
||||
}
|
||||
}
|
||||
|
||||
const parseBooleanParam = param => {
|
||||
const parseBooleanParam = (param: any) => {
|
||||
return !(param && param === "false")
|
||||
}
|
||||
|
||||
exports.adminUser = async ctx => {
|
||||
export const adminUser = async (ctx: any) => {
|
||||
const { email, password, tenantId } = ctx.request.body
|
||||
|
||||
// account portal sends a pre-hashed password - honour param to prevent double hashing
|
||||
|
@ -81,10 +81,10 @@ exports.adminUser = async ctx => {
|
|||
} catch (err) {
|
||||
// don't worry about errors
|
||||
}
|
||||
await db.put(generateNewUsageQuotaDoc())
|
||||
await db.put(Pro.Licensing.Quotas.generateNewQuotaUsage())
|
||||
}
|
||||
|
||||
if (response.rows.some(row => row.doc.admin)) {
|
||||
if (response.rows.some((row: any) => row.doc.admin)) {
|
||||
ctx.throw(
|
||||
403,
|
||||
"You cannot initialise once an global user has been created."
|
||||
|
@ -106,12 +106,12 @@ exports.adminUser = async ctx => {
|
|||
}
|
||||
try {
|
||||
ctx.body = await saveUser(user, tenantId, hashPassword, requirePassword)
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
ctx.throw(err.status || 400, err)
|
||||
}
|
||||
}
|
||||
|
||||
exports.destroy = async ctx => {
|
||||
export const destroy = async (ctx: any) => {
|
||||
const db = getGlobalDB()
|
||||
const dbUser = await db.get(ctx.params.id)
|
||||
|
||||
|
@ -139,10 +139,10 @@ exports.destroy = async ctx => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.removeAppRole = async ctx => {
|
||||
export const removeAppRole = async (ctx: any) => {
|
||||
const { appId } = ctx.params
|
||||
const db = getGlobalDB()
|
||||
const users = await allUsers(ctx)
|
||||
const users = await allUsers()
|
||||
const bulk = []
|
||||
const cacheInvalidations = []
|
||||
for (let user of users) {
|
||||
|
@ -162,7 +162,7 @@ exports.removeAppRole = async ctx => {
|
|||
/**
|
||||
* Add the attributes that are session based to the current user.
|
||||
*/
|
||||
const addSessionAttributesToUser = ctx => {
|
||||
const addSessionAttributesToUser = (ctx: any) => {
|
||||
ctx.body.account = ctx.user.account
|
||||
ctx.body.license = ctx.user.license
|
||||
ctx.body.budibaseAccess = ctx.user.budibaseAccess
|
||||
|
@ -174,7 +174,7 @@ const addSessionAttributesToUser = ctx => {
|
|||
* Remove the attributes that are session based from the current user,
|
||||
* so that stale values are not written to the db
|
||||
*/
|
||||
const removeSessionAttributesFromUser = ctx => {
|
||||
const removeSessionAttributesFromUser = (ctx: any) => {
|
||||
delete ctx.request.body.csrfToken
|
||||
delete ctx.request.body.account
|
||||
delete ctx.request.body.accountPortalAccess
|
||||
|
@ -182,7 +182,7 @@ const removeSessionAttributesFromUser = ctx => {
|
|||
delete ctx.request.body.license
|
||||
}
|
||||
|
||||
exports.getSelf = async ctx => {
|
||||
export const getSelf = async (ctx: any) => {
|
||||
if (!ctx.user) {
|
||||
ctx.throw(403, "User not logged in")
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ exports.getSelf = async ctx => {
|
|||
addSessionAttributesToUser(ctx)
|
||||
}
|
||||
|
||||
exports.updateSelf = async ctx => {
|
||||
export const updateSelf = async (ctx: any) => {
|
||||
const db = getGlobalDB()
|
||||
const user = await db.get(ctx.user._id)
|
||||
if (ctx.request.body.password) {
|
||||
|
@ -224,8 +224,8 @@ exports.updateSelf = async ctx => {
|
|||
}
|
||||
|
||||
// called internally by app server user fetch
|
||||
exports.fetch = async ctx => {
|
||||
const users = await allUsers(ctx)
|
||||
export const fetch = async (ctx: any) => {
|
||||
const users = await allUsers()
|
||||
// user hashed password shouldn't ever be returned
|
||||
for (let user of users) {
|
||||
if (user) {
|
||||
|
@ -236,7 +236,7 @@ exports.fetch = async ctx => {
|
|||
}
|
||||
|
||||
// called internally by app server user find
|
||||
exports.find = async ctx => {
|
||||
export const find = async (ctx: any) => {
|
||||
const db = getGlobalDB()
|
||||
let user
|
||||
try {
|
||||
|
@ -251,7 +251,7 @@ exports.find = async ctx => {
|
|||
ctx.body = user
|
||||
}
|
||||
|
||||
exports.tenantUserLookup = async ctx => {
|
||||
export const tenantUserLookup = async (ctx: any) => {
|
||||
const id = ctx.params.id
|
||||
const user = await getTenantUser(id)
|
||||
if (user) {
|
||||
|
@ -261,7 +261,7 @@ exports.tenantUserLookup = async ctx => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.invite = async ctx => {
|
||||
export const invite = async (ctx: any) => {
|
||||
let { email, userInfo } = ctx.request.body
|
||||
const existing = await getGlobalUserByEmail(email)
|
||||
if (existing) {
|
||||
|
@ -271,20 +271,21 @@ exports.invite = async ctx => {
|
|||
userInfo = {}
|
||||
}
|
||||
userInfo.tenantId = getTenantId()
|
||||
await sendEmail(email, EmailTemplatePurpose.INVITATION, {
|
||||
const opts: any = {
|
||||
subject: "{{ company }} platform invitation",
|
||||
info: userInfo,
|
||||
})
|
||||
}
|
||||
await sendEmail(email, EmailTemplatePurpose.INVITATION, opts)
|
||||
ctx.body = {
|
||||
message: "Invitation has been sent.",
|
||||
}
|
||||
}
|
||||
|
||||
exports.inviteAccept = async ctx => {
|
||||
export const inviteAccept = async (ctx: any) => {
|
||||
const { inviteCode, password, firstName, lastName } = ctx.request.body
|
||||
try {
|
||||
// info is an extension of the user object that was stored by global
|
||||
const { email, info } = await checkInviteCode(inviteCode)
|
||||
const { email, info }: any = await checkInviteCode(inviteCode)
|
||||
ctx.body = await saveUser(
|
||||
{
|
||||
firstName,
|
||||
|
@ -295,7 +296,7 @@ exports.inviteAccept = async ctx => {
|
|||
},
|
||||
info.tenantId
|
||||
)
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
if (err.code === errors.codes.USAGE_LIMIT_EXCEEDED) {
|
||||
// explicitly re-throw limit exceeded errors
|
||||
ctx.throw(400, err)
|
Loading…
Reference in New Issue