Merge pull request #1574 from Budibase/fix/mike-0.9.1

Various fixes based on reports
This commit is contained in:
Michael Drury 2021-05-27 15:57:32 +01:00 committed by GitHub
commit 7892260366
14 changed files with 361 additions and 30 deletions

View File

@ -7,12 +7,12 @@
// Check this onMount rather than a reactive statement to avoid trumping // Check this onMount rather than a reactive statement to avoid trumping
// the login return URL functionality. // the login return URL functionality.
onMount(() => { onMount(() => {
if ($auth.user) { if ($auth.user && !$auth.user.forceResetPassword) {
$redirect("../") $redirect("../")
} }
}) })
</script> </script>
{#if !$auth.user} {#if !$auth.user || $auth.user.forceResetPassword}
<slot /> <slot />
{/if} {/if}

View File

@ -1,10 +1,8 @@
const Router = require("@koa/router") const Router = require("@koa/router")
const authorized = require("../../middleware/authorized")
const controller = require("../controllers/analytics") const controller = require("../controllers/analytics")
const { BUILDER } = require("@budibase/auth/permissions")
const router = Router() const router = Router()
router.get("/api/analytics", authorized(BUILDER), controller.isEnabled) router.get("/api/analytics", controller.isEnabled)
module.exports = router module.exports = router

View File

@ -7,12 +7,8 @@ const router = Router()
router router
.get("/api/applications/:appId/definition", controller.fetchAppDefinition) .get("/api/applications/:appId/definition", controller.fetchAppDefinition)
.get("/api/applications", authorized(BUILDER), controller.fetch) .get("/api/applications", controller.fetch)
.get( .get("/api/applications/:appId/appPackage", controller.fetchAppPackage)
"/api/applications/:appId/appPackage",
authorized(BUILDER),
controller.fetchAppPackage
)
.put("/api/applications/:appId", authorized(BUILDER), controller.update) .put("/api/applications/:appId", authorized(BUILDER), controller.update)
.post("/api/applications", authorized(BUILDER), controller.create) .post("/api/applications", authorized(BUILDER), controller.create)
.delete("/api/applications/:appId", authorized(BUILDER), controller.delete) .delete("/api/applications/:appId", authorized(BUILDER), controller.delete)

View File

@ -61,14 +61,6 @@ describe("/applications", () => {
// two created apps + the inited app // two created apps + the inited app
expect(res.body.length).toBe(3) expect(res.body.length).toBe(3)
}) })
it("should apply authorization to endpoint", async () => {
await checkBuilderEndpoint({
config,
method: "GET",
url: `/api/applications`,
})
})
}) })
describe("fetchAppDefinition", () => { describe("fetchAppDefinition", () => {

View File

@ -1,13 +1,15 @@
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
const { checkPermissionsEndpoint } = require("./utilities/TestFunctions") const { checkPermissionsEndpoint } = require("./utilities/TestFunctions")
const setup = require("./utilities") const setup = require("./utilities")
const { basicUser } = setup.structures
const workerRequests = require("../../../utilities/workerRequests") const workerRequests = require("../../../utilities/workerRequests")
jest.mock("../../../utilities/workerRequests", () => ({ jest.mock("../../../utilities/workerRequests", () => ({
getGlobalUsers: jest.fn(() => { getGlobalUsers: jest.fn(() => {
return {} return {}
}), }),
getGlobalSelf: jest.fn(() => {
return {}
}),
addAppRoleToUser: jest.fn(), addAppRoleToUser: jest.fn(),
deleteGlobalUser: jest.fn(), deleteGlobalUser: jest.fn(),
})) }))

View File

@ -8,6 +8,11 @@ jest.mock("../../../../utilities/workerRequests", () => ({
_id: "us_uuid1", _id: "us_uuid1",
} }
}), }),
getGlobalSelf: jest.fn(() => {
return {
_id: "us_uuid1",
}
}),
})) }))
exports.delay = ms => new Promise(resolve => setTimeout(resolve, ms)) exports.delay = ms => new Promise(resolve => setTimeout(resolve, ms))

View File

@ -58,9 +58,9 @@ const SCHEMA = {
class PostgresIntegration { class PostgresIntegration {
constructor(config) { constructor(config) {
this.config = config this.config = config
if (this.config.ssl.rejectUnauthorized) { if (this.config.ssl && this.config.ssl.rejectUnauthorized) {
this.config.ssl.rejectUnauthorized = this.config.ssl.rejectUnauthorized =
this.config.ssl.rejectUnauthorized === "true" ? true : false this.config.ssl.rejectUnauthorized === "true"
} }
if (!pool) { if (!pool) {

View File

@ -1,7 +1,7 @@
const { getAppId, setCookie, getCookie } = require("@budibase/auth").utils const { getAppId, setCookie, getCookie } = require("@budibase/auth").utils
const { Cookies } = require("@budibase/auth").constants const { Cookies } = require("@budibase/auth").constants
const { getRole } = require("@budibase/auth/roles") const { getRole } = require("@budibase/auth/roles")
const { getGlobalUsers } = require("../utilities/workerRequests") const { getGlobalSelf } = require("../utilities/workerRequests")
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
const { generateUserMetadataID } = require("../db/utils") const { generateUserMetadataID } = require("../db/utils")
@ -25,10 +25,11 @@ module.exports = async (ctx, next) => {
requestAppId != null && requestAppId != null &&
(appCookie == null || (appCookie == null ||
requestAppId !== appCookie.appId || requestAppId !== appCookie.appId ||
appCookie.roleId === BUILTIN_ROLE_IDS.PUBLIC) appCookie.roleId === BUILTIN_ROLE_IDS.PUBLIC ||
!appCookie.roleId)
) { ) {
// Different App ID means cookie needs reset, or if the same public user has logged in // Different App ID means cookie needs reset, or if the same public user has logged in
const globalUser = await getGlobalUsers(ctx, requestAppId, ctx.user._id) const globalUser = await getGlobalSelf(ctx, requestAppId)
updateCookie = true updateCookie = true
appId = requestAppId appId = requestAppId
// retrieving global user gets the right role // retrieving global user gets the right role
@ -51,6 +52,7 @@ module.exports = async (ctx, next) => {
// override userID with metadata one // override userID with metadata one
_id: userId, _id: userId,
userId, userId,
roleId,
role: await getRole(appId, roleId), role: await getRole(appId, roleId),
} }
} }

View File

@ -3,7 +3,7 @@ mockWorker()
function mockWorker() { function mockWorker() {
jest.mock("../../utilities/workerRequests", () => ({ jest.mock("../../utilities/workerRequests", () => ({
getGlobalUsers: () => { getGlobalSelf: () => {
return { return {
_id: "us_uuid1", _id: "us_uuid1",
roles: { roles: {

View File

@ -119,16 +119,19 @@ exports.getGlobalUsers = async (ctx, appId = null, globalId = null) => {
return users return users
} }
exports.getGlobalSelf = async ctx => { exports.getGlobalSelf = async (ctx, appId = null) => {
const endpoint = `/api/admin/users/self` const endpoint = `/api/admin/users/self`
const response = await fetch( const response = await fetch(
checkSlashesInUrl(env.WORKER_URL + endpoint), checkSlashesInUrl(env.WORKER_URL + endpoint),
request(ctx, { method: "GET" }) request(ctx, { method: "GET" })
) )
const json = await response.json() let json = await response.json()
if (json.status !== 200 && response.status !== 200) { if (json.status !== 200 && response.status !== 200) {
ctx.throw(400, "Unable to get self globally.") ctx.throw(400, "Unable to get self globally.")
} }
if (appId) {
json = getAppRole(appId, json)
}
return json return json
} }

View File

@ -2,6 +2,7 @@ const dayjs = require("dayjs")
dayjs.extend(require("dayjs/plugin/duration")) dayjs.extend(require("dayjs/plugin/duration"))
dayjs.extend(require("dayjs/plugin/advancedFormat")) dayjs.extend(require("dayjs/plugin/advancedFormat"))
dayjs.extend(require("dayjs/plugin/relativeTime")) dayjs.extend(require("dayjs/plugin/relativeTime"))
dayjs.extend(require("dayjs/plugin/utc"))
/** /**
* This file was largely taken from the helper-date package - we did this for two reasons: * This file was largely taken from the helper-date package - we did this for two reasons:
@ -88,7 +89,11 @@ module.exports.date = (str, pattern, options) => {
setLocale(config.str, config.pattern, config.options) setLocale(config.str, config.pattern, config.options)
return dayjs(new Date(config.str)).format(config.pattern) const date = dayjs(new Date(config.str)).utc()
if (config.pattern === "") {
return date.toISOString()
}
return date.format(config.pattern)
} }
module.exports.duration = (str, pattern, format) => { module.exports.duration = (str, pattern, format) => {

View File

@ -18,7 +18,7 @@ class Postprocessor {
module.exports.processors = [ module.exports.processors = [
new Postprocessor(PostProcessorNames.CONVERT_LITERALS, statement => { new Postprocessor(PostProcessorNames.CONVERT_LITERALS, statement => {
if (!statement.includes(LITERAL_MARKER)) { if (typeof statement !== "string" || !statement.includes(LITERAL_MARKER)) {
return statement return statement
} }
const splitMarkerIndex = statement.indexOf("-") const splitMarkerIndex = statement.indexOf("-")

View File

@ -0,0 +1,305 @@
{
"user":{
"_id":"ro_ta_users_us_b0bc7ba0ce304294accc1ced8165dd23",
"_rev":"1-e9199d92e7286005a9c11c614fdbcc51",
"email":"test2@test.com",
"status":"active",
"roleId":"PUBLIC",
"test-Created By_text":"",
"test-Updated By_text":""
},
"closestComponentId":"c670254c9e74e40518ee5becff53aa5be",
"url":{
},
"c670254c9e74e40518ee5becff53aa5be":{
"rows":[
{
"_id":"ro_ta_1399af8a08d244a9885c674dd5555c84_8c1940e906254db5ac79c51011255d6c",
"_rev":"1-49ff5a4094a251a7767155eb85f4c9b7",
"sef":"sefesfesf",
"Name":"sefesf",
"tableId":"ta_1399af8a08d244a9885c674dd5555c84",
"Auto ID":1,
"Created At":"2021-05-27T10:30:37.386Z",
"Updated At":"2021-05-27T10:30:37.386Z",
"type":"row",
"Created By":[
{
"_id":"ro_ta_users_us_de1bd7fe710146db990d92845008c763"
}
],
"Updated By":[
{
"_id":"ro_ta_users_us_de1bd7fe710146db990d92845008c763"
}
],
"testing":"2",
"Created By_text":"",
"Updated By_text":""
}
],
"schema":{
"Auto ID":{
"name":"Auto ID",
"type":"number",
"subtype":"autoID",
"icon":"ri-magic-line",
"autocolumn":true,
"constraints":{
"type":"number",
"presence":false,
"numericality":{
"greaterThanOrEqualTo":"",
"lessThanOrEqualTo":""
}
},
"lastID":1
},
"Created By":{
"name":"Created By",
"type":"link",
"subtype":"createdBy",
"icon":"ri-magic-line",
"autocolumn":true,
"constraints":{
"type":"array",
"presence":false
},
"tableId":"ta_users",
"fieldName":"test-Created By",
"relationshipType":"many-to-many"
},
"Created At":{
"name":"Created At",
"type":"datetime",
"subtype":"createdAt",
"icon":"ri-magic-line",
"autocolumn":true,
"constraints":{
"type":"string",
"length":{
},
"presence":false,
"datetime":{
"latest":"",
"earliest":""
}
}
},
"Updated By":{
"name":"Updated By",
"type":"link",
"subtype":"updatedBy",
"icon":"ri-magic-line",
"autocolumn":true,
"constraints":{
"type":"array",
"presence":false
},
"tableId":"ta_users",
"fieldName":"test-Updated By",
"relationshipType":"many-to-many"
},
"Updated At":{
"name":"Updated At",
"type":"datetime",
"subtype":"updatedAt",
"icon":"ri-magic-line",
"autocolumn":true,
"constraints":{
"type":"string",
"length":{
},
"presence":false,
"datetime":{
"latest":"",
"earliest":""
}
}
},
"Name":{
"type":"string",
"constraints":{
"type":"string",
"length":{
"maximum":null
},
"presence":false
},
"fieldName":"test",
"name":"Name"
},
"sef":{
"type":"string",
"constraints":{
"type":"string",
"length":{
"maximum":null
},
"presence":false
},
"fieldName":"test",
"name":"sef"
},
"testing":{
"type":"formula",
"constraints":{
"type":"string",
"presence":false
},
"fieldName":"test",
"name":"testing",
"formula":"{{ add [Auto ID] 1 }}"
}
},
"rowsLength":1
},
"data":{
"rows":[
{
"_id":"ro_ta_1399af8a08d244a9885c674dd5555c84_8c1940e906254db5ac79c51011255d6c",
"_rev":"1-49ff5a4094a251a7767155eb85f4c9b7",
"sef":"sefesfesf",
"Name":"sefesf",
"tableId":"ta_1399af8a08d244a9885c674dd5555c84",
"Auto ID":1,
"Created At":"2021-05-27T10:30:37.386Z",
"Updated At":"2021-05-27T10:30:37.386Z",
"type":"row",
"Created By":[
{
"_id":"ro_ta_users_us_de1bd7fe710146db990d92845008c763"
}
],
"Updated By":[
{
"_id":"ro_ta_users_us_de1bd7fe710146db990d92845008c763"
}
],
"testing":"2",
"Created By_text":"",
"Updated By_text":""
}
],
"schema":{
"Auto ID":{
"name":"Auto ID",
"type":"number",
"subtype":"autoID",
"icon":"ri-magic-line",
"autocolumn":true,
"constraints":{
"type":"number",
"presence":false,
"numericality":{
"greaterThanOrEqualTo":"",
"lessThanOrEqualTo":""
}
},
"lastID":1
},
"Created By":{
"name":"Created By",
"type":"link",
"subtype":"createdBy",
"icon":"ri-magic-line",
"autocolumn":true,
"constraints":{
"type":"array",
"presence":false
},
"tableId":"ta_users",
"fieldName":"test-Created By",
"relationshipType":"many-to-many"
},
"Created At":{
"name":"Created At",
"type":"datetime",
"subtype":"createdAt",
"icon":"ri-magic-line",
"autocolumn":true,
"constraints":{
"type":"string",
"length":{
},
"presence":false,
"datetime":{
"latest":"",
"earliest":""
}
}
},
"Updated By":{
"name":"Updated By",
"type":"link",
"subtype":"updatedBy",
"icon":"ri-magic-line",
"autocolumn":true,
"constraints":{
"type":"array",
"presence":false
},
"tableId":"ta_users",
"fieldName":"test-Updated By",
"relationshipType":"many-to-many"
},
"Updated At":{
"name":"Updated At",
"type":"datetime",
"subtype":"updatedAt",
"icon":"ri-magic-line",
"autocolumn":true,
"constraints":{
"type":"string",
"length":{
},
"presence":false,
"datetime":{
"latest":"",
"earliest":""
}
}
},
"Name":{
"type":"string",
"constraints":{
"type":"string",
"length":{
"maximum":null
},
"presence":false
},
"fieldName":"test",
"name":"Name"
},
"sef":{
"type":"string",
"constraints":{
"type":"string",
"length":{
"maximum":null
},
"presence":false
},
"fieldName":"test",
"name":"sef"
},
"testing":{
"type":"formula",
"constraints":{
"type":"string",
"presence":false
},
"fieldName":"test",
"name":"testing",
"formula":"{{ add [Auto ID] 1 }}"
}
},
"rowsLength":1
}
}

View File

@ -1,4 +1,5 @@
const { processString, processObject, isValid } = require("../src/index.cjs") const { processString, processObject, isValid } = require("../src/index.cjs")
const tableJson = require("./examples/table.json")
describe("test the custom helpers we have applied", () => { describe("test the custom helpers we have applied", () => {
it("should be able to use the object helper", async () => { it("should be able to use the object helper", async () => {
@ -355,6 +356,15 @@ describe("Cover a few complex use cases", () => {
expect(validity).toBe(true) expect(validity).toBe(true)
}) })
it("should test a case of attempting to get a UTC ISO back out after processing", async () => {
const date = new Date()
const input = `{{ date (subtract (date dateThing "x") 300000) "" }}`
const output = await processString(input, {
dateThing: date.toISOString(),
})
expect(output).toEqual(new Date(date.getTime() - 300000).toISOString())
})
it("test a very complex duration output", async () => { it("test a very complex duration output", async () => {
const currentTime = new Date(1612432082000).toISOString(), const currentTime = new Date(1612432082000).toISOString(),
eventTime = new Date(1612432071000).toISOString() eventTime = new Date(1612432071000).toISOString()
@ -388,4 +398,17 @@ describe("Cover a few complex use cases", () => {
const output = await processObject(input, context) const output = await processObject(input, context)
expect(output.text).toBe("12-01") expect(output.text).toBe("12-01")
}) })
it("should only invalidate a single string in an object", async () => {
const input = {
dataProvider:"{{ literal [c670254c9e74e40518ee5becff53aa5be] }}",
theme:"spectrum--lightest",
showAutoColumns:false,
quiet:true,
size:"spectrum--medium",
rowCount:8,
}
const output = await processObject(input, tableJson)
expect(output.dataProvider).not.toBe("Invalid Binding")
})
}) })