Merge branch 'feature/draft-apps' of https://github.com/Budibase/budibase into feature/draft-apps
This commit is contained in:
commit
ad64d58af4
|
@ -141,6 +141,18 @@ exports.getRoleParams = (roleId = null, otherProps = {}) => {
|
||||||
return getDocParams(DocumentTypes.ROLE, roleId, otherProps)
|
return getDocParams(DocumentTypes.ROLE, roleId, otherProps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a development app ID to a deployed app ID.
|
||||||
|
*/
|
||||||
|
exports.getDeployedAppID = appId => {
|
||||||
|
// if dev, convert it
|
||||||
|
if (appId.startsWith(exports.APP_DEV_PREFIX)) {
|
||||||
|
const id = appId.split(exports.APP_DEV_PREFIX)[1]
|
||||||
|
return `${exports.APP_PREFIX}${id}`
|
||||||
|
}
|
||||||
|
return appId
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lots of different points in the system need to find the full list of apps, this will
|
* Lots of different points in the system need to find the full list of apps, this will
|
||||||
* enumerate the entire CouchDB cluster and get the list of databases (every app).
|
* enumerate the entire CouchDB cluster and get the list of databases (every app).
|
||||||
|
|
|
@ -2,6 +2,7 @@ const fetch = require("node-fetch")
|
||||||
const env = require("../environment")
|
const env = require("../environment")
|
||||||
const { checkSlashesInUrl } = require("./index")
|
const { checkSlashesInUrl } = require("./index")
|
||||||
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
|
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
|
||||||
|
const { getDeployedAppID } = require("@budibase/auth/db")
|
||||||
|
|
||||||
function getAppRole(appId, user) {
|
function getAppRole(appId, user) {
|
||||||
if (!user.roles) {
|
if (!user.roles) {
|
||||||
|
@ -95,6 +96,8 @@ exports.deleteGlobalUser = async (ctx, globalId) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getGlobalUsers = async (ctx, appId = null, globalId = null) => {
|
exports.getGlobalUsers = async (ctx, appId = null, globalId = null) => {
|
||||||
|
// always use the deployed app
|
||||||
|
appId = getDeployedAppID(appId)
|
||||||
const endpoint = globalId
|
const endpoint = globalId
|
||||||
? `/api/admin/users/${globalId}`
|
? `/api/admin/users/${globalId}`
|
||||||
: `/api/admin/users`
|
: `/api/admin/users`
|
||||||
|
@ -119,9 +122,14 @@ exports.saveGlobalUser = async (ctx, appId, body) => {
|
||||||
const globalUser = body._id
|
const globalUser = body._id
|
||||||
? await exports.getGlobalUsers(ctx, appId, body._id)
|
? await exports.getGlobalUsers(ctx, appId, body._id)
|
||||||
: {}
|
: {}
|
||||||
const roles = globalUser.roles || {}
|
const preRoles = globalUser.roles || {}
|
||||||
if (body.roleId) {
|
if (body.roleId) {
|
||||||
roles[appId] = body.roleId
|
preRoles[appId] = body.roleId
|
||||||
|
}
|
||||||
|
// make sure no dev app IDs in roles
|
||||||
|
const roles = {}
|
||||||
|
for (let [appId, roleId] of Object.entries(preRoles)) {
|
||||||
|
roles[getDeployedAppID(appId)] = roleId
|
||||||
}
|
}
|
||||||
const endpoint = `/api/admin/users`
|
const endpoint = `/api/admin/users`
|
||||||
const reqCfg = {
|
const reqCfg = {
|
||||||
|
|
|
@ -1,24 +1,37 @@
|
||||||
const { getAllRoles } = require("@budibase/auth/roles")
|
const { getAllRoles } = require("@budibase/auth/roles")
|
||||||
const { getAllApps } = require("@budibase/auth/db")
|
const { getAllApps, getDeployedAppID, DocumentTypes } = require("@budibase/auth/db")
|
||||||
|
const CouchDB = require("../../../db")
|
||||||
|
|
||||||
exports.fetch = async ctx => {
|
exports.fetch = async ctx => {
|
||||||
// always use the dev apps as they'll be most up to date (true)
|
// always use the dev apps as they'll be most up to date (true)
|
||||||
const apps = await getAllApps(true)
|
const apps = await getAllApps(true)
|
||||||
const promises = []
|
const promises = []
|
||||||
for (let app of apps) {
|
for (let app of apps) {
|
||||||
promises.push(getAllRoles(app._id))
|
// use dev app IDs
|
||||||
|
promises.push(getAllRoles(app.appId))
|
||||||
}
|
}
|
||||||
const roles = await Promise.all(promises)
|
const roles = await Promise.all(promises)
|
||||||
const response = {}
|
const response = {}
|
||||||
for (let app of apps) {
|
for (let app of apps) {
|
||||||
response[app._id] = roles.shift()
|
const deployedAppId = getDeployedAppID(app.appId)
|
||||||
|
response[deployedAppId] = {
|
||||||
|
roles: roles.shift(),
|
||||||
|
name: app.name,
|
||||||
|
version: app.version,
|
||||||
|
url: app.url,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctx.body = response
|
ctx.body = response
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.find = async ctx => {
|
exports.find = async ctx => {
|
||||||
const appId = ctx.params.appId
|
const appId = ctx.params.appId
|
||||||
|
const db = new CouchDB(appId)
|
||||||
|
const app = await db.get(DocumentTypes.APP_METADATA)
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
roles: await getAllRoles(appId),
|
roles: await getAllRoles(appId),
|
||||||
|
name: app.name,
|
||||||
|
version: app.version,
|
||||||
|
url: app.url,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,45 +30,65 @@ const EmailTemplatePurpose = {
|
||||||
CUSTOM: "custom",
|
CUSTOM: "custom",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const InternalTemplateBindings = {
|
||||||
|
PLATFORM_URL: "platformUrl",
|
||||||
|
COMPANY: "company",
|
||||||
|
LOGO_URL: "logoUrl",
|
||||||
|
EMAIL: "email",
|
||||||
|
USER: "user",
|
||||||
|
REQUEST: "request",
|
||||||
|
DOCS_URL: "docsUrl",
|
||||||
|
LOGIN_URL: "loginUrl",
|
||||||
|
CURRENT_YEAR: "currentYear",
|
||||||
|
CURRENT_DATE: "currentDate",
|
||||||
|
BODY: "body",
|
||||||
|
STYLES: "styles",
|
||||||
|
RESET_URL: "resetUrl",
|
||||||
|
RESET_CODE: "resetCode",
|
||||||
|
INVITE_URL: "inviteUrl",
|
||||||
|
INVITE_CODE: "inviteUrl",
|
||||||
|
CONTENTS: "contents",
|
||||||
|
}
|
||||||
|
|
||||||
const TemplateBindings = {
|
const TemplateBindings = {
|
||||||
PLATFORM_URL: {
|
PLATFORM_URL: {
|
||||||
name: "platformUrl",
|
name: InternalTemplateBindings.PLATFORM_URL,
|
||||||
description: "The URL used to access the budibase platform",
|
description: "The URL used to access the budibase platform",
|
||||||
},
|
},
|
||||||
COMPANY: {
|
COMPANY: {
|
||||||
name: "company",
|
name: InternalTemplateBindings.COMPANY,
|
||||||
description: "The name of your organization",
|
description: "The name of your organization",
|
||||||
},
|
},
|
||||||
LOGO_URL: {
|
LOGO_URL: {
|
||||||
name: "logoUrl",
|
name: InternalTemplateBindings.LOGO_URL,
|
||||||
description: "The URL of your organizations logo.",
|
description: "The URL of your organizations logo.",
|
||||||
},
|
},
|
||||||
EMAIL: {
|
EMAIL: {
|
||||||
name: "email",
|
name: InternalTemplateBindings.EMAIL,
|
||||||
description: "The recipients email address.",
|
description: "The recipients email address.",
|
||||||
},
|
},
|
||||||
USER: {
|
USER: {
|
||||||
name: "user",
|
name: InternalTemplateBindings.USER,
|
||||||
description: "The recipients user object.",
|
description: "The recipients user object.",
|
||||||
},
|
},
|
||||||
REQUEST: {
|
REQUEST: {
|
||||||
name: "request",
|
name: InternalTemplateBindings.REQUEST,
|
||||||
description: "Additional request metadata.",
|
description: "Additional request metadata.",
|
||||||
},
|
},
|
||||||
DOCS_URL: {
|
DOCS_URL: {
|
||||||
name: "docsUrl",
|
name: InternalTemplateBindings.DOCS_URL,
|
||||||
description: "Organization documentation URL.",
|
description: "Organization documentation URL.",
|
||||||
},
|
},
|
||||||
LOGIN_URL: {
|
LOGIN_URL: {
|
||||||
name: "loginUrl",
|
name: InternalTemplateBindings.LOGIN_URL,
|
||||||
description: "The URL used to log into the organization budibase instance.",
|
description: "The URL used to log into the organization budibase instance.",
|
||||||
},
|
},
|
||||||
CURRENT_YEAR: {
|
CURRENT_YEAR: {
|
||||||
name: "currentYear",
|
name: InternalTemplateBindings.CURRENT_YEAR,
|
||||||
description: "The current year.",
|
description: "The current year.",
|
||||||
},
|
},
|
||||||
CURRENT_DATE: {
|
CURRENT_DATE: {
|
||||||
name: "currentDate",
|
name: InternalTemplateBindings.CURRENT_DATE,
|
||||||
description: "The current date.",
|
description: "The current date.",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -80,11 +100,11 @@ const TemplateMetadata = {
|
||||||
purpose: EmailTemplatePurpose.BASE,
|
purpose: EmailTemplatePurpose.BASE,
|
||||||
bindings: [
|
bindings: [
|
||||||
{
|
{
|
||||||
name: "body",
|
name: InternalTemplateBindings.BODY,
|
||||||
description: "The main body of another email template.",
|
description: "The main body of another email template.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "styles",
|
name: InternalTemplateBindings.STYLES,
|
||||||
description: "The contents of the Styling email template.",
|
description: "The contents of the Styling email template.",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -94,12 +114,12 @@ const TemplateMetadata = {
|
||||||
purpose: EmailTemplatePurpose.PASSWORD_RECOVERY,
|
purpose: EmailTemplatePurpose.PASSWORD_RECOVERY,
|
||||||
bindings: [
|
bindings: [
|
||||||
{
|
{
|
||||||
name: "resetUrl",
|
name: InternalTemplateBindings.RESET_URL,
|
||||||
description:
|
description:
|
||||||
"The URL the recipient must click to reset their password.",
|
"The URL the recipient must click to reset their password.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "resetCode",
|
name: InternalTemplateBindings.RESET_CODE,
|
||||||
description:
|
description:
|
||||||
"The temporary password reset code used in the recipients password reset URL.",
|
"The temporary password reset code used in the recipients password reset URL.",
|
||||||
},
|
},
|
||||||
|
@ -110,12 +130,12 @@ const TemplateMetadata = {
|
||||||
purpose: EmailTemplatePurpose.INVITATION,
|
purpose: EmailTemplatePurpose.INVITATION,
|
||||||
bindings: [
|
bindings: [
|
||||||
{
|
{
|
||||||
name: "inviteUrl",
|
name: InternalTemplateBindings.INVITE_URL,
|
||||||
description:
|
description:
|
||||||
"The URL the recipient must click to accept the invitation and activate their account.",
|
"The URL the recipient must click to accept the invitation and activate their account.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "inviteCode",
|
name: InternalTemplateBindings.INVITE_CODE,
|
||||||
description:
|
description:
|
||||||
"The temporary invite code used in the recipients invitation URL.",
|
"The temporary invite code used in the recipients invitation URL.",
|
||||||
},
|
},
|
||||||
|
@ -126,7 +146,7 @@ const TemplateMetadata = {
|
||||||
purpose: EmailTemplatePurpose.CUSTOM,
|
purpose: EmailTemplatePurpose.CUSTOM,
|
||||||
bindings: [
|
bindings: [
|
||||||
{
|
{
|
||||||
name: "contents",
|
name: InternalTemplateBindings.CONTENTS,
|
||||||
description: "Custom content body.",
|
description: "Custom content body.",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -142,4 +162,5 @@ exports.TemplateTypes = TemplateTypes
|
||||||
exports.EmailTemplatePurpose = EmailTemplatePurpose
|
exports.EmailTemplatePurpose = EmailTemplatePurpose
|
||||||
exports.TemplateMetadata = TemplateMetadata
|
exports.TemplateMetadata = TemplateMetadata
|
||||||
exports.TemplateBindings = TemplateBindings
|
exports.TemplateBindings = TemplateBindings
|
||||||
|
exports.InternalTemplateBindings = InternalTemplateBindings
|
||||||
exports.GLOBAL_OWNER = "global"
|
exports.GLOBAL_OWNER = "global"
|
||||||
|
|
|
@ -2,7 +2,7 @@ const CouchDB = require("../db")
|
||||||
const { getScopedConfig, StaticDatabases } = require("@budibase/auth").db
|
const { getScopedConfig, StaticDatabases } = require("@budibase/auth").db
|
||||||
const {
|
const {
|
||||||
Configs,
|
Configs,
|
||||||
TemplateBindings,
|
InternalTemplateBindings,
|
||||||
LOGO_URL,
|
LOGO_URL,
|
||||||
EmailTemplatePurpose,
|
EmailTemplatePurpose,
|
||||||
} = require("../constants")
|
} = require("../constants")
|
||||||
|
@ -21,27 +21,27 @@ exports.getSettingsTemplateContext = async (purpose, code = null) => {
|
||||||
}
|
}
|
||||||
const URL = settings.platformUrl
|
const URL = settings.platformUrl
|
||||||
const context = {
|
const context = {
|
||||||
[TemplateBindings.LOGO_URL]:
|
[InternalTemplateBindings.LOGO_URL]:
|
||||||
checkSlashesInUrl(`${URL}/${settings.logoUrl}`) || LOGO_URL,
|
checkSlashesInUrl(`${URL}/${settings.logoUrl}`) || LOGO_URL,
|
||||||
[TemplateBindings.PLATFORM_URL]: URL,
|
[InternalTemplateBindings.PLATFORM_URL]: URL,
|
||||||
[TemplateBindings.COMPANY]: settings.company || BASE_COMPANY,
|
[InternalTemplateBindings.COMPANY]: settings.company || BASE_COMPANY,
|
||||||
[TemplateBindings.DOCS_URL]:
|
[InternalTemplateBindings.DOCS_URL]:
|
||||||
settings.docsUrl || "https://docs.budibase.com/",
|
settings.docsUrl || "https://docs.budibase.com/",
|
||||||
[TemplateBindings.LOGIN_URL]: checkSlashesInUrl(`${URL}/login`),
|
[InternalTemplateBindings.LOGIN_URL]: checkSlashesInUrl(`${URL}/login`),
|
||||||
[TemplateBindings.CURRENT_DATE]: new Date().toISOString(),
|
[InternalTemplateBindings.CURRENT_DATE]: new Date().toISOString(),
|
||||||
[TemplateBindings.CURRENT_YEAR]: new Date().getFullYear(),
|
[InternalTemplateBindings.CURRENT_YEAR]: new Date().getFullYear(),
|
||||||
}
|
}
|
||||||
// attach purpose specific context
|
// attach purpose specific context
|
||||||
switch (purpose) {
|
switch (purpose) {
|
||||||
case EmailTemplatePurpose.PASSWORD_RECOVERY:
|
case EmailTemplatePurpose.PASSWORD_RECOVERY:
|
||||||
context[TemplateBindings.RESET_CODE] = code
|
context[InternalTemplateBindings.RESET_CODE] = code
|
||||||
context[TemplateBindings.RESET_URL] = checkSlashesInUrl(
|
context[InternalTemplateBindings.RESET_URL] = checkSlashesInUrl(
|
||||||
`${URL}/reset?code=${code}`
|
`${URL}/reset?code=${code}`
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
case EmailTemplatePurpose.INVITATION:
|
case EmailTemplatePurpose.INVITATION:
|
||||||
context[TemplateBindings.INVITE_CODE] = code
|
context[InternalTemplateBindings.INVITE_CODE] = code
|
||||||
context[TemplateBindings.INVITE_URL] = checkSlashesInUrl(
|
context[InternalTemplateBindings.INVITE_URL] = checkSlashesInUrl(
|
||||||
`${URL}/invite?code=${code}`
|
`${URL}/invite?code=${code}`
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
|
Loading…
Reference in New Issue