Merge branch 'master' into BUDI-7580/account_portal_submodule
This commit is contained in:
commit
7b7dc84a8e
|
@ -39,7 +39,15 @@
|
||||||
allowCreator
|
allowCreator
|
||||||
) => {
|
) => {
|
||||||
if (allowedRoles?.length) {
|
if (allowedRoles?.length) {
|
||||||
return roles.filter(role => allowedRoles.includes(role._id))
|
const filteredRoles = roles.filter(role =>
|
||||||
|
allowedRoles.includes(role._id)
|
||||||
|
)
|
||||||
|
return [
|
||||||
|
...filteredRoles,
|
||||||
|
...(allowedRoles.includes(Constants.Roles.CREATOR)
|
||||||
|
? [{ _id: Constants.Roles.CREATOR, name: "Creator", enabled: false }]
|
||||||
|
: []),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
let newRoles = [...roles]
|
let newRoles = [...roles]
|
||||||
|
|
||||||
|
@ -129,8 +137,9 @@
|
||||||
getOptionColour={getColor}
|
getOptionColour={getColor}
|
||||||
getOptionIcon={getIcon}
|
getOptionIcon={getIcon}
|
||||||
isOptionEnabled={option =>
|
isOptionEnabled={option =>
|
||||||
option._id !== Constants.Roles.CREATOR ||
|
(option._id !== Constants.Roles.CREATOR ||
|
||||||
$licensing.perAppBuildersEnabled}
|
$licensing.perAppBuildersEnabled) &&
|
||||||
|
option.enabled !== false}
|
||||||
{placeholder}
|
{placeholder}
|
||||||
{error}
|
{error}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -516,6 +516,13 @@
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const parseRole = user => {
|
||||||
|
if (user.isAdminOrGlobalBuilder) {
|
||||||
|
return Constants.Roles.CREATOR
|
||||||
|
}
|
||||||
|
return user.role
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:keydown={handleKeyDown} />
|
<svelte:window on:keydown={handleKeyDown} />
|
||||||
|
@ -725,7 +732,7 @@
|
||||||
<RoleSelect
|
<RoleSelect
|
||||||
footer={getRoleFooter(user)}
|
footer={getRoleFooter(user)}
|
||||||
placeholder={false}
|
placeholder={false}
|
||||||
value={user.role}
|
value={parseRole(user)}
|
||||||
allowRemove={user.role && !user.group}
|
allowRemove={user.role && !user.group}
|
||||||
allowPublic={false}
|
allowPublic={false}
|
||||||
allowCreator={true}
|
allowCreator={true}
|
||||||
|
@ -744,7 +751,7 @@
|
||||||
autoWidth
|
autoWidth
|
||||||
align="right"
|
align="right"
|
||||||
allowedRoles={user.isAdminOrGlobalBuilder
|
allowedRoles={user.isAdminOrGlobalBuilder
|
||||||
? [Constants.Roles.ADMIN]
|
? [Constants.Roles.CREATOR]
|
||||||
: null}
|
: null}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,128 +11,24 @@ const { PermissionType, PermissionLevel } = permissions
|
||||||
const router: Router = new Router()
|
const router: Router = new Router()
|
||||||
|
|
||||||
router
|
router
|
||||||
/**
|
|
||||||
* @api {get} /api/:sourceId/:rowId/enrich Get an enriched row
|
|
||||||
* @apiName Get an enriched row
|
|
||||||
* @apiGroup rows
|
|
||||||
* @apiPermission table read access
|
|
||||||
* @apiDescription This API is only useful when dealing with rows that have relationships.
|
|
||||||
* Normally when a row is a returned from the API relationships will only have the structure
|
|
||||||
* `{ primaryDisplay: "name", _id: ... }` but this call will return the full related rows
|
|
||||||
* for each relationship instead.
|
|
||||||
*
|
|
||||||
* @apiParam {string} rowId The ID of the row which is to be retrieved and enriched.
|
|
||||||
*
|
|
||||||
* @apiSuccess {object} row The response body will be the enriched row.
|
|
||||||
*/
|
|
||||||
.get(
|
.get(
|
||||||
"/api/:sourceId/:rowId/enrich",
|
"/api/:sourceId/:rowId/enrich",
|
||||||
paramSubResource("sourceId", "rowId"),
|
paramSubResource("sourceId", "rowId"),
|
||||||
authorized(PermissionType.TABLE, PermissionLevel.READ),
|
authorized(PermissionType.TABLE, PermissionLevel.READ),
|
||||||
rowController.fetchEnrichedRow
|
rowController.fetchEnrichedRow
|
||||||
)
|
)
|
||||||
/**
|
|
||||||
* @api {get} /api/:sourceId/rows Get all rows in a table
|
|
||||||
* @apiName Get all rows in a table
|
|
||||||
* @apiGroup rows
|
|
||||||
* @apiPermission table read access
|
|
||||||
* @apiDescription This is a deprecated endpoint that should not be used anymore, instead use the search endpoint.
|
|
||||||
* This endpoint gets all of the rows within the specified table - it is not heavily used
|
|
||||||
* due to its lack of support for pagination. With SQL tables this will retrieve up to a limit and then
|
|
||||||
* will simply stop.
|
|
||||||
*
|
|
||||||
* @apiParam {string} sourceId The ID of the table to retrieve all rows within.
|
|
||||||
*
|
|
||||||
* @apiSuccess {object[]} rows The response body will be an array of all rows found.
|
|
||||||
*/
|
|
||||||
.get(
|
.get(
|
||||||
"/api/:sourceId/rows",
|
"/api/:sourceId/rows",
|
||||||
paramResource("sourceId"),
|
paramResource("sourceId"),
|
||||||
authorized(PermissionType.TABLE, PermissionLevel.READ),
|
authorized(PermissionType.TABLE, PermissionLevel.READ),
|
||||||
rowController.fetch
|
rowController.fetch
|
||||||
)
|
)
|
||||||
/**
|
|
||||||
* @api {get} /api/:sourceId/rows/:rowId Retrieve a single row
|
|
||||||
* @apiName Retrieve a single row
|
|
||||||
* @apiGroup rows
|
|
||||||
* @apiPermission table read access
|
|
||||||
* @apiDescription This endpoint retrieves only the specified row. If you wish to retrieve
|
|
||||||
* a row by anything other than its _id field, use the search endpoint.
|
|
||||||
*
|
|
||||||
* @apiParam {string} sourceId The ID of the table to retrieve a row from.
|
|
||||||
* @apiParam {string} rowId The ID of the row to retrieve.
|
|
||||||
*
|
|
||||||
* @apiSuccess {object} body The response body will be the row that was found.
|
|
||||||
*/
|
|
||||||
.get(
|
.get(
|
||||||
"/api/:sourceId/rows/:rowId",
|
"/api/:sourceId/rows/:rowId",
|
||||||
paramSubResource("sourceId", "rowId"),
|
paramSubResource("sourceId", "rowId"),
|
||||||
authorized(PermissionType.TABLE, PermissionLevel.READ),
|
authorized(PermissionType.TABLE, PermissionLevel.READ),
|
||||||
rowController.find
|
rowController.find
|
||||||
)
|
)
|
||||||
/**
|
|
||||||
* @api {post} /api/:sourceId/search Search for rows in a table
|
|
||||||
* @apiName Search for rows in a table
|
|
||||||
* @apiGroup rows
|
|
||||||
* @apiPermission table read access
|
|
||||||
* @apiDescription This is the primary method of accessing rows in Budibase, the data provider
|
|
||||||
* and data UI in the builder are built atop this. All filtering, sorting and pagination is
|
|
||||||
* handled through this, for internal and external (datasource plus, e.g. SQL) tables.
|
|
||||||
*
|
|
||||||
* @apiParam {string} sourceId The ID of the table to retrieve rows from.
|
|
||||||
*
|
|
||||||
* @apiParam (Body) {boolean} [paginate] If pagination is required then this should be set to true,
|
|
||||||
* defaults to false.
|
|
||||||
* @apiParam (Body) {object} [query] This contains a set of filters which should be applied, if none
|
|
||||||
* specified then the request will be unfiltered. An example with all of the possible query
|
|
||||||
* options has been supplied below.
|
|
||||||
* @apiParam (Body) {number} [limit] This sets a limit for the number of rows that will be returned,
|
|
||||||
* this will be implemented at the database level if supported for performance reasons. This
|
|
||||||
* is useful when paginating to set exactly how many rows per page.
|
|
||||||
* @apiParam (Body) {string} [bookmark] If pagination is enabled then a bookmark will be returned
|
|
||||||
* with each successful search request, this should be supplied back to get the next page.
|
|
||||||
* @apiParam (Body) {object} [sort] If sort is desired this should contain the name of the column to
|
|
||||||
* sort on.
|
|
||||||
* @apiParam (Body) {string} [sortOrder] If sort is enabled then this can be either "descending" or
|
|
||||||
* "ascending" as required.
|
|
||||||
* @apiParam (Body) {string} [sortType] If sort is enabled then you must specify the type of search
|
|
||||||
* being used, either "string" or "number". This is only used for internal tables.
|
|
||||||
*
|
|
||||||
* @apiParamExample {json} Example:
|
|
||||||
* {
|
|
||||||
* "tableId": "ta_70260ff0b85c467ca74364aefc46f26d",
|
|
||||||
* "query": {
|
|
||||||
* "string": {},
|
|
||||||
* "fuzzy": {},
|
|
||||||
* "range": {
|
|
||||||
* "columnName": {
|
|
||||||
* "high": 20,
|
|
||||||
* "low": 10,
|
|
||||||
* }
|
|
||||||
* },
|
|
||||||
* "equal": {
|
|
||||||
* "columnName": "someValue"
|
|
||||||
* },
|
|
||||||
* "notEqual": {},
|
|
||||||
* "empty": {},
|
|
||||||
* "notEmpty": {},
|
|
||||||
* "oneOf": {
|
|
||||||
* "columnName": ["value"]
|
|
||||||
* }
|
|
||||||
* },
|
|
||||||
* "limit": 10,
|
|
||||||
* "sort": "name",
|
|
||||||
* "sortOrder": "descending",
|
|
||||||
* "sortType": "string",
|
|
||||||
* "paginate": true
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @apiSuccess {object[]} rows An array of rows that was found based on the supplied parameters.
|
|
||||||
* @apiSuccess {boolean} hasNextPage If pagination was enabled then this specifies whether or
|
|
||||||
* not there is another page after this request.
|
|
||||||
* @apiSuccess {string} bookmark The bookmark to be sent with the next request to get the next
|
|
||||||
* page.
|
|
||||||
*/
|
|
||||||
.post(
|
.post(
|
||||||
"/api/:sourceId/search",
|
"/api/:sourceId/search",
|
||||||
internalSearchValidator(),
|
internalSearchValidator(),
|
||||||
|
@ -148,30 +44,6 @@ router
|
||||||
authorized(PermissionType.TABLE, PermissionLevel.READ),
|
authorized(PermissionType.TABLE, PermissionLevel.READ),
|
||||||
rowController.search
|
rowController.search
|
||||||
)
|
)
|
||||||
/**
|
|
||||||
* @api {post} /api/:sourceId/rows Creates a new row
|
|
||||||
* @apiName Creates a new row
|
|
||||||
* @apiGroup rows
|
|
||||||
* @apiPermission table write access
|
|
||||||
* @apiDescription This API will create a new row based on the supplied body. If the
|
|
||||||
* body includes an "_id" field then it will update an existing row if the field
|
|
||||||
* links to one. Please note that "_id", "_rev" and "tableId" are fields that are
|
|
||||||
* already used by Budibase tables and cannot be used for columns.
|
|
||||||
*
|
|
||||||
* @apiParam {string} sourceId The ID of the table to save a row to.
|
|
||||||
*
|
|
||||||
* @apiParam (Body) {string} [_id] If the row exists already then an ID for the row must be provided.
|
|
||||||
* @apiParam (Body) {string} [_rev] If working with an existing row for an internal table its revision
|
|
||||||
* must also be provided.
|
|
||||||
* @apiParam (Body) {string} tableId The ID of the table should also be specified in the row body itself.
|
|
||||||
* @apiParam (Body) {any} [any] Any field supplied in the body will be assessed to see if it matches
|
|
||||||
* a column in the specified table. All other fields will be dropped and not stored.
|
|
||||||
*
|
|
||||||
* @apiSuccess {string} _id The ID of the row that was just saved, if it was just created this
|
|
||||||
* is the rows new ID.
|
|
||||||
* @apiSuccess {string} [_rev] If saving to an internal table a revision will also be returned.
|
|
||||||
* @apiSuccess {object} body The contents of the row that was saved will be returned as well.
|
|
||||||
*/
|
|
||||||
.post(
|
.post(
|
||||||
"/api/:sourceId/rows",
|
"/api/:sourceId/rows",
|
||||||
paramResource("sourceId"),
|
paramResource("sourceId"),
|
||||||
|
@ -179,14 +51,6 @@ router
|
||||||
trimViewRowInfo,
|
trimViewRowInfo,
|
||||||
rowController.save
|
rowController.save
|
||||||
)
|
)
|
||||||
/**
|
|
||||||
* @api {patch} /api/:sourceId/rows Updates a row
|
|
||||||
* @apiName Update a row
|
|
||||||
* @apiGroup rows
|
|
||||||
* @apiPermission table write access
|
|
||||||
* @apiDescription This endpoint is identical to the row creation endpoint but instead it will
|
|
||||||
* error if an _id isn't provided, it will only function for existing rows.
|
|
||||||
*/
|
|
||||||
.patch(
|
.patch(
|
||||||
"/api/:sourceId/rows",
|
"/api/:sourceId/rows",
|
||||||
paramResource("sourceId"),
|
paramResource("sourceId"),
|
||||||
|
@ -194,52 +58,12 @@ router
|
||||||
trimViewRowInfo,
|
trimViewRowInfo,
|
||||||
rowController.patch
|
rowController.patch
|
||||||
)
|
)
|
||||||
/**
|
|
||||||
* @api {post} /api/:sourceId/rows/validate Validate inputs for a row
|
|
||||||
* @apiName Validate inputs for a row
|
|
||||||
* @apiGroup rows
|
|
||||||
* @apiPermission table write access
|
|
||||||
* @apiDescription When attempting to save a row you may want to check if the row is valid
|
|
||||||
* given the table schema, this will iterate through all the constraints on the table and
|
|
||||||
* check if the request body is valid.
|
|
||||||
*
|
|
||||||
* @apiParam {string} sourceId The ID of the table the row is to be validated for.
|
|
||||||
*
|
|
||||||
* @apiParam (Body) {any} [any] Any fields provided in the request body will be tested
|
|
||||||
* against the table schema and constraints.
|
|
||||||
*
|
|
||||||
* @apiSuccess {boolean} valid If inputs provided are acceptable within the table schema this
|
|
||||||
* will be true, if it is not then then errors property will be populated.
|
|
||||||
* @apiSuccess {object} [errors] A key value map of information about fields on the input
|
|
||||||
* which do not match the table schema. The key name will be the column names that have breached
|
|
||||||
* the schema.
|
|
||||||
*/
|
|
||||||
.post(
|
.post(
|
||||||
"/api/:sourceId/rows/validate",
|
"/api/:sourceId/rows/validate",
|
||||||
paramResource("sourceId"),
|
paramResource("sourceId"),
|
||||||
authorized(PermissionType.TABLE, PermissionLevel.WRITE),
|
authorized(PermissionType.TABLE, PermissionLevel.WRITE),
|
||||||
rowController.validate
|
rowController.validate
|
||||||
)
|
)
|
||||||
/**
|
|
||||||
* @api {delete} /api/:sourceId/rows Delete rows
|
|
||||||
* @apiName Delete rows
|
|
||||||
* @apiGroup rows
|
|
||||||
* @apiPermission table write access
|
|
||||||
* @apiDescription This endpoint can delete a single row, or delete them in a bulk
|
|
||||||
* fashion.
|
|
||||||
*
|
|
||||||
* @apiParam {string} sourceId The ID of the table the row is to be deleted from.
|
|
||||||
*
|
|
||||||
* @apiParam (Body) {object[]} [rows] If bulk deletion is desired then provide the rows in this
|
|
||||||
* key of the request body that are to be deleted.
|
|
||||||
* @apiParam (Body) {string} [_id] If deleting a single row then provide its ID in this field.
|
|
||||||
* @apiParam (Body) {string} [_rev] If deleting a single row from an internal table then provide its
|
|
||||||
* revision here.
|
|
||||||
*
|
|
||||||
* @apiSuccess {object[]|object} body If deleting bulk then the response body will be an array
|
|
||||||
* of the deleted rows, if deleting a single row then the body will contain a "row" property which
|
|
||||||
* is the deleted row.
|
|
||||||
*/
|
|
||||||
.delete(
|
.delete(
|
||||||
"/api/:sourceId/rows",
|
"/api/:sourceId/rows",
|
||||||
paramResource("sourceId"),
|
paramResource("sourceId"),
|
||||||
|
@ -247,20 +71,6 @@ router
|
||||||
trimViewRowInfo,
|
trimViewRowInfo,
|
||||||
rowController.destroy
|
rowController.destroy
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* @api {post} /api/:sourceId/rows/exportRows Export Rows
|
|
||||||
* @apiName Export rows
|
|
||||||
* @apiGroup rows
|
|
||||||
* @apiPermission table write access
|
|
||||||
* @apiDescription This API can export a number of provided rows
|
|
||||||
*
|
|
||||||
* @apiParam {string} sourceId The ID of the table the row is to be deleted from.
|
|
||||||
*
|
|
||||||
* @apiParam (Body) {object[]} [rows] The row IDs which are to be exported
|
|
||||||
*
|
|
||||||
* @apiSuccess {object[]|object}
|
|
||||||
*/
|
|
||||||
.post(
|
.post(
|
||||||
"/api/:sourceId/rows/exportRows",
|
"/api/:sourceId/rows/exportRows",
|
||||||
paramResource("sourceId"),
|
paramResource("sourceId"),
|
||||||
|
|
|
@ -9,99 +9,13 @@ const { BUILDER, PermissionLevel, PermissionType } = permissions
|
||||||
const router: Router = new Router()
|
const router: Router = new Router()
|
||||||
|
|
||||||
router
|
router
|
||||||
/**
|
|
||||||
* @api {get} /api/tables Fetch all tables
|
|
||||||
* @apiName Fetch all tables
|
|
||||||
* @apiGroup tables
|
|
||||||
* @apiPermission table read access
|
|
||||||
* @apiDescription This endpoint retrieves all of the tables which have been created in
|
|
||||||
* an app. This includes all of the external and internal tables; to tell the difference
|
|
||||||
* between these look for the "type" property on each table, either being "internal" or "external".
|
|
||||||
*
|
|
||||||
* @apiSuccess {object[]} body The response body will be the list of tables that was found - as
|
|
||||||
* this does not take any parameters the only error scenario is no access.
|
|
||||||
*/
|
|
||||||
.get("/api/tables", authorized(BUILDER), tableController.fetch)
|
.get("/api/tables", authorized(BUILDER), tableController.fetch)
|
||||||
/**
|
|
||||||
* @api {get} /api/tables/:id Fetch a single table
|
|
||||||
* @apiName Fetch a single table
|
|
||||||
* @apiGroup tables
|
|
||||||
* @apiPermission table read access
|
|
||||||
* @apiDescription Retrieves a single table this could be be internal or external based on
|
|
||||||
* the provided table ID.
|
|
||||||
*
|
|
||||||
* @apiParam {string} id The ID of the table which is to be retrieved.
|
|
||||||
*
|
|
||||||
* @apiSuccess {object[]} body The response body will be the table that was found.
|
|
||||||
*/
|
|
||||||
.get(
|
.get(
|
||||||
"/api/tables/:tableId",
|
"/api/tables/:tableId",
|
||||||
paramResource("tableId"),
|
paramResource("tableId"),
|
||||||
authorized(PermissionType.TABLE, PermissionLevel.READ, { schema: true }),
|
authorized(PermissionType.TABLE, PermissionLevel.READ, { schema: true }),
|
||||||
tableController.find
|
tableController.find
|
||||||
)
|
)
|
||||||
/**
|
|
||||||
* @api {post} /api/tables Save a table
|
|
||||||
* @apiName Save a table
|
|
||||||
* @apiGroup tables
|
|
||||||
* @apiPermission builder
|
|
||||||
* @apiDescription Create or update a table with this endpoint, this will function for both internal
|
|
||||||
* external tables.
|
|
||||||
*
|
|
||||||
* @apiParam (Body) {string} [_id] If updating an existing table then the ID of the table must be specified.
|
|
||||||
* @apiParam (Body) {string} [_rev] If updating an existing internal table then the revision must also be specified.
|
|
||||||
* @apiParam (Body) {string} type] This should either be "internal" or "external" depending on the table type -
|
|
||||||
* this will default to internal.
|
|
||||||
* @apiParam (Body) {string} [sourceId] If creating an external table then this should be set to the datasource ID. If
|
|
||||||
* building an internal table this does not need to be set, although it will be returned as "bb_internal".
|
|
||||||
* @apiParam (Body) {string} name The name of the table, this will be used in the UI. To rename the table simply
|
|
||||||
* supply the table structure to this endpoint with the name changed.
|
|
||||||
* @apiParam (Body) {object} schema A key value object which has all of the columns in the table as the keys in this
|
|
||||||
* object. For each column a "type" and "constraints" must be specified, with some types requiring further information.
|
|
||||||
* More information about the schema structure can be found in the Typescript definitions.
|
|
||||||
* @apiParam (Body) {string} [primaryDisplay] The name of the column which should be used when displaying rows
|
|
||||||
* from this table as relationships.
|
|
||||||
* @apiParam (Body) {object[]} [indexes] Specifies the search indexes - this is deprecated behaviour with the introduction
|
|
||||||
* of lucene indexes. This functionality is only available for internal tables.
|
|
||||||
* @apiParam (Body) {object} [_rename] If a column is to be renamed then the "old" column name should be set in this
|
|
||||||
* structure, and the "updated", new column name should also be supplied. The schema should also be updated, this field
|
|
||||||
* lets the server know that a field hasn't just been deleted, that the data has moved to a new name, this will fix
|
|
||||||
* the rows in the table. This functionality is only available for internal tables.
|
|
||||||
* @apiParam (Body) {object[]} [rows] When creating a table using a compatible data source, an array of objects to be imported into the new table can be provided.
|
|
||||||
*
|
|
||||||
* @apiParamExample {json} Example:
|
|
||||||
* {
|
|
||||||
* "_id": "ta_05541307fa0f4044abee071ca2a82119",
|
|
||||||
* "_rev": "10-0fbe4e78f69b255d79f1017e2eeef807",
|
|
||||||
* "type": "internal",
|
|
||||||
* "views": {},
|
|
||||||
* "name": "tableName",
|
|
||||||
* "schema": {
|
|
||||||
* "column": {
|
|
||||||
* "type": "string",
|
|
||||||
* "constraints": {
|
|
||||||
* "type": "string",
|
|
||||||
* "length": {
|
|
||||||
* "maximum": null
|
|
||||||
* },
|
|
||||||
* "presence": false
|
|
||||||
* },
|
|
||||||
* "name": "column"
|
|
||||||
* },
|
|
||||||
* },
|
|
||||||
* "primaryDisplay": "column",
|
|
||||||
* "indexes": [],
|
|
||||||
* "sourceId": "bb_internal",
|
|
||||||
* "_rename": {
|
|
||||||
* "old": "columnName",
|
|
||||||
* "updated": "newColumnName",
|
|
||||||
* },
|
|
||||||
* "rows": []
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @apiSuccess {object} table The response body will contain the table structure after being cleaned up and
|
|
||||||
* saved to the database.
|
|
||||||
*/
|
|
||||||
.post(
|
.post(
|
||||||
"/api/tables",
|
"/api/tables",
|
||||||
// allows control over updating a table
|
// allows control over updating a table
|
||||||
|
@ -125,41 +39,12 @@ router
|
||||||
authorized(BUILDER),
|
authorized(BUILDER),
|
||||||
tableController.validateExistingTableImport
|
tableController.validateExistingTableImport
|
||||||
)
|
)
|
||||||
/**
|
|
||||||
* @api {post} /api/tables/:tableId/:revId Delete a table
|
|
||||||
* @apiName Delete a table
|
|
||||||
* @apiGroup tables
|
|
||||||
* @apiPermission builder
|
|
||||||
* @apiDescription This endpoint will delete a table and all of its associated data, for this reason it is
|
|
||||||
* quite dangerous - it will work for internal and external tables.
|
|
||||||
*
|
|
||||||
* @apiParam {string} tableId The ID of the table which is to be deleted.
|
|
||||||
* @apiParam {string} [revId] If deleting an internal table then the revision must also be supplied (_rev), for
|
|
||||||
* external tables this can simply be set to anything, e.g. "external".
|
|
||||||
*
|
|
||||||
* @apiSuccess {string} message A message stating that the table was deleted successfully.
|
|
||||||
*/
|
|
||||||
.delete(
|
.delete(
|
||||||
"/api/tables/:tableId/:revId",
|
"/api/tables/:tableId/:revId",
|
||||||
paramResource("tableId"),
|
paramResource("tableId"),
|
||||||
authorized(BUILDER),
|
authorized(BUILDER),
|
||||||
tableController.destroy
|
tableController.destroy
|
||||||
)
|
)
|
||||||
/**
|
|
||||||
* @api {post} /api/tables/:tableId/:revId Import CSV to existing table
|
|
||||||
* @apiName Import CSV to existing table
|
|
||||||
* @apiGroup tables
|
|
||||||
* @apiPermission builder
|
|
||||||
* @apiDescription This endpoint will import data to existing tables, internal or external. It is used in combination
|
|
||||||
* with the CSV validation endpoint. Take the output of the CSV validation endpoint and pass it to this endpoint to
|
|
||||||
* import the data; please note this will only import fields that already exist on the table/match the type.
|
|
||||||
*
|
|
||||||
* @apiParam {string} tableId The ID of the table which the data should be imported to.
|
|
||||||
*
|
|
||||||
* @apiParam (Body) {object[]} rows An array of objects representing the rows to be imported, key-value pairs not matching the table schema will be ignored.
|
|
||||||
*
|
|
||||||
* @apiSuccess {string} message A message stating that the data was imported successfully.
|
|
||||||
*/
|
|
||||||
.post(
|
.post(
|
||||||
"/api/tables/:tableId/import",
|
"/api/tables/:tableId/import",
|
||||||
paramResource("tableId"),
|
paramResource("tableId"),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { events } from "@budibase/backend-core"
|
import { events } from "@budibase/backend-core"
|
||||||
import { generator } from "@budibase/backend-core/tests"
|
import { generator } from "@budibase/backend-core/tests"
|
||||||
import { structures, TestConfiguration, mocks } from "../../../../tests"
|
import { structures, TestConfiguration, mocks } from "../../../../tests"
|
||||||
import { UserGroup } from "@budibase/types"
|
import { User, UserGroup } from "@budibase/types"
|
||||||
|
|
||||||
mocks.licenses.useGroups()
|
mocks.licenses.useGroups()
|
||||||
|
|
||||||
|
@ -231,4 +231,39 @@ describe("/api/global/groups", () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("with global builder role", () => {
|
||||||
|
let builder: User
|
||||||
|
let group: UserGroup
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
builder = await config.createUser({
|
||||||
|
builder: { global: true },
|
||||||
|
admin: { global: false },
|
||||||
|
})
|
||||||
|
await config.createSession(builder)
|
||||||
|
|
||||||
|
let resp = await config.api.groups.saveGroup(
|
||||||
|
structures.groups.UserGroup()
|
||||||
|
)
|
||||||
|
group = resp.body as UserGroup
|
||||||
|
})
|
||||||
|
|
||||||
|
it("find should return 200", async () => {
|
||||||
|
await config.withUser(builder, async () => {
|
||||||
|
await config.api.groups.searchUsers(group._id!, {
|
||||||
|
emailSearch: `user1`,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("update should return 200", async () => {
|
||||||
|
await config.withUser(builder, async () => {
|
||||||
|
await config.api.groups.updateGroupUsers(group._id!, {
|
||||||
|
add: [builder._id!],
|
||||||
|
remove: [],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -190,6 +190,16 @@ class TestConfiguration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async withUser(user: User, f: () => Promise<void>) {
|
||||||
|
const oldUser = this.user
|
||||||
|
this.user = user
|
||||||
|
try {
|
||||||
|
await f()
|
||||||
|
} finally {
|
||||||
|
this.user = oldUser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
authHeaders(user: User) {
|
authHeaders(user: User) {
|
||||||
const authToken: AuthToken = {
|
const authToken: AuthToken = {
|
||||||
userId: user._id!,
|
userId: user._id!,
|
||||||
|
@ -257,9 +267,10 @@ class TestConfiguration {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async createUser(user?: User) {
|
async createUser(opts?: Partial<User>) {
|
||||||
if (!user) {
|
let user = structures.users.user()
|
||||||
user = structures.users.user()
|
if (user) {
|
||||||
|
user = { ...user, ...opts }
|
||||||
}
|
}
|
||||||
const response = await this._req(user, null, controllers.users.save)
|
const response = await this._req(user, null, controllers.users.save)
|
||||||
const body = response as SaveUserResponse
|
const body = response as SaveUserResponse
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { generator } from "@budibase/backend-core/tests"
|
import { generator } from "@budibase/backend-core/tests"
|
||||||
import { db } from "@budibase/backend-core"
|
import { db } from "@budibase/backend-core"
|
||||||
import { UserGroupRoles } from "@budibase/types"
|
import { UserGroup as UserGroupType, UserGroupRoles } from "@budibase/types"
|
||||||
|
|
||||||
export const UserGroup = () => {
|
export function UserGroup(): UserGroupType {
|
||||||
const appsCount = generator.integer({ min: 0, max: 3 })
|
const appsCount = generator.integer({ min: 0, max: 3 })
|
||||||
const roles = Array.from({ length: appsCount }).reduce(
|
const roles = Array.from({ length: appsCount }).reduce(
|
||||||
(p: UserGroupRoles, v) => {
|
(p: UserGroupRoles, v) => {
|
||||||
|
@ -14,13 +14,11 @@ export const UserGroup = () => {
|
||||||
{}
|
{}
|
||||||
)
|
)
|
||||||
|
|
||||||
let group = {
|
return {
|
||||||
apps: [],
|
|
||||||
color: generator.color(),
|
color: generator.color(),
|
||||||
icon: generator.word(),
|
icon: generator.word(),
|
||||||
name: generator.word(),
|
name: generator.word(),
|
||||||
roles: roles,
|
roles: roles,
|
||||||
users: [],
|
users: [],
|
||||||
}
|
}
|
||||||
return group
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue