Remove server -> worker request to retrieve apps, remove hosting endpoints and store
This commit is contained in:
parent
7b19251b8d
commit
08bd447b51
|
@ -1,6 +1,5 @@
|
||||||
import { getFrontendStore } from "./store/frontend"
|
import { getFrontendStore } from "./store/frontend"
|
||||||
import { getAutomationStore } from "./store/automation"
|
import { getAutomationStore } from "./store/automation"
|
||||||
import { getHostingStore } from "./store/hosting"
|
|
||||||
import { getThemeStore } from "./store/theme"
|
import { getThemeStore } from "./store/theme"
|
||||||
import { derived, writable } from "svelte/store"
|
import { derived, writable } from "svelte/store"
|
||||||
import { FrontendTypes, LAYOUT_NAMES } from "../constants"
|
import { FrontendTypes, LAYOUT_NAMES } from "../constants"
|
||||||
|
@ -9,7 +8,6 @@ import { findComponent } from "./componentUtils"
|
||||||
export const store = getFrontendStore()
|
export const store = getFrontendStore()
|
||||||
export const automationStore = getAutomationStore()
|
export const automationStore = getAutomationStore()
|
||||||
export const themeStore = getThemeStore()
|
export const themeStore = getThemeStore()
|
||||||
export const hostingStore = getHostingStore()
|
|
||||||
|
|
||||||
export const currentAsset = derived(store, $store => {
|
export const currentAsset = derived(store, $store => {
|
||||||
const type = $store.currentFrontEndType
|
const type = $store.currentFrontEndType
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { get, writable } from "svelte/store"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import {
|
import {
|
||||||
allScreens,
|
allScreens,
|
||||||
hostingStore,
|
|
||||||
currentAsset,
|
currentAsset,
|
||||||
mainLayout,
|
mainLayout,
|
||||||
selectedComponent,
|
selectedComponent,
|
||||||
|
@ -100,7 +99,6 @@ export const getFrontendStore = () => {
|
||||||
version: application.version,
|
version: application.version,
|
||||||
revertableVersion: application.revertableVersion,
|
revertableVersion: application.revertableVersion,
|
||||||
}))
|
}))
|
||||||
await hostingStore.actions.fetch()
|
|
||||||
|
|
||||||
// Initialise backend stores
|
// Initialise backend stores
|
||||||
const [_integrations] = await Promise.all([
|
const [_integrations] = await Promise.all([
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
import { writable } from "svelte/store"
|
|
||||||
import api, { get } from "../api"
|
|
||||||
|
|
||||||
const INITIAL_HOSTING_UI_STATE = {
|
|
||||||
appUrl: "",
|
|
||||||
deployedApps: {},
|
|
||||||
deployedAppNames: [],
|
|
||||||
deployedAppUrls: [],
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getHostingStore = () => {
|
|
||||||
const store = writable({ ...INITIAL_HOSTING_UI_STATE })
|
|
||||||
store.actions = {
|
|
||||||
fetch: async () => {
|
|
||||||
const response = await api.get("/api/hosting/urls")
|
|
||||||
const urls = await response.json()
|
|
||||||
store.update(state => {
|
|
||||||
state.appUrl = urls.app
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
},
|
|
||||||
fetchDeployedApps: async () => {
|
|
||||||
let deployments = await (await get("/api/hosting/apps")).json()
|
|
||||||
store.update(state => {
|
|
||||||
state.deployedApps = deployments
|
|
||||||
state.deployedAppNames = Object.values(deployments).map(app => app.name)
|
|
||||||
state.deployedAppUrls = Object.values(deployments).map(app => app.url)
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
return deployments
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return store
|
|
||||||
}
|
|
|
@ -6,7 +6,7 @@
|
||||||
import api from "builderStore/api"
|
import api from "builderStore/api"
|
||||||
import { notifications } from "@budibase/bbui"
|
import { notifications } from "@budibase/bbui"
|
||||||
import CreateWebhookDeploymentModal from "./CreateWebhookDeploymentModal.svelte"
|
import CreateWebhookDeploymentModal from "./CreateWebhookDeploymentModal.svelte"
|
||||||
import { store, hostingStore } from "builderStore"
|
import { store } from "builderStore"
|
||||||
|
|
||||||
const DeploymentStatus = {
|
const DeploymentStatus = {
|
||||||
SUCCESS: "SUCCESS",
|
SUCCESS: "SUCCESS",
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
let poll
|
let poll
|
||||||
let deployments = []
|
let deployments = []
|
||||||
let urlComponent = $store.url || `/${appId}`
|
let urlComponent = $store.url || `/${appId}`
|
||||||
let deploymentUrl = `${$hostingStore.appUrl}${urlComponent}`
|
let deploymentUrl = `${urlComponent}`
|
||||||
|
|
||||||
const formatDate = (date, format) =>
|
const formatDate = (date, format) =>
|
||||||
Intl.DateTimeFormat("en-GB", DATE_OPTIONS[format]).format(date)
|
Intl.DateTimeFormat("en-GB", DATE_OPTIONS[format]).format(date)
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import { writable, get as svelteGet } from "svelte/store"
|
import { writable, get as svelteGet } from "svelte/store"
|
||||||
|
|
||||||
import { notifications, Input, ModalContent, Dropzone } from "@budibase/bbui"
|
import { notifications, Input, ModalContent, Dropzone } from "@budibase/bbui"
|
||||||
import { store, automationStore, hostingStore } from "builderStore"
|
import { store, automationStore } from "builderStore"
|
||||||
import { admin, auth } from "stores/portal"
|
import { apps, admin, auth } from "stores/portal"
|
||||||
import api, { get, post } from "builderStore/api"
|
import api, { get, post } from "builderStore/api"
|
||||||
import analytics, { Events } from "analytics"
|
import analytics, { Events } from "analytics"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
|
@ -22,10 +21,9 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
const setupValidation = async () => {
|
const setupValidation = async () => {
|
||||||
await hostingStore.actions.fetchDeployedApps()
|
const applications = svelteGet(apps)
|
||||||
const apps = svelteGet(hostingStore).deployedApps
|
appValidation.name(validation, { apps: applications })
|
||||||
appValidation.name(validation, { apps })
|
appValidation.url(validation, { apps: applications })
|
||||||
appValidation.url(validation, { apps })
|
|
||||||
appValidation.file(validation, { template })
|
appValidation.file(validation, { template })
|
||||||
// init validation
|
// init validation
|
||||||
validation.check($values)
|
validation.check($values)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { writable, get as svelteGet } from "svelte/store"
|
import { writable, get as svelteGet } from "svelte/store"
|
||||||
import { notifications, Input, ModalContent, Body } from "@budibase/bbui"
|
import { notifications, Input, ModalContent, Body } from "@budibase/bbui"
|
||||||
import { hostingStore } from "builderStore"
|
|
||||||
import { apps } from "stores/portal"
|
import { apps } from "stores/portal"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { createValidationStore } from "helpers/validation/yup"
|
import { createValidationStore } from "helpers/validation/yup"
|
||||||
|
@ -20,10 +19,9 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
const setupValidation = async () => {
|
const setupValidation = async () => {
|
||||||
await hostingStore.actions.fetchDeployedApps()
|
const applications = svelteGet(apps)
|
||||||
const apps = svelteGet(hostingStore).deployedApps
|
appValidation.name(validation, { apps: applications, currentApp: app })
|
||||||
appValidation.name(validation, { apps, currentApp: app })
|
appValidation.url(validation, { apps: applications, currentApp: app })
|
||||||
appValidation.url(validation, { apps, currentApp: app })
|
|
||||||
// init validation
|
// init validation
|
||||||
validation.check($values)
|
validation.check($values)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,10 @@ import { string, mixed } from "yup"
|
||||||
import { APP_NAME_REGEX, APP_URL_REGEX } from "constants"
|
import { APP_NAME_REGEX, APP_URL_REGEX } from "constants"
|
||||||
|
|
||||||
export const name = (validation, { apps, currentApp } = { apps: [] }) => {
|
export const name = (validation, { apps, currentApp } = { apps: [] }) => {
|
||||||
let existingApps = Object.values(apps)
|
|
||||||
validation.addValidator(
|
validation.addValidator(
|
||||||
"name",
|
"name",
|
||||||
string()
|
string()
|
||||||
|
.trim()
|
||||||
.required("Your application must have a name")
|
.required("Your application must have a name")
|
||||||
.matches(APP_NAME_REGEX, "App name must be letters and numbers only")
|
.matches(APP_NAME_REGEX, "App name must be letters and numbers only")
|
||||||
.test(
|
.test(
|
||||||
|
@ -18,12 +18,9 @@ export const name = (validation, { apps, currentApp } = { apps: [] }) => {
|
||||||
}
|
}
|
||||||
if (currentApp) {
|
if (currentApp) {
|
||||||
// filter out the current app if present
|
// filter out the current app if present
|
||||||
existingApps = existingApps
|
apps = apps.filter(app => app.appId !== currentApp.appId)
|
||||||
// match the id format of the current app (remove 'app_')
|
|
||||||
.map(app => ({ ...app, appId: app.appId.substring(4) }))
|
|
||||||
.filter(app => app.appId !== currentApp.appId)
|
|
||||||
}
|
}
|
||||||
return !existingApps
|
return !apps
|
||||||
.map(app => app.name)
|
.map(app => app.name)
|
||||||
.some(appName => appName.toLowerCase() === value.toLowerCase())
|
.some(appName => appName.toLowerCase() === value.toLowerCase())
|
||||||
}
|
}
|
||||||
|
@ -31,8 +28,7 @@ export const name = (validation, { apps, currentApp } = { apps: [] }) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const url = (validation, { apps, currentApp } = { apps: {} }) => {
|
export const url = (validation, { apps, currentApp } = { apps: [] }) => {
|
||||||
let existingApps = Object.values(apps)
|
|
||||||
validation.addValidator(
|
validation.addValidator(
|
||||||
"url",
|
"url",
|
||||||
string()
|
string()
|
||||||
|
@ -47,13 +43,10 @@ export const url = (validation, { apps, currentApp } = { apps: {} }) => {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (currentApp) {
|
if (currentApp) {
|
||||||
existingApps = existingApps
|
|
||||||
// match the id format of the current app (remove 'app_')
|
|
||||||
.map(app => ({ ...app, appId: app.appId.substring(4) }))
|
|
||||||
// filter out the current app if present
|
// filter out the current app if present
|
||||||
.filter(app => app.appId !== currentApp.appId)
|
apps = apps.filter(app => app.appId !== currentApp.appId)
|
||||||
}
|
}
|
||||||
return !existingApps
|
return !apps
|
||||||
.map(app => app.url)
|
.map(app => app.url)
|
||||||
.some(appUrl => appUrl.toLowerCase() === value.toLowerCase())
|
.some(appUrl => appUrl.toLowerCase() === value.toLowerCase())
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,7 @@ const {
|
||||||
Replication,
|
Replication,
|
||||||
} = require("@budibase/backend-core/db")
|
} = require("@budibase/backend-core/db")
|
||||||
const { USERS_TABLE_SCHEMA } = require("../../constants")
|
const { USERS_TABLE_SCHEMA } = require("../../constants")
|
||||||
const {
|
const { removeAppFromUserRoles } = require("../../utilities/workerRequests")
|
||||||
getDeployedApps,
|
|
||||||
removeAppFromUserRoles,
|
|
||||||
} = require("../../utilities/workerRequests")
|
|
||||||
const { clientLibraryPath, stringToReadStream } = require("../../utilities")
|
const { clientLibraryPath, stringToReadStream } = require("../../utilities")
|
||||||
const { getAllLocks } = require("../../utilities/redis")
|
const { getAllLocks } = require("../../utilities/redis")
|
||||||
const {
|
const {
|
||||||
|
@ -78,28 +75,43 @@ function getUserRoleId(ctx) {
|
||||||
: ctx.user.role._id
|
: ctx.user.role._id
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAppUrlIfNotInUse(ctx) {
|
async function getAppUrl(ctx) {
|
||||||
|
// construct the url
|
||||||
let url
|
let url
|
||||||
if (ctx.request.body.url) {
|
if (ctx.request.body.url) {
|
||||||
|
// if the url is provided, use that
|
||||||
url = encodeURI(ctx.request.body.url)
|
url = encodeURI(ctx.request.body.url)
|
||||||
} else if (ctx.request.body.name) {
|
} else {
|
||||||
|
// otherwise use the name
|
||||||
url = encodeURI(`${ctx.request.body.name}`)
|
url = encodeURI(`${ctx.request.body.name}`)
|
||||||
}
|
}
|
||||||
if (url) {
|
|
||||||
url = `/${url.replace(URL_REGEX_SLASH, "")}`.toLowerCase()
|
url = `/${url.replace(URL_REGEX_SLASH, "")}`.toLowerCase()
|
||||||
}
|
|
||||||
const deployedApps = await getDeployedApps()
|
|
||||||
if (
|
|
||||||
url &&
|
|
||||||
deployedApps[url] != null &&
|
|
||||||
ctx.params != null &&
|
|
||||||
deployedApps[url].appId !== ctx.params.appId
|
|
||||||
) {
|
|
||||||
ctx.throw(400, "App name/URL is already in use.")
|
|
||||||
}
|
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const checkAppUrl = (ctx, apps, url, currentAppId) => {
|
||||||
|
if (currentAppId) {
|
||||||
|
apps = apps.filter(app => app.appId !== currentAppId)
|
||||||
|
}
|
||||||
|
if (apps.some(app => app.url === url)) {
|
||||||
|
ctx.throw(400, "App URL is already in use.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkAppName = (ctx, apps, name, currentAppId) => {
|
||||||
|
// TODO: Replace with Joi
|
||||||
|
if (!name) {
|
||||||
|
ctx.throw(400, "Name is required")
|
||||||
|
}
|
||||||
|
if (currentAppId) {
|
||||||
|
apps = apps.filter(app => app.appId !== currentAppId)
|
||||||
|
}
|
||||||
|
if (apps.some(app => app.name === name)) {
|
||||||
|
ctx.throw(400, "App name is already in use.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function createInstance(template) {
|
async function createInstance(template) {
|
||||||
const tenantId = isMultiTenant() ? getTenantId() : null
|
const tenantId = isMultiTenant() ? getTenantId() : null
|
||||||
const baseAppId = generateAppID(tenantId)
|
const baseAppId = generateAppID(tenantId)
|
||||||
|
@ -203,6 +215,12 @@ exports.fetchAppPackage = async ctx => {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.create = async ctx => {
|
exports.create = async ctx => {
|
||||||
|
const apps = await getAllApps(CouchDB, { dev: true })
|
||||||
|
const name = ctx.request.body.name
|
||||||
|
checkAppName(ctx, apps, name)
|
||||||
|
const url = await getAppUrl(ctx)
|
||||||
|
checkAppUrl(ctx, apps, url)
|
||||||
|
|
||||||
const { useTemplate, templateKey, templateString } = ctx.request.body
|
const { useTemplate, templateKey, templateString } = ctx.request.body
|
||||||
const instanceConfig = {
|
const instanceConfig = {
|
||||||
useTemplate,
|
useTemplate,
|
||||||
|
@ -215,7 +233,6 @@ exports.create = async ctx => {
|
||||||
const instance = await createInstance(instanceConfig)
|
const instance = await createInstance(instanceConfig)
|
||||||
const appId = instance._id
|
const appId = instance._id
|
||||||
|
|
||||||
const url = await getAppUrlIfNotInUse(ctx)
|
|
||||||
const db = new CouchDB(appId)
|
const db = new CouchDB(appId)
|
||||||
let _rev
|
let _rev
|
||||||
try {
|
try {
|
||||||
|
@ -232,7 +249,7 @@ exports.create = async ctx => {
|
||||||
type: "app",
|
type: "app",
|
||||||
version: packageJson.version,
|
version: packageJson.version,
|
||||||
componentLibraries: ["@budibase/standard-components"],
|
componentLibraries: ["@budibase/standard-components"],
|
||||||
name: ctx.request.body.name,
|
name: name,
|
||||||
url: url,
|
url: url,
|
||||||
template: ctx.request.body.template,
|
template: ctx.request.body.template,
|
||||||
instance: instance,
|
instance: instance,
|
||||||
|
@ -260,7 +277,15 @@ exports.create = async ctx => {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.update = async ctx => {
|
exports.update = async ctx => {
|
||||||
const data = await updateAppPackage(ctx, ctx.request.body, ctx.params.appId)
|
const apps = await getAllApps(CouchDB, { dev: true })
|
||||||
|
// validation
|
||||||
|
const name = ctx.request.body.name
|
||||||
|
checkAppName(ctx, apps, name, ctx.params.appId)
|
||||||
|
const url = await getAppUrl(ctx)
|
||||||
|
checkAppUrl(ctx, apps, url, ctx.params.appId)
|
||||||
|
|
||||||
|
const appPackageUpdates = { name, url }
|
||||||
|
const data = await updateAppPackage(appPackageUpdates, ctx.params.appId)
|
||||||
ctx.status = 200
|
ctx.status = 200
|
||||||
ctx.body = data
|
ctx.body = data
|
||||||
}
|
}
|
||||||
|
@ -282,7 +307,7 @@ exports.updateClient = async ctx => {
|
||||||
version: packageJson.version,
|
version: packageJson.version,
|
||||||
revertableVersion: currentVersion,
|
revertableVersion: currentVersion,
|
||||||
}
|
}
|
||||||
const data = await updateAppPackage(ctx, appPackageUpdates, ctx.params.appId)
|
const data = await updateAppPackage(appPackageUpdates, ctx.params.appId)
|
||||||
ctx.status = 200
|
ctx.status = 200
|
||||||
ctx.body = data
|
ctx.body = data
|
||||||
}
|
}
|
||||||
|
@ -305,7 +330,7 @@ exports.revertClient = async ctx => {
|
||||||
version: application.revertableVersion,
|
version: application.revertableVersion,
|
||||||
revertableVersion: null,
|
revertableVersion: null,
|
||||||
}
|
}
|
||||||
const data = await updateAppPackage(ctx, appPackageUpdates, ctx.params.appId)
|
const data = await updateAppPackage(appPackageUpdates, ctx.params.appId)
|
||||||
ctx.status = 200
|
ctx.status = 200
|
||||||
ctx.body = data
|
ctx.body = data
|
||||||
}
|
}
|
||||||
|
@ -378,12 +403,11 @@ exports.sync = async (ctx, next) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateAppPackage = async (ctx, appPackage, appId) => {
|
const updateAppPackage = async (appPackage, appId) => {
|
||||||
const url = await getAppUrlIfNotInUse(ctx)
|
|
||||||
const db = new CouchDB(appId)
|
const db = new CouchDB(appId)
|
||||||
const application = await db.get(DocumentTypes.APP_METADATA)
|
const application = await db.get(DocumentTypes.APP_METADATA)
|
||||||
|
|
||||||
const newAppPackage = { ...application, ...appPackage, url }
|
const newAppPackage = { ...application, ...appPackage }
|
||||||
if (appPackage._rev !== application._rev) {
|
if (appPackage._rev !== application._rev) {
|
||||||
newAppPackage._rev = application._rev
|
newAppPackage._rev = application._rev
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
const CouchDB = require("../../db")
|
|
||||||
const { getDeployedApps } = require("../../utilities/workerRequests")
|
|
||||||
const { getScopedConfig } = require("@budibase/backend-core/db")
|
|
||||||
const { Configs } = require("@budibase/backend-core/constants")
|
|
||||||
const { checkSlashesInUrl } = require("../../utilities")
|
|
||||||
|
|
||||||
exports.fetchUrls = async ctx => {
|
|
||||||
const appId = ctx.appId
|
|
||||||
const db = new CouchDB(appId)
|
|
||||||
const settings = await getScopedConfig(db, { type: Configs.SETTINGS })
|
|
||||||
let appUrl = "http://localhost:10000/app"
|
|
||||||
if (settings && settings["platformUrl"]) {
|
|
||||||
appUrl = checkSlashesInUrl(`${settings["platformUrl"]}/app`)
|
|
||||||
}
|
|
||||||
ctx.body = {
|
|
||||||
app: appUrl,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.getDeployedApps = async ctx => {
|
|
||||||
ctx.body = await getDeployedApps()
|
|
||||||
}
|
|
|
@ -5,7 +5,7 @@ const { resolve, join } = require("../../../utilities/centralPath")
|
||||||
const uuid = require("uuid")
|
const uuid = require("uuid")
|
||||||
const { ObjectStoreBuckets } = require("../../../constants")
|
const { ObjectStoreBuckets } = require("../../../constants")
|
||||||
const { processString } = require("@budibase/string-templates")
|
const { processString } = require("@budibase/string-templates")
|
||||||
const { getDeployedApps } = require("../../../utilities/workerRequests")
|
const { getAllApps } = require("@budibase/backend-core/db")
|
||||||
const CouchDB = require("../../../db")
|
const CouchDB = require("../../../db")
|
||||||
const {
|
const {
|
||||||
loadHandlebarsFile,
|
loadHandlebarsFile,
|
||||||
|
@ -40,9 +40,13 @@ async function prepareUpload({ s3Key, bucket, metadata, file }) {
|
||||||
async function getAppIdFromUrl(ctx) {
|
async function getAppIdFromUrl(ctx) {
|
||||||
// the "appId" component of the URL can be the id or the custom url
|
// the "appId" component of the URL can be the id or the custom url
|
||||||
let possibleAppUrl = `/${encodeURI(ctx.params.appId).toLowerCase()}`
|
let possibleAppUrl = `/${encodeURI(ctx.params.appId).toLowerCase()}`
|
||||||
const apps = await getDeployedApps()
|
|
||||||
if (apps[possibleAppUrl] && apps[possibleAppUrl].appId) {
|
// search prod apps for a url that matches, exclude dev where id is always used
|
||||||
return apps[possibleAppUrl].appId
|
const apps = await getAllApps(CouchDB, { dev: false })
|
||||||
|
const app = apps.filter(a => a.url === possibleAppUrl)[0]
|
||||||
|
|
||||||
|
if (app && app.appId) {
|
||||||
|
return app.appId
|
||||||
} else {
|
} else {
|
||||||
return ctx.params.appId
|
return ctx.params.appId
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
const Router = require("@koa/router")
|
|
||||||
const controller = require("../controllers/hosting")
|
|
||||||
const authorized = require("../../middleware/authorized")
|
|
||||||
const { BUILDER } = require("@budibase/backend-core/permissions")
|
|
||||||
|
|
||||||
const router = Router()
|
|
||||||
|
|
||||||
router
|
|
||||||
.get("/api/hosting/urls", authorized(BUILDER), controller.fetchUrls)
|
|
||||||
// this isn't risky, doesn't return anything about apps other than names and URLs
|
|
||||||
.get("/api/hosting/apps", controller.getDeployedApps)
|
|
||||||
|
|
||||||
module.exports = router
|
|
|
@ -20,7 +20,6 @@ const integrationRoutes = require("./integration")
|
||||||
const permissionRoutes = require("./permission")
|
const permissionRoutes = require("./permission")
|
||||||
const datasourceRoutes = require("./datasource")
|
const datasourceRoutes = require("./datasource")
|
||||||
const queryRoutes = require("./query")
|
const queryRoutes = require("./query")
|
||||||
const hostingRoutes = require("./hosting")
|
|
||||||
const backupRoutes = require("./backup")
|
const backupRoutes = require("./backup")
|
||||||
const metadataRoutes = require("./metadata")
|
const metadataRoutes = require("./metadata")
|
||||||
const devRoutes = require("./dev")
|
const devRoutes = require("./dev")
|
||||||
|
@ -46,7 +45,6 @@ exports.mainRoutes = [
|
||||||
permissionRoutes,
|
permissionRoutes,
|
||||||
datasourceRoutes,
|
datasourceRoutes,
|
||||||
queryRoutes,
|
queryRoutes,
|
||||||
hostingRoutes,
|
|
||||||
backupRoutes,
|
backupRoutes,
|
||||||
metadataRoutes,
|
metadataRoutes,
|
||||||
devRoutes,
|
devRoutes,
|
||||||
|
|
|
@ -53,8 +53,8 @@ describe("/applications", () => {
|
||||||
|
|
||||||
describe("fetch", () => {
|
describe("fetch", () => {
|
||||||
it("lists all applications", async () => {
|
it("lists all applications", async () => {
|
||||||
await config.createApp(request, "app1")
|
await config.createApp("app1")
|
||||||
await config.createApp(request, "app2")
|
await config.createApp("app2")
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/applications?status=${AppStatus.DEV}`)
|
.get(`/api/applications?status=${AppStatus.DEV}`)
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
// mock out node fetch for this
|
|
||||||
jest.mock("node-fetch")
|
|
||||||
|
|
||||||
const { checkBuilderEndpoint } = require("./utilities/TestFunctions")
|
|
||||||
const setup = require("./utilities")
|
|
||||||
|
|
||||||
describe("/hosting", () => {
|
|
||||||
let request = setup.getRequest()
|
|
||||||
let config = setup.getConfig()
|
|
||||||
let app
|
|
||||||
|
|
||||||
afterAll(setup.afterAll)
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
app = await config.init()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("fetchUrls", () => {
|
|
||||||
it("should be able to fetch current app URLs", async () => {
|
|
||||||
const res = await request
|
|
||||||
.get(`/api/hosting/urls`)
|
|
||||||
.set(config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
expect(res.body.app).toEqual(`http://localhost:10000/app`)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
|
||||||
await checkBuilderEndpoint({
|
|
||||||
config,
|
|
||||||
method: "GET",
|
|
||||||
url: `/api/hosting/urls`,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -22,6 +22,7 @@ const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
||||||
const { createASession } = require("@budibase/backend-core/sessions")
|
const { createASession } = require("@budibase/backend-core/sessions")
|
||||||
const { user: userCache } = require("@budibase/backend-core/cache")
|
const { user: userCache } = require("@budibase/backend-core/cache")
|
||||||
const CouchDB = require("../../db")
|
const CouchDB = require("../../db")
|
||||||
|
const newid = require("../../db/newid")
|
||||||
core.init(CouchDB)
|
core.init(CouchDB)
|
||||||
|
|
||||||
const GLOBAL_USER_ID = "us_uuid1"
|
const GLOBAL_USER_ID = "us_uuid1"
|
||||||
|
@ -98,7 +99,8 @@ class TestConfiguration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async init(appName = "test_application") {
|
// use a new id as the name to avoid name collisions
|
||||||
|
async init(appName = newid()) {
|
||||||
await this.globalUser()
|
await this.globalUser()
|
||||||
return this.createApp(appName)
|
return this.createApp(appName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,29 +58,6 @@ exports.sendSmtpEmail = async (to, from, subject, contents, automation) => {
|
||||||
return response.json()
|
return response.json()
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getDeployedApps = async () => {
|
|
||||||
try {
|
|
||||||
const response = await fetch(
|
|
||||||
checkSlashesInUrl(env.WORKER_URL + `/api/apps`),
|
|
||||||
request(null, {
|
|
||||||
method: "GET",
|
|
||||||
})
|
|
||||||
)
|
|
||||||
const json = await response.json()
|
|
||||||
const apps = {}
|
|
||||||
for (let [key, value] of Object.entries(json)) {
|
|
||||||
if (value.url) {
|
|
||||||
value.url = value.url.toLowerCase()
|
|
||||||
apps[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return apps
|
|
||||||
} catch (err) {
|
|
||||||
// error, cannot determine deployed apps, don't stop app creation - sort this later
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.getGlobalSelf = async (ctx, appId = null) => {
|
exports.getGlobalSelf = async (ctx, appId = null) => {
|
||||||
const endpoint = `/api/global/users/self`
|
const endpoint = `/api/global/users/self`
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
const {
|
|
||||||
getAllApps,
|
|
||||||
getDeployedAppID,
|
|
||||||
isProdAppID,
|
|
||||||
} = require("@budibase/backend-core/db")
|
|
||||||
const CouchDB = require("../../db")
|
|
||||||
|
|
||||||
const URL_REGEX_SLASH = /\/|\\/g
|
|
||||||
|
|
||||||
exports.getApps = async ctx => {
|
|
||||||
const apps = await getAllApps(CouchDB, { all: true })
|
|
||||||
const body = {}
|
|
||||||
for (let app of apps) {
|
|
||||||
let url = app.url || encodeURI(`${app.name}`)
|
|
||||||
url = `/${url.replace(URL_REGEX_SLASH, "")}`
|
|
||||||
const appId = app.appId,
|
|
||||||
isProd = isProdAppID(app.appId)
|
|
||||||
if (!body[url]) {
|
|
||||||
body[url] = {
|
|
||||||
appId: getDeployedAppID(appId),
|
|
||||||
name: app.name,
|
|
||||||
url,
|
|
||||||
deployed: isProd,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
body[url].deployed = isProd || body[url].deployed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.body = body
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
const Router = require("@koa/router")
|
|
||||||
const controller = require("../controllers/app")
|
|
||||||
|
|
||||||
const router = Router()
|
|
||||||
|
|
||||||
router.get("/api/apps", controller.getApps)
|
|
||||||
|
|
||||||
module.exports = router
|
|
|
@ -8,14 +8,12 @@ const roleRoutes = require("./global/roles")
|
||||||
const sessionRoutes = require("./global/sessions")
|
const sessionRoutes = require("./global/sessions")
|
||||||
const environmentRoutes = require("./system/environment")
|
const environmentRoutes = require("./system/environment")
|
||||||
const tenantsRoutes = require("./system/tenants")
|
const tenantsRoutes = require("./system/tenants")
|
||||||
const appRoutes = require("./app")
|
|
||||||
|
|
||||||
exports.routes = [
|
exports.routes = [
|
||||||
configRoutes,
|
configRoutes,
|
||||||
userRoutes,
|
userRoutes,
|
||||||
workspaceRoutes,
|
workspaceRoutes,
|
||||||
authRoutes,
|
authRoutes,
|
||||||
appRoutes,
|
|
||||||
templateRoutes,
|
templateRoutes,
|
||||||
tenantsRoutes,
|
tenantsRoutes,
|
||||||
emailRoutes,
|
emailRoutes,
|
||||||
|
|
Loading…
Reference in New Issue