Browse Source

Adding a testing system which generates the schema and compares against responses.

master
Michael Drury 5 years ago
parent
commit
46d23cfb25
  1. 8
      packages/bbui/yarn.lock
  2. 1267
      packages/client/yarn.lock
  3. 1
      packages/server/__mocks__/node-fetch.ts
  4. 1
      packages/server/package.json
  5. 24
      packages/server/specs/generate.js
  6. 1187
      packages/server/specs/openapi.json
  7. 918
      packages/server/specs/openapi.yaml
  8. 148
      packages/server/specs/resources/table.js
  9. 1
      packages/server/specs/resources/utils/index.js
  10. 88
      packages/server/src/api/routes/public/applications.ts
  11. 76
      packages/server/src/api/routes/public/queries.ts
  12. 240
      packages/server/src/api/routes/public/rows.ts
  13. 76
      packages/server/src/api/routes/public/tables.ts
  14. 74
      packages/server/src/api/routes/public/tests/compare.spec.js
  15. 73
      packages/server/src/api/routes/public/users.ts
  16. 19
      packages/server/src/tests/utilities/TestConfiguration.js
  17. 1137
      packages/server/yarn.lock

8
packages/bbui/yarn.lock

@ -53,10 +53,10 @@
to-gfm-code-block "^0.1.1" to-gfm-code-block "^0.1.1"
year "^0.2.1" year "^0.2.1"
"@budibase/string-templates@^1.0.66-alpha.0": "@budibase/string-templates@^1.0.72-alpha.0":
version "1.0.72" version "1.0.75"
resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.72.tgz#acc154e402cce98ea30eedde9c6124183ee9b37c" resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.75.tgz#5b4061f1a626160ec092f32f036541376298100c"
integrity sha512-w715TjgO6NUHkZNqoOEo8lAKJ/PQ4b00ATWSX5VB523SAu7y/uOiqKqV1E3fgwxq1o8L+Ff7rn9FTkiYtjkV/g== integrity sha512-hPgr6n5cpSCGFEha5DS/P+rtRXOLc72M6y4J/scl59JvUi/ZUJkjRgJdpQPdBLu04CNKp89V59+rAqAuDjOC0g==
dependencies: dependencies:
"@budibase/handlebars-helpers" "^0.11.7" "@budibase/handlebars-helpers" "^0.11.7"
dayjs "^1.10.4" dayjs "^1.10.4"

1267
packages/client/yarn.lock

File diff suppressed because it is too large

1
packages/server/__mocks__/node-fetch.ts

@ -53,6 +53,7 @@ module FetchMock {
{ {
doc: { doc: {
_id: "test", _id: "test",
tableId: opts.body.split("tableId:")[1].split('"')[0],
}, },
}, },
], ],

1
packages/server/package.json

@ -158,6 +158,7 @@
"docker-compose": "^0.23.6", "docker-compose": "^0.23.6",
"eslint": "^6.8.0", "eslint": "^6.8.0",
"jest": "^27.0.5", "jest": "^27.0.5",
"jest-openapi": "^0.14.2",
"nodemon": "^2.0.4", "nodemon": "^2.0.4",
"openapi-types": "^9.3.1", "openapi-types": "^9.3.1",
"path-to-regexp": "^6.2.0", "path-to-regexp": "^6.2.0",

24
packages/server/specs/generate.js

@ -49,12 +49,11 @@ const options = {
apis: [join(__dirname, "..", "src", "api", "routes", "public", "*.ts")], apis: [join(__dirname, "..", "src", "api", "routes", "public", "*.ts")],
} }
function writeFile(output, { isJson } = {}) { function writeFile(output, filename) {
try { try {
const filename = isJson ? "openapi.json" : "openapi.yaml"
const path = join(__dirname, filename) const path = join(__dirname, filename)
let spec = output let spec = output
if (isJson) { if (filename.endsWith("json")) {
spec = JSON.stringify(output, null, 2) spec = JSON.stringify(output, null, 2)
} }
// input the static variables // input the static variables
@ -63,13 +62,22 @@ function writeFile(output, { isJson } = {}) {
} }
writeFileSync(path, spec) writeFileSync(path, spec)
console.log(`Wrote spec to ${path}`) console.log(`Wrote spec to ${path}`)
return path
} catch (err) { } catch (err) {
console.error(err) console.error(err)
} }
} }
const outputJSON = swaggerJsdoc(options) function run() {
options.format = ".yaml" const outputJSON = swaggerJsdoc(options)
const outputYAML = swaggerJsdoc(options) options.format = ".yaml"
writeFile(outputJSON, { isJson: true }) const outputYAML = swaggerJsdoc(options)
writeFile(outputYAML) writeFile(outputJSON, "openapi.json")
return writeFile(outputYAML, "openapi.yaml")
}
if (require.main === module) {
run()
}
module.exports = run

1187
packages/server/specs/openapi.json

File diff suppressed because it is too large

918
packages/server/specs/openapi.yaml

File diff suppressed because it is too large

148
packages/server/specs/resources/table.js

@ -63,6 +63,7 @@ const baseColumnDef = {
const tableSchema = { const tableSchema = {
description: "The table to be created/updated.", description: "The table to be created/updated.",
type: "object", type: "object",
required: ["name", "schema"],
properties: { properties: {
name: { name: {
description: "The name of the table", description: "The name of the table",
@ -74,82 +75,85 @@ const tableSchema = {
"The name of the column which should be used in relationship tags when relating to this table.", "The name of the column which should be used in relationship tags when relating to this table.",
}, },
schema: { schema: {
oneOf: [ type: "object",
// relationship additionalProperties: {
{ oneOf: [
type: "object", // relationship
properties: { {
...baseColumnDef, type: "object",
type: { properties: {
type: "string", ...baseColumnDef,
enum: [FieldTypes.LINK], type: {
description: "A relationship column.", type: "string",
}, enum: [FieldTypes.LINK],
fieldName: { description: "A relationship column.",
type: "string", },
description: fieldName: {
"The name of the column which a relationship column is related to in another table.", type: "string",
}, description:
tableId: { "The name of the column which a relationship column is related to in another table.",
type: "string", },
description: tableId: {
"The ID of the table which a relationship column is related to.", type: "string",
}, description:
relationshipType: { "The ID of the table which a relationship column is related to.",
type: "string", },
enum: Object.values(RelationshipTypes), relationshipType: {
description: type: "string",
"Defines the type of relationship that this column will be used for.", enum: Object.values(RelationshipTypes),
}, description:
through: { "Defines the type of relationship that this column will be used for.",
type: "string", },
description: through: {
"When using a SQL table that contains many to many relationships this defines the table the relationships are linked through.", type: "string",
}, description:
foreignKey: { "When using a SQL table that contains many to many relationships this defines the table the relationships are linked through.",
type: "string", },
description: foreignKey: {
"When using a SQL table that contains a one to many relationship this defines the foreign key.", type: "string",
}, description:
throughFrom: { "When using a SQL table that contains a one to many relationship this defines the foreign key.",
type: "string", },
description: throughFrom: {
"When using a SQL table that utilises a through table, this defines the primary key in the through table for this table.", type: "string",
}, description:
throughTo: { "When using a SQL table that utilises a through table, this defines the primary key in the through table for this table.",
type: "string", },
description: throughTo: {
"When using a SQL table that utilises a through table, this defines the primary key in the through table for the related table.", type: "string",
description:
"When using a SQL table that utilises a through table, this defines the primary key in the through table for the related table.",
},
}, },
}, },
}, {
{ type: "object",
type: "object", properties: {
properties: { ...baseColumnDef,
...baseColumnDef, type: {
type: { type: "string",
type: "string", enum: [FieldTypes.FORMULA],
enum: [FieldTypes.FORMULA], description: "A formula column.",
description: "A formula column.", },
}, formula: {
formula: { type: "string",
type: "string", description:
description: "Defines a Handlebars or JavaScript formula to use, note that Javascript formulas are expected to be provided in the base64 format.",
"Defines a Handlebars or JavaScript formula to use, note that Javascript formulas are expected to be provided in the base64 format.", },
}, formulaType: {
formulaType: { type: "string",
type: "string", enum: Object.values(FormulaTypes),
enum: Object.values(FormulaTypes), description:
description: "Defines whether this is a static or dynamic formula.",
"Defines whether this is a static or dynamic formula.", },
}, },
}, },
}, {
{ type: "object",
type: "object", properties: baseColumnDef,
properties: baseColumnDef, },
}, ],
], },
}, },
}, },
} }

1
packages/server/specs/resources/utils/index.js

@ -2,6 +2,7 @@ exports.object = (props, opts) => {
return { return {
type: "object", type: "object",
properties: props, properties: props,
required: Object.keys(props),
...opts, ...opts,
} }
} }

88
packages/server/src/api/routes/public/applications.ts

@ -5,43 +5,6 @@ const { nameValidator, applicationValidator } = require("../utils/validators")
const read = [], const read = [],
write = [] write = []
/**
* @openapi
* /applications/search:
* post:
* summary: Search for an application based on its app name.
* tags:
* - applications
* parameters:
* - $ref: '#/components/parameters/appId'
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/nameSearch'
* responses:
* 200:
* description: Returns the applications that were found based on the search parameters.
* content:
* application/json:
* schema:
* type: object
* properties:
* applications:
* type: array
* items:
* $ref: '#/components/schemas/application'
* examples:
* applications:
* $ref: '#/components/examples/applications'
*/
read.push(
new Endpoint("post", "/applications/search", controller.search).addMiddleware(
nameValidator()
)
)
/** /**
* @openapi * @openapi
* /applications: * /applications:
@ -68,7 +31,11 @@ read.push(
* application: * application:
* $ref: '#/components/examples/application' * $ref: '#/components/examples/application'
*/ */
write.push(new Endpoint("post", "/applications", controller.create)) write.push(
new Endpoint("post", "/applications", controller.create).addMiddleware(
applicationValidator
)
)
/** /**
* @openapi * @openapi
@ -96,7 +63,11 @@ write.push(new Endpoint("post", "/applications", controller.create))
* application: * application:
* $ref: '#/components/examples/application' * $ref: '#/components/examples/application'
*/ */
write.push(new Endpoint("put", "/applications/:appId", controller.update)) write.push(
new Endpoint("put", "/applications/:appId", controller.update).addMiddleware(
applicationValidator
)
)
/** /**
* @openapi * @openapi
@ -142,4 +113,43 @@ write.push(new Endpoint("delete", "/applications/:appId", controller.destroy))
*/ */
read.push(new Endpoint("get", "/applications/:appId", controller.read)) read.push(new Endpoint("get", "/applications/:appId", controller.read))
/**
* @openapi
* /applications/search:
* post:
* summary: Search for an application based on its app name.
* tags:
* - applications
* parameters:
* - $ref: '#/components/parameters/appId'
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/nameSearch'
* responses:
* 200:
* description: Returns the applications that were found based on the search parameters.
* content:
* application/json:
* schema:
* type: object
* required:
* - applications
* properties:
* applications:
* type: array
* items:
* $ref: '#/components/schemas/application'
* examples:
* applications:
* $ref: '#/components/examples/applications'
*/
read.push(
new Endpoint("post", "/applications/search", controller.search).addMiddleware(
nameValidator()
)
)
export default { read, write } export default { read, write }

76
packages/server/src/api/routes/public/queries.ts

@ -5,43 +5,6 @@ import { nameValidator } from "../utils/validators"
const read = [], const read = [],
write = [] write = []
/**
* @openapi
* /queries/search:
* post:
* summary: Search for a query based on its name.
* tags:
* - queries
* parameters:
* - $ref: '#/components/parameters/appId'
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/nameSearch'
* responses:
* 200:
* description: Returns the queries found based on the search parameters.
* content:
* application/json:
* schema:
* type: object
* properties:
* queries:
* type: array
* items:
* $ref: '#/components/schemas/query'
* examples:
* queries:
* $ref: '#/components/examples/queries'
*/
read.push(
new Endpoint("post", "/queries/search", controller.search).addMiddleware(
nameValidator()
)
)
/** /**
* @openapi * @openapi
* /queries/{queryId}: * /queries/{queryId}:
@ -89,4 +52,43 @@ read.push(
*/ */
write.push(new Endpoint("post", "/queries/:queryId", controller.execute)) write.push(new Endpoint("post", "/queries/:queryId", controller.execute))
/**
* @openapi
* /queries/search:
* post:
* summary: Search for a query based on its name.
* tags:
* - queries
* parameters:
* - $ref: '#/components/parameters/appId'
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/nameSearch'
* responses:
* 200:
* description: Returns the queries found based on the search parameters.
* content:
* application/json:
* schema:
* type: object
* required:
* - queries
* properties:
* queries:
* type: array
* items:
* $ref: '#/components/schemas/query'
* examples:
* queries:
* $ref: '#/components/examples/queries'
*/
read.push(
new Endpoint("post", "/queries/search", controller.search).addMiddleware(
nameValidator()
)
)
export default { read, write } export default { read, write }

240
packages/server/src/api/routes/public/rows.ts

@ -5,6 +5,124 @@ import { externalSearchValidator } from "../utils/validators"
const read = [], const read = [],
write = [] write = []
/**
* @openapi
* /tables/{tableId}/rows:
* post:
* summary: Creates a new row within a specified table.
* tags:
* - rows
* parameters:
* - $ref: '#/components/parameters/tableId'
* - $ref: '#/components/parameters/appId'
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/row'
* examples:
* row:
* $ref: '#/components/examples/inputRow'
* responses:
* 200:
* description: Returns the created row, including the ID which has been generated for it.
* This can be found in the Budibase portal, viewed under the developer information.
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/rowOutput'
* examples:
* row:
* $ref: '#/components/examples/row'
*/
write.push(new Endpoint("post", "/tables/:tableId/rows", controller.create))
/**
* @openapi
* /tables/{tableId}/rows/{rowId}:
* put:
* summary: Update a single row within a specified table.
* tags:
* - rows
* parameters:
* - $ref: '#/components/parameters/tableId'
* - $ref: '#/components/parameters/rowId'
* - $ref: '#/components/parameters/appId'
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/row'
* examples:
* row:
* $ref: '#/components/examples/inputRow'
* responses:
* 200:
* description: Returns the created row, including the ID which has been generated for it.
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/rowOutput'
* examples:
* row:
* $ref: '#/components/examples/row'
*/
write.push(
new Endpoint("put", "/tables/:tableId/rows/:rowId", controller.update)
)
/**
* @openapi
* /tables/{tableId}/rows/{rowId}:
* delete:
* summary: Delete a single row from the specified table.
* tags:
* - rows
* parameters:
* - $ref: '#/components/parameters/tableId'
* - $ref: '#/components/parameters/rowId'
* - $ref: '#/components/parameters/appId'
* responses:
* 200:
* description: Returns the deleted row, including the ID which has been generated for it.
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/rowOutput'
* examples:
* row:
* $ref: '#/components/examples/row'
*/
write.push(
new Endpoint("delete", "/tables/:tableId/rows/:rowId", controller.destroy)
)
/**
* @openapi
* /tables/{tableId}/rows/{rowId}:
* get:
* summary: Get a single row from the specified table.
* tags:
* - rows
* parameters:
* - $ref: '#/components/parameters/tableId'
* - $ref: '#/components/parameters/rowId'
* - $ref: '#/components/parameters/appId'
* responses:
* 200:
* description: Returns the retrieved row.
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/rowOutput'
* examples:
* row:
* $ref: '#/components/examples/row'
*/
read.push(new Endpoint("get", "/tables/:tableId/rows/:rowId", controller.read))
/** /**
* @openapi * @openapi
* /tables/{tableId}/rows/search: * /tables/{tableId}/rows/search:
@ -21,6 +139,8 @@ const read = [],
* application/json: * application/json:
* schema: * schema:
* type: object * type: object
* required:
* - query
* properties: * properties:
* query: * query:
* type: object * type: object
@ -102,6 +222,8 @@ const read = [],
* application/json: * application/json:
* schema: * schema:
* type: object * type: object
* required:
* - rows
* properties: * properties:
* rows: * rows:
* description: An array of rows, these will each contain an _id field which can be used * description: An array of rows, these will each contain an _id field which can be used
@ -129,122 +251,4 @@ read.push(
).addMiddleware(externalSearchValidator()) ).addMiddleware(externalSearchValidator())
) )
/**
* @openapi
* /tables/{tableId}/rows:
* post:
* summary: Creates a new row within a specified table.
* tags:
* - rows
* parameters:
* - $ref: '#/components/parameters/tableId'
* - $ref: '#/components/parameters/appId'
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/row'
* examples:
* row:
* $ref: '#/components/examples/inputRow'
* responses:
* 200:
* description: Returns the created row, including the ID which has been generated for it.
* This can be found in the Budibase portal, viewed under the developer information.
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/rowOutput'
* examples:
* row:
* $ref: '#/components/examples/row'
*/
write.push(new Endpoint("post", "/tables/:tableId/rows", controller.create))
/**
* @openapi
* /tables/{tableId}/rows/{rowId}:
* put:
* summary: Update a single row within a specified table.
* tags:
* - rows
* parameters:
* - $ref: '#/components/parameters/tableId'
* - $ref: '#/components/parameters/rowId'
* - $ref: '#/components/parameters/appId'
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/row'
* examples:
* row:
* $ref: '#/components/examples/inputRow'
* responses:
* 200:
* description: Returns the created row, including the ID which has been generated for it.
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/rowOutput'
* examples:
* row:
* $ref: '#/components/examples/row'
*/
write.push(
new Endpoint("put", "/tables/:tableId/rows/:rowId", controller.update)
)
/**
* @openapi
* /tables/{tableId}/rows/{rowId}:
* delete:
* summary: Delete a single row from the specified table.
* tags:
* - rows
* parameters:
* - $ref: '#/components/parameters/tableId'
* - $ref: '#/components/parameters/rowId'
* - $ref: '#/components/parameters/appId'
* responses:
* 200:
* description: Returns the deleted row, including the ID which has been generated for it.
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/rowOutput'
* examples:
* row:
* $ref: '#/components/examples/row'
*/
write.push(
new Endpoint("delete", "/tables/:tableId/rows/:rowId", controller.destroy)
)
/**
* @openapi
* /tables/{tableId}/rows/{rowId}:
* get:
* summary: Get a single row from the specified table.
* tags:
* - rows
* parameters:
* - $ref: '#/components/parameters/tableId'
* - $ref: '#/components/parameters/rowId'
* - $ref: '#/components/parameters/appId'
* responses:
* 200:
* description: Returns the retrieved row.
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/rowOutput'
* examples:
* row:
* $ref: '#/components/examples/row'
*/
read.push(new Endpoint("get", "/tables/:tableId/rows/:rowId", controller.read))
export default { read, write } export default { read, write }

76
packages/server/src/api/routes/public/tables.ts

@ -5,43 +5,6 @@ import { tableValidator, nameValidator } from "../utils/validators"
const read = [], const read = [],
write = [] write = []
/**
* @openapi
* /tables/search:
* post:
* summary: Search internal and external tables based on their name.
* tags:
* - tables
* parameters:
* - $ref: '#/components/parameters/appId'
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/nameSearch'
* responses:
* 200:
* description: Returns the found tables, based on the search parameters.
* content:
* application/json:
* schema:
* type: object
* properties:
* applications:
* type: array
* items:
* $ref: '#/components/schemas/table'
* examples:
* tables:
* $ref: '#/components/examples/tables'
*/
read.push(
new Endpoint("post", "/tables/search", controller.search).addMiddleware(
nameValidator()
)
)
/** /**
* @openapi * @openapi
* /tables: * /tables:
@ -158,4 +121,43 @@ write.push(new Endpoint("delete", "/tables/:tableId", controller.destroy))
*/ */
read.push(new Endpoint("get", "/tables/:tableId", controller.read)) read.push(new Endpoint("get", "/tables/:tableId", controller.read))
/**
* @openapi
* /tables/search:
* post:
* summary: Search internal and external tables based on their name.
* tags:
* - tables
* parameters:
* - $ref: '#/components/parameters/appId'
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/nameSearch'
* responses:
* 200:
* description: Returns the found tables, based on the search parameters.
* content:
* application/json:
* schema:
* type: object
* required:
* - tables
* properties:
* tables:
* type: array
* items:
* $ref: '#/components/schemas/table'
* examples:
* tables:
* $ref: '#/components/examples/tables'
*/
read.push(
new Endpoint("post", "/tables/search", controller.search).addMiddleware(
nameValidator()
)
)
export default { read, write } export default { read, write }

74
packages/server/src/api/routes/public/tests/compare.spec.js

@ -0,0 +1,74 @@
const jestOpenAPI = require("jest-openapi").default
const generateSchema = require("../../../../../specs/generate")
const setup = require("../../tests/utilities")
const { checkSlashesInUrl } = require("../../../../utilities")
const yamlPath = generateSchema()
jestOpenAPI(yamlPath)
let request = setup.getRequest()
let config = setup.getConfig()
let apiKey, table
beforeAll(async () => {
await config.init()
table = await config.updateTable()
apiKey = await config.generateApiKey()
})
afterAll(setup.afterAll)
async function makeRequest(method, endpoint, body, appId) {
const extraHeaders = {
"x-budibase-api-key": apiKey,
"x-budibase-app-id": appId ? appId : config.getAppId(),
}
const req = request
[method](checkSlashesInUrl(`/api/public/v1/${endpoint}`))
.set(config.defaultHeaders(extraHeaders))
if (body) {
req.send(body)
}
const res = await req.expect("Content-Type", /json/).expect(200)
expect(res.body).toBeDefined()
return res
}
describe("check the applications endpoints", () => {
it("should allow retrieving applications through search", async () => {
const res = await makeRequest("post", "/applications/search")
expect(res).toSatisfyApiSpec()
})
})
describe("check the tables endpoints", () => {
it("should allow retrieving applications through search", async () => {
const res = await makeRequest("post", "/tables/search")
expect(res).toSatisfyApiSpec()
})
})
describe("check the rows endpoints", () => {
it("should allow retrieving applications through search", async () => {
const res = await makeRequest("post", `/tables/${table._id}/rows/search`, {
query: {
},
})
expect(res).toSatisfyApiSpec()
})
})
describe("check the users endpoints", () => {
it("should allow retrieving applications through search", async () => {
const res = await makeRequest("post", "/users/search")
expect(res).toSatisfyApiSpec()
})
})
describe("check the queries endpoints", () => {
it("should allow retrieving applications through search", async () => {
const res = await makeRequest("post", "/queries/search")
expect(res).toSatisfyApiSpec()
})
})

73
packages/server/src/api/routes/public/users.ts

@ -5,40 +5,6 @@ import { nameValidator } from "../utils/validators"
const read = [], const read = [],
write = [] write = []
/**
* @openapi
* /users/search:
* post:
* summary: Search for a user based on their email/username.
* tags:
* - users
* parameters:
* - $ref: '#/components/parameters/appId'
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/nameSearch'
* responses:
* 200:
* description: Returns the found users based on search parameters.
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: '#/components/schemas/user'
* examples:
* users:
* $ref: '#/components/examples/users'
*/
read.push(
new Endpoint("post", "/users/search", controller.search).addMiddleware(
nameValidator()
)
)
/** /**
* @openapi * @openapi
* /users: * /users:
@ -142,4 +108,43 @@ write.push(new Endpoint("delete", "/users/:userId", controller.destroy))
*/ */
read.push(new Endpoint("get", "/users/:userId", controller.read)) read.push(new Endpoint("get", "/users/:userId", controller.read))
/**
* @openapi
* /users/search:
* post:
* summary: Search for a user based on their email/username.
* tags:
* - users
* parameters:
* - $ref: '#/components/parameters/appId'
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/nameSearch'
* responses:
* 200:
* description: Returns the found users based on search parameters.
* content:
* application/json:
* schema:
* type: object
* required:
* - users
* properties:
* users:
* type: array
* items:
* $ref: '#/components/schemas/user'
* examples:
* users:
* $ref: '#/components/examples/users'
*/
read.push(
new Endpoint("post", "/users/search", controller.search).addMiddleware(
nameValidator()
)
)
export default { read, write } export default { read, write }

19
packages/server/src/tests/utilities/TestConfiguration.js

@ -25,6 +25,8 @@ const { createASession } = require("@budibase/backend-core/sessions")
const { user: userCache } = require("@budibase/backend-core/cache") const { user: userCache } = require("@budibase/backend-core/cache")
const newid = require("../../db/newid") const newid = require("../../db/newid")
const context = require("@budibase/backend-core/context") const context = require("@budibase/backend-core/context")
const { generateDevInfoID, SEPARATOR } = require("@budibase/backend-core/db")
const { encrypt } = require("@budibase/backend-core/encryption")
const GLOBAL_USER_ID = "us_uuid1" const GLOBAL_USER_ID = "us_uuid1"
const EMAIL = "babs@babs.com" const EMAIL = "babs@babs.com"
@ -83,6 +85,20 @@ class TestConfiguration {
} }
} }
async generateApiKey(userId = GLOBAL_USER_ID) {
const db = getGlobalDB(TENANT_ID)
const id = generateDevInfoID(userId)
let devInfo
try {
devInfo = await db.get(id)
} catch (err) {
devInfo = { _id: id, userId }
}
devInfo.apiKey = encrypt(`${TENANT_ID}${SEPARATOR}${newid()}`)
await db.put(devInfo)
return devInfo.apiKey
}
async globalUser({ async globalUser({
id = GLOBAL_USER_ID, id = GLOBAL_USER_ID,
builder = true, builder = true,
@ -135,7 +151,7 @@ class TestConfiguration {
cleanup(this.allApps.map(app => app.appId)) cleanup(this.allApps.map(app => app.appId))
} }
defaultHeaders() { defaultHeaders(extras = {}) {
const auth = { const auth = {
userId: GLOBAL_USER_ID, userId: GLOBAL_USER_ID,
sessionId: "sessionid", sessionId: "sessionid",
@ -154,6 +170,7 @@ class TestConfiguration {
`${Cookies.CurrentApp}=${appToken}`, `${Cookies.CurrentApp}=${appToken}`,
], ],
[Headers.CSRF_TOKEN]: CSRF_TOKEN, [Headers.CSRF_TOKEN]: CSRF_TOKEN,
...extras,
} }
if (this.appId) { if (this.appId) {
headers[Headers.APP_ID] = this.appId headers[Headers.APP_ID] = this.appId

1137
packages/server/yarn.lock

File diff suppressed because it is too large
Loading…
Cancel
Save