Merge branch 'develop' into fix/test-flakiness
This commit is contained in:
commit
4ea61140e8
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "2.9.30-alpha.3",
|
"version": "2.9.30-alpha.4",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
import env from "../environment"
|
import env from "../environment"
|
||||||
import * as eventHelpers from "./events"
|
import * as eventHelpers from "./events"
|
||||||
import * as accounts from "../accounts"
|
import * as accounts from "../accounts"
|
||||||
|
import * as accountSdk from "../accounts"
|
||||||
import * as cache from "../cache"
|
import * as cache from "../cache"
|
||||||
import { getIdentity, getTenantId, getGlobalDB } from "../context"
|
import { getGlobalDB, getIdentity, getTenantId } from "../context"
|
||||||
import * as dbUtils from "../db"
|
import * as dbUtils from "../db"
|
||||||
import { EmailUnavailableError, HTTPError } from "../errors"
|
import { EmailUnavailableError, HTTPError } from "../errors"
|
||||||
import * as platform from "../platform"
|
import * as platform from "../platform"
|
||||||
import * as sessions from "../security/sessions"
|
import * as sessions from "../security/sessions"
|
||||||
import * as usersCore from "./users"
|
import * as usersCore from "./users"
|
||||||
import {
|
import {
|
||||||
|
Account,
|
||||||
AllDocsResponse,
|
AllDocsResponse,
|
||||||
BulkUserCreated,
|
BulkUserCreated,
|
||||||
BulkUserDeleted,
|
BulkUserDeleted,
|
||||||
|
isSSOAccount,
|
||||||
|
isSSOUser,
|
||||||
RowResponse,
|
RowResponse,
|
||||||
SaveUserOpts,
|
SaveUserOpts,
|
||||||
User,
|
User,
|
||||||
Account,
|
|
||||||
isSSOUser,
|
|
||||||
isSSOAccount,
|
|
||||||
UserStatus,
|
UserStatus,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import * as accountSdk from "../accounts"
|
|
||||||
import {
|
import {
|
||||||
validateUniqueUser,
|
|
||||||
getAccountHolderFromUserIds,
|
getAccountHolderFromUserIds,
|
||||||
isAdmin,
|
isAdmin,
|
||||||
|
validateUniqueUser,
|
||||||
} from "./utils"
|
} from "./utils"
|
||||||
import { searchExistingEmails } from "./lookup"
|
import { searchExistingEmails } from "./lookup"
|
||||||
import { hash } from "../utils"
|
import { hash } from "../utils"
|
||||||
|
@ -179,6 +179,14 @@ export class UserDB {
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async bulkGet(userIds: string[]) {
|
||||||
|
return await usersCore.bulkGetGlobalUsersById(userIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async bulkUpdate(users: User[]) {
|
||||||
|
return await usersCore.bulkUpdateGlobalUsers(users)
|
||||||
|
}
|
||||||
|
|
||||||
static async save(user: User, opts: SaveUserOpts = {}): Promise<User> {
|
static async save(user: User, opts: SaveUserOpts = {}): Promise<User> {
|
||||||
// default booleans to true
|
// default booleans to true
|
||||||
if (opts.hashPassword == null) {
|
if (opts.hashPassword == null) {
|
||||||
|
|
|
@ -86,6 +86,10 @@ export const useAuditLogs = () => {
|
||||||
return useFeature(Feature.AUDIT_LOGS)
|
return useFeature(Feature.AUDIT_LOGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const usePublicApiUserRoles = () => {
|
||||||
|
return useFeature(Feature.USER_ROLE_PUBLIC_API)
|
||||||
|
}
|
||||||
|
|
||||||
export const useScimIntegration = () => {
|
export const useScimIntegration = () => {
|
||||||
return useFeature(Feature.SCIM)
|
return useFeature(Feature.SCIM)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1521,7 +1521,7 @@
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"builder": {
|
"builder": {
|
||||||
"description": "Describes if the user is a builder user or not.",
|
"description": "Describes if the user is a builder user or not. This field can only be set on a business or enterprise license.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"global": {
|
"global": {
|
||||||
|
@ -1531,7 +1531,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"description": "Describes if the user is an admin user or not.",
|
"description": "Describes if the user is an admin user or not. This field can only be set on a business or enterprise license.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"global": {
|
"global": {
|
||||||
|
@ -1541,7 +1541,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roles": {
|
"roles": {
|
||||||
"description": "Contains the roles of the user per app (assuming they are not a builder user).",
|
"description": "Contains the roles of the user per app (assuming they are not a builder user). This field can only be set on a business or enterprise license.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -1588,7 +1588,7 @@
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"builder": {
|
"builder": {
|
||||||
"description": "Describes if the user is a builder user or not.",
|
"description": "Describes if the user is a builder user or not. This field can only be set on a business or enterprise license.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"global": {
|
"global": {
|
||||||
|
@ -1598,7 +1598,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"description": "Describes if the user is an admin user or not.",
|
"description": "Describes if the user is an admin user or not. This field can only be set on a business or enterprise license.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"global": {
|
"global": {
|
||||||
|
@ -1608,7 +1608,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roles": {
|
"roles": {
|
||||||
"description": "Contains the roles of the user per app (assuming they are not a builder user).",
|
"description": "Contains the roles of the user per app (assuming they are not a builder user). This field can only be set on a business or enterprise license.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -1667,7 +1667,7 @@
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"builder": {
|
"builder": {
|
||||||
"description": "Describes if the user is a builder user or not.",
|
"description": "Describes if the user is a builder user or not. This field can only be set on a business or enterprise license.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"global": {
|
"global": {
|
||||||
|
@ -1677,7 +1677,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"description": "Describes if the user is an admin user or not.",
|
"description": "Describes if the user is an admin user or not. This field can only be set on a business or enterprise license.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"global": {
|
"global": {
|
||||||
|
@ -1687,7 +1687,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roles": {
|
"roles": {
|
||||||
"description": "Contains the roles of the user per app (assuming they are not a builder user).",
|
"description": "Contains the roles of the user per app (assuming they are not a builder user). This field can only be set on a business or enterprise license.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -1833,6 +1833,137 @@
|
||||||
"required": [
|
"required": [
|
||||||
"name"
|
"name"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"rolesAssign": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"appBuilder": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"appId": {
|
||||||
|
"description": "The app that the users should have app builder privileges granted for.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Allow setting users to builders per app.",
|
||||||
|
"required": [
|
||||||
|
"appId"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"builder": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Add/remove global builder permissions from the list of users."
|
||||||
|
},
|
||||||
|
"admin": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Add/remove global admin permissions from the list of users."
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"roleId": {
|
||||||
|
"description": "The role ID, such as BASIC, ADMIN or a custom role ID.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"appId": {
|
||||||
|
"description": "The app that the role relates to.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Add/remove a per-app role, such as BASIC, ADMIN etc.",
|
||||||
|
"required": [
|
||||||
|
"roleId",
|
||||||
|
"appId"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"userIds": {
|
||||||
|
"description": "The user IDs to be updated to add/remove the specified roles.",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"userIds"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rolesUnAssign": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"appBuilder": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"appId": {
|
||||||
|
"description": "The app that the users should have app builder privileges granted for.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Allow setting users to builders per app.",
|
||||||
|
"required": [
|
||||||
|
"appId"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"builder": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Add/remove global builder permissions from the list of users."
|
||||||
|
},
|
||||||
|
"admin": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Add/remove global admin permissions from the list of users."
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"roleId": {
|
||||||
|
"description": "The role ID, such as BASIC, ADMIN or a custom role ID.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"appId": {
|
||||||
|
"description": "The app that the role relates to.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Add/remove a per-app role, such as BASIC, ADMIN etc.",
|
||||||
|
"required": [
|
||||||
|
"roleId",
|
||||||
|
"appId"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"userIds": {
|
||||||
|
"description": "The user IDs to be updated to add/remove the specified roles.",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"userIds"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rolesOutput": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"userIds": {
|
||||||
|
"description": "The updated users' IDs",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"userIds"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -2186,6 +2317,70 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/roles/assign": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "roleAssign",
|
||||||
|
"summary": "Assign a role to a list of users",
|
||||||
|
"description": "This is a business/enterprise only endpoint",
|
||||||
|
"tags": [
|
||||||
|
"roles"
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/rolesAssign"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Returns a list of updated user IDs",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/rolesOutput"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/roles/unassign": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "roleUnAssign",
|
||||||
|
"summary": "Un-assign a role from a list of users",
|
||||||
|
"description": "This is a business/enterprise only endpoint",
|
||||||
|
"tags": [
|
||||||
|
"roles"
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/rolesUnAssign"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Returns a list of updated user IDs",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/rolesOutput"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/tables/{tableId}/rows": {
|
"/tables/{tableId}/rows": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "rowCreate",
|
"operationId": "rowCreate",
|
||||||
|
|
|
@ -1297,7 +1297,8 @@ components:
|
||||||
login.
|
login.
|
||||||
type: boolean
|
type: boolean
|
||||||
builder:
|
builder:
|
||||||
description: Describes if the user is a builder user or not.
|
description: Describes if the user is a builder user or not. This field can only
|
||||||
|
be set on a business or enterprise license.
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
global:
|
global:
|
||||||
|
@ -1305,7 +1306,8 @@ components:
|
||||||
system.
|
system.
|
||||||
type: boolean
|
type: boolean
|
||||||
admin:
|
admin:
|
||||||
description: Describes if the user is an admin user or not.
|
description: Describes if the user is an admin user or not. This field can only
|
||||||
|
be set on a business or enterprise license.
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
global:
|
global:
|
||||||
|
@ -1313,7 +1315,8 @@ components:
|
||||||
type: boolean
|
type: boolean
|
||||||
roles:
|
roles:
|
||||||
description: Contains the roles of the user per app (assuming they are not a
|
description: Contains the roles of the user per app (assuming they are not a
|
||||||
builder user).
|
builder user). This field can only be set on a business or
|
||||||
|
enterprise license.
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: string
|
type: string
|
||||||
|
@ -1352,7 +1355,8 @@ components:
|
||||||
login.
|
login.
|
||||||
type: boolean
|
type: boolean
|
||||||
builder:
|
builder:
|
||||||
description: Describes if the user is a builder user or not.
|
description: Describes if the user is a builder user or not. This field can only
|
||||||
|
be set on a business or enterprise license.
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
global:
|
global:
|
||||||
|
@ -1360,7 +1364,8 @@ components:
|
||||||
system.
|
system.
|
||||||
type: boolean
|
type: boolean
|
||||||
admin:
|
admin:
|
||||||
description: Describes if the user is an admin user or not.
|
description: Describes if the user is an admin user or not. This field can only
|
||||||
|
be set on a business or enterprise license.
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
global:
|
global:
|
||||||
|
@ -1368,7 +1373,8 @@ components:
|
||||||
type: boolean
|
type: boolean
|
||||||
roles:
|
roles:
|
||||||
description: Contains the roles of the user per app (assuming they are not a
|
description: Contains the roles of the user per app (assuming they are not a
|
||||||
builder user).
|
builder user). This field can only be set on a business or
|
||||||
|
enterprise license.
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: string
|
type: string
|
||||||
|
@ -1415,7 +1421,8 @@ components:
|
||||||
login.
|
login.
|
||||||
type: boolean
|
type: boolean
|
||||||
builder:
|
builder:
|
||||||
description: Describes if the user is a builder user or not.
|
description: Describes if the user is a builder user or not. This field can only
|
||||||
|
be set on a business or enterprise license.
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
global:
|
global:
|
||||||
|
@ -1423,7 +1430,8 @@ components:
|
||||||
system.
|
system.
|
||||||
type: boolean
|
type: boolean
|
||||||
admin:
|
admin:
|
||||||
description: Describes if the user is an admin user or not.
|
description: Describes if the user is an admin user or not. This field can only
|
||||||
|
be set on a business or enterprise license.
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
global:
|
global:
|
||||||
|
@ -1431,7 +1439,8 @@ components:
|
||||||
type: boolean
|
type: boolean
|
||||||
roles:
|
roles:
|
||||||
description: Contains the roles of the user per app (assuming they are not a
|
description: Contains the roles of the user per app (assuming they are not a
|
||||||
builder user).
|
builder user). This field can only be set on a business or
|
||||||
|
enterprise license.
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: string
|
type: string
|
||||||
|
@ -1547,6 +1556,99 @@ components:
|
||||||
insensitive starts with match.
|
insensitive starts with match.
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
|
rolesAssign:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
appBuilder:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
appId:
|
||||||
|
description: The app that the users should have app builder privileges granted
|
||||||
|
for.
|
||||||
|
type: string
|
||||||
|
description: Allow setting users to builders per app.
|
||||||
|
required:
|
||||||
|
- appId
|
||||||
|
builder:
|
||||||
|
type: boolean
|
||||||
|
description: Add/remove global builder permissions from the list of users.
|
||||||
|
admin:
|
||||||
|
type: boolean
|
||||||
|
description: Add/remove global admin permissions from the list of users.
|
||||||
|
role:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
roleId:
|
||||||
|
description: The role ID, such as BASIC, ADMIN or a custom role ID.
|
||||||
|
type: string
|
||||||
|
appId:
|
||||||
|
description: The app that the role relates to.
|
||||||
|
type: string
|
||||||
|
description: Add/remove a per-app role, such as BASIC, ADMIN etc.
|
||||||
|
required:
|
||||||
|
- roleId
|
||||||
|
- appId
|
||||||
|
userIds:
|
||||||
|
description: The user IDs to be updated to add/remove the specified roles.
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- userIds
|
||||||
|
rolesUnAssign:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
appBuilder:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
appId:
|
||||||
|
description: The app that the users should have app builder privileges granted
|
||||||
|
for.
|
||||||
|
type: string
|
||||||
|
description: Allow setting users to builders per app.
|
||||||
|
required:
|
||||||
|
- appId
|
||||||
|
builder:
|
||||||
|
type: boolean
|
||||||
|
description: Add/remove global builder permissions from the list of users.
|
||||||
|
admin:
|
||||||
|
type: boolean
|
||||||
|
description: Add/remove global admin permissions from the list of users.
|
||||||
|
role:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
roleId:
|
||||||
|
description: The role ID, such as BASIC, ADMIN or a custom role ID.
|
||||||
|
type: string
|
||||||
|
appId:
|
||||||
|
description: The app that the role relates to.
|
||||||
|
type: string
|
||||||
|
description: Add/remove a per-app role, such as BASIC, ADMIN etc.
|
||||||
|
required:
|
||||||
|
- roleId
|
||||||
|
- appId
|
||||||
|
userIds:
|
||||||
|
description: The user IDs to be updated to add/remove the specified roles.
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- userIds
|
||||||
|
rolesOutput:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
userIds:
|
||||||
|
description: The updated users' IDs
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- userIds
|
||||||
|
required:
|
||||||
|
- data
|
||||||
security:
|
security:
|
||||||
- ApiKeyAuth: []
|
- ApiKeyAuth: []
|
||||||
paths:
|
paths:
|
||||||
|
@ -1757,6 +1859,46 @@ paths:
|
||||||
examples:
|
examples:
|
||||||
queries:
|
queries:
|
||||||
$ref: "#/components/examples/queries"
|
$ref: "#/components/examples/queries"
|
||||||
|
/roles/assign:
|
||||||
|
post:
|
||||||
|
operationId: roleAssign
|
||||||
|
summary: Assign a role to a list of users
|
||||||
|
description: This is a business/enterprise only endpoint
|
||||||
|
tags:
|
||||||
|
- roles
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/rolesAssign"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Returns a list of updated user IDs
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/rolesOutput"
|
||||||
|
/roles/unassign:
|
||||||
|
post:
|
||||||
|
operationId: roleUnAssign
|
||||||
|
summary: Un-assign a role from a list of users
|
||||||
|
description: This is a business/enterprise only endpoint
|
||||||
|
tags:
|
||||||
|
- roles
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/rolesUnAssign"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Returns a list of updated user IDs
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/rolesOutput"
|
||||||
"/tables/{tableId}/rows":
|
"/tables/{tableId}/rows":
|
||||||
post:
|
post:
|
||||||
operationId: rowCreate
|
operationId: rowCreate
|
||||||
|
|
|
@ -5,6 +5,7 @@ import query from "./query"
|
||||||
import user from "./user"
|
import user from "./user"
|
||||||
import metrics from "./metrics"
|
import metrics from "./metrics"
|
||||||
import misc from "./misc"
|
import misc from "./misc"
|
||||||
|
import roles from "./roles"
|
||||||
|
|
||||||
export const examples = {
|
export const examples = {
|
||||||
...application.getExamples(),
|
...application.getExamples(),
|
||||||
|
@ -23,4 +24,5 @@ export const schemas = {
|
||||||
...query.getSchemas(),
|
...query.getSchemas(),
|
||||||
...user.getSchemas(),
|
...user.getSchemas(),
|
||||||
...misc.getSchemas(),
|
...misc.getSchemas(),
|
||||||
|
...roles.getSchemas(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { object } from "./utils"
|
||||||
|
import Resource from "./utils/Resource"
|
||||||
|
|
||||||
|
const roleSchema = object(
|
||||||
|
{
|
||||||
|
appBuilder: object(
|
||||||
|
{
|
||||||
|
appId: {
|
||||||
|
description:
|
||||||
|
"The app that the users should have app builder privileges granted for.",
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ description: "Allow setting users to builders per app." }
|
||||||
|
),
|
||||||
|
builder: {
|
||||||
|
type: "boolean",
|
||||||
|
description:
|
||||||
|
"Add/remove global builder permissions from the list of users.",
|
||||||
|
},
|
||||||
|
admin: {
|
||||||
|
type: "boolean",
|
||||||
|
description:
|
||||||
|
"Add/remove global admin permissions from the list of users.",
|
||||||
|
},
|
||||||
|
role: object(
|
||||||
|
{
|
||||||
|
roleId: {
|
||||||
|
description: "The role ID, such as BASIC, ADMIN or a custom role ID.",
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
appId: {
|
||||||
|
description: "The app that the role relates to.",
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ description: "Add/remove a per-app role, such as BASIC, ADMIN etc." }
|
||||||
|
),
|
||||||
|
userIds: {
|
||||||
|
description:
|
||||||
|
"The user IDs to be updated to add/remove the specified roles.",
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ required: ["userIds"] }
|
||||||
|
)
|
||||||
|
|
||||||
|
export default new Resource().setSchemas({
|
||||||
|
rolesAssign: roleSchema,
|
||||||
|
rolesUnAssign: roleSchema,
|
||||||
|
rolesOutput: object({
|
||||||
|
data: object({
|
||||||
|
userIds: {
|
||||||
|
description: "The updated users' IDs",
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
|
@ -58,7 +58,8 @@ const userSchema = object(
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
},
|
},
|
||||||
builder: {
|
builder: {
|
||||||
description: "Describes if the user is a builder user or not.",
|
description:
|
||||||
|
"Describes if the user is a builder user or not. This field can only be set on a business or enterprise license.",
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
global: {
|
global: {
|
||||||
|
@ -69,7 +70,8 @@ const userSchema = object(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
admin: {
|
admin: {
|
||||||
description: "Describes if the user is an admin user or not.",
|
description:
|
||||||
|
"Describes if the user is an admin user or not. This field can only be set on a business or enterprise license.",
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
global: {
|
global: {
|
||||||
|
@ -81,7 +83,7 @@ const userSchema = object(
|
||||||
},
|
},
|
||||||
roles: {
|
roles: {
|
||||||
description:
|
description:
|
||||||
"Contains the roles of the user per app (assuming they are not a builder user).",
|
"Contains the roles of the user per app (assuming they are not a builder user). This field can only be set on a business or enterprise license.",
|
||||||
type: "object",
|
type: "object",
|
||||||
additionalProperties: {
|
additionalProperties: {
|
||||||
type: "string",
|
type: "string",
|
||||||
|
|
|
@ -3,6 +3,8 @@ import { search as stringSearch, addRev } from "./utils"
|
||||||
import * as controller from "../application"
|
import * as controller from "../application"
|
||||||
import * as deployController from "../deploy"
|
import * as deployController from "../deploy"
|
||||||
import { Application } from "../../../definitions/common"
|
import { Application } from "../../../definitions/common"
|
||||||
|
import { UserCtx } from "@budibase/types"
|
||||||
|
import { Next } from "koa"
|
||||||
|
|
||||||
function fixAppID(app: Application, params: any) {
|
function fixAppID(app: Application, params: any) {
|
||||||
if (!params) {
|
if (!params) {
|
||||||
|
@ -14,7 +16,7 @@ function fixAppID(app: Application, params: any) {
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setResponseApp(ctx: any) {
|
async function setResponseApp(ctx: UserCtx) {
|
||||||
const appId = ctx.body?.appId
|
const appId = ctx.body?.appId
|
||||||
if (appId && (!ctx.params || !ctx.params.appId)) {
|
if (appId && (!ctx.params || !ctx.params.appId)) {
|
||||||
ctx.params = { appId }
|
ctx.params = { appId }
|
||||||
|
@ -28,14 +30,14 @@ async function setResponseApp(ctx: any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function search(ctx: any, next: any) {
|
export async function search(ctx: UserCtx, next: Next) {
|
||||||
const { name } = ctx.request.body
|
const { name } = ctx.request.body
|
||||||
const apps = await dbCore.getAllApps({ all: true })
|
const apps = await dbCore.getAllApps({ all: true })
|
||||||
ctx.body = stringSearch(apps, name)
|
ctx.body = stringSearch(apps, name)
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function create(ctx: any, next: any) {
|
export async function create(ctx: UserCtx, next: Next) {
|
||||||
if (!ctx.request.body || !ctx.request.body.useTemplate) {
|
if (!ctx.request.body || !ctx.request.body.useTemplate) {
|
||||||
ctx.request.body = {
|
ctx.request.body = {
|
||||||
useTemplate: false,
|
useTemplate: false,
|
||||||
|
@ -47,14 +49,14 @@ export async function create(ctx: any, next: any) {
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function read(ctx: any, next: any) {
|
export async function read(ctx: UserCtx, next: Next) {
|
||||||
await context.doInAppContext(ctx.params.appId, async () => {
|
await context.doInAppContext(ctx.params.appId, async () => {
|
||||||
await setResponseApp(ctx)
|
await setResponseApp(ctx)
|
||||||
await next()
|
await next()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function update(ctx: any, next: any) {
|
export async function update(ctx: UserCtx, next: Next) {
|
||||||
ctx.request.body = await addRev(fixAppID(ctx.request.body, ctx.params))
|
ctx.request.body = await addRev(fixAppID(ctx.request.body, ctx.params))
|
||||||
await context.doInAppContext(ctx.params.appId, async () => {
|
await context.doInAppContext(ctx.params.appId, async () => {
|
||||||
await controller.update(ctx)
|
await controller.update(ctx)
|
||||||
|
@ -63,7 +65,7 @@ export async function update(ctx: any, next: any) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function destroy(ctx: any, next: any) {
|
export async function destroy(ctx: UserCtx, next: Next) {
|
||||||
await context.doInAppContext(ctx.params.appId, async () => {
|
await context.doInAppContext(ctx.params.appId, async () => {
|
||||||
// get the app before deleting it
|
// get the app before deleting it
|
||||||
await setResponseApp(ctx)
|
await setResponseApp(ctx)
|
||||||
|
@ -75,14 +77,14 @@ export async function destroy(ctx: any, next: any) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function unpublish(ctx: any, next: any) {
|
export async function unpublish(ctx: UserCtx, next: Next) {
|
||||||
await context.doInAppContext(ctx.params.appId, async () => {
|
await context.doInAppContext(ctx.params.appId, async () => {
|
||||||
await controller.unpublish(ctx)
|
await controller.unpublish(ctx)
|
||||||
await next()
|
await next()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function publish(ctx: any, next: any) {
|
export async function publish(ctx: UserCtx, next: Next) {
|
||||||
await context.doInAppContext(ctx.params.appId, async () => {
|
await context.doInAppContext(ctx.params.appId, async () => {
|
||||||
await deployController.publishApp(ctx)
|
await deployController.publishApp(ctx)
|
||||||
await next()
|
await next()
|
||||||
|
|
|
@ -16,6 +16,10 @@ export type CreateRowParams = components["schemas"]["row"]
|
||||||
export type User = components["schemas"]["userOutput"]["data"]
|
export type User = components["schemas"]["userOutput"]["data"]
|
||||||
export type CreateUserParams = components["schemas"]["user"]
|
export type CreateUserParams = components["schemas"]["user"]
|
||||||
|
|
||||||
|
export type RoleAssignRequest = components["schemas"]["rolesAssign"]
|
||||||
|
export type RoleUnAssignRequest = components["schemas"]["rolesUnAssign"]
|
||||||
|
export type RoleAssignmentResponse = components["schemas"]["rolesOutput"]
|
||||||
|
|
||||||
export type SearchInputParams =
|
export type SearchInputParams =
|
||||||
| components["schemas"]["nameSearch"]
|
| components["schemas"]["nameSearch"]
|
||||||
| components["schemas"]["rowSearch"]
|
| components["schemas"]["rowSearch"]
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import { search as stringSearch } from "./utils"
|
import { search as stringSearch } from "./utils"
|
||||||
import * as queryController from "../query"
|
import * as queryController from "../query"
|
||||||
|
import { UserCtx } from "@budibase/types"
|
||||||
|
import { Next } from "koa"
|
||||||
|
|
||||||
export async function search(ctx: any, next: any) {
|
export async function search(ctx: UserCtx, next: Next) {
|
||||||
await queryController.fetch(ctx)
|
await queryController.fetch(ctx)
|
||||||
const { name } = ctx.request.body
|
const { name } = ctx.request.body
|
||||||
ctx.body = stringSearch(ctx.body, name)
|
ctx.body = stringSearch(ctx.body, name)
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function execute(ctx: any, next: any) {
|
export async function execute(ctx: UserCtx, next: Next) {
|
||||||
// don't wrap this, already returns "data"
|
// don't wrap this, already returns "data"
|
||||||
await queryController.executeV2(ctx)
|
await queryController.executeV2(ctx)
|
||||||
await next()
|
await next()
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { UserCtx } from "@budibase/types"
|
||||||
|
import { Next } from "koa"
|
||||||
|
import { sdk } from "@budibase/pro"
|
||||||
|
import {
|
||||||
|
RoleAssignmentResponse,
|
||||||
|
RoleUnAssignRequest,
|
||||||
|
RoleAssignRequest,
|
||||||
|
} from "./mapping/types"
|
||||||
|
|
||||||
|
async function assign(
|
||||||
|
ctx: UserCtx<RoleAssignRequest, RoleAssignmentResponse>,
|
||||||
|
next: Next
|
||||||
|
) {
|
||||||
|
const { userIds, ...assignmentProps } = ctx.request.body
|
||||||
|
await sdk.publicApi.roles.assign(userIds, assignmentProps)
|
||||||
|
ctx.body = { data: { userIds } }
|
||||||
|
await next()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function unAssign(
|
||||||
|
ctx: UserCtx<RoleUnAssignRequest, RoleAssignmentResponse>,
|
||||||
|
next: Next
|
||||||
|
) {
|
||||||
|
const { userIds, ...unAssignmentProps } = ctx.request.body
|
||||||
|
await sdk.publicApi.roles.unAssign(userIds, unAssignmentProps)
|
||||||
|
ctx.body = { data: { userIds } }
|
||||||
|
await next()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
assign,
|
||||||
|
unAssign,
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
import * as rowController from "../row"
|
import * as rowController from "../row"
|
||||||
import { addRev } from "./utils"
|
import { addRev } from "./utils"
|
||||||
import { Row } from "@budibase/types"
|
import { Row, UserCtx } from "@budibase/types"
|
||||||
import { convertBookmark } from "../../../utilities"
|
import { convertBookmark } from "../../../utilities"
|
||||||
|
import { Next } from "koa"
|
||||||
|
|
||||||
// makes sure that the user doesn't need to pass in the type, tableId or _id params for
|
// makes sure that the user doesn't need to pass in the type, tableId or _id params for
|
||||||
// the call to be correct
|
// the call to be correct
|
||||||
|
@ -21,7 +22,7 @@ export function fixRow(row: Row, params: any) {
|
||||||
return row
|
return row
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function search(ctx: any, next: any) {
|
export async function search(ctx: UserCtx, next: Next) {
|
||||||
let { sort, paginate, bookmark, limit, query } = ctx.request.body
|
let { sort, paginate, bookmark, limit, query } = ctx.request.body
|
||||||
// update the body to the correct format of the internal search
|
// update the body to the correct format of the internal search
|
||||||
if (!sort) {
|
if (!sort) {
|
||||||
|
@ -40,25 +41,25 @@ export async function search(ctx: any, next: any) {
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function create(ctx: any, next: any) {
|
export async function create(ctx: UserCtx, next: Next) {
|
||||||
ctx.request.body = fixRow(ctx.request.body, ctx.params)
|
ctx.request.body = fixRow(ctx.request.body, ctx.params)
|
||||||
await rowController.save(ctx)
|
await rowController.save(ctx)
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function read(ctx: any, next: any) {
|
export async function read(ctx: UserCtx, next: Next) {
|
||||||
await rowController.fetchEnrichedRow(ctx)
|
await rowController.fetchEnrichedRow(ctx)
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function update(ctx: any, next: any) {
|
export async function update(ctx: UserCtx, next: Next) {
|
||||||
const { tableId } = ctx.params
|
const { tableId } = ctx.params
|
||||||
ctx.request.body = await addRev(fixRow(ctx.request.body, ctx.params), tableId)
|
ctx.request.body = await addRev(fixRow(ctx.request.body, ctx.params), tableId)
|
||||||
await rowController.save(ctx)
|
await rowController.save(ctx)
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function destroy(ctx: any, next: any) {
|
export async function destroy(ctx: UserCtx, next: Next) {
|
||||||
const { tableId } = ctx.params
|
const { tableId } = ctx.params
|
||||||
// set the body as expected, with the _id and _rev fields
|
// set the body as expected, with the _id and _rev fields
|
||||||
ctx.request.body = await addRev(
|
ctx.request.body = await addRev(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { search as stringSearch, addRev } from "./utils"
|
import { search as stringSearch, addRev } from "./utils"
|
||||||
import * as controller from "../table"
|
import * as controller from "../table"
|
||||||
import { Table } from "@budibase/types"
|
import { Table, UserCtx } from "@budibase/types"
|
||||||
|
import { Next } from "koa"
|
||||||
|
|
||||||
function fixTable(table: Table, params: any) {
|
function fixTable(table: Table, params: any) {
|
||||||
if (!params || !table) {
|
if (!params || !table) {
|
||||||
|
@ -15,24 +16,24 @@ function fixTable(table: Table, params: any) {
|
||||||
return table
|
return table
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function search(ctx: any, next: any) {
|
export async function search(ctx: UserCtx, next: Next) {
|
||||||
const { name } = ctx.request.body
|
const { name } = ctx.request.body
|
||||||
await controller.fetch(ctx)
|
await controller.fetch(ctx)
|
||||||
ctx.body = stringSearch(ctx.body, name)
|
ctx.body = stringSearch(ctx.body, name)
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function create(ctx: any, next: any) {
|
export async function create(ctx: UserCtx, next: Next) {
|
||||||
await controller.save(ctx)
|
await controller.save(ctx)
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function read(ctx: any, next: any) {
|
export async function read(ctx: UserCtx, next: Next) {
|
||||||
await controller.find(ctx)
|
await controller.find(ctx)
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function update(ctx: any, next: any) {
|
export async function update(ctx: UserCtx, next: Next) {
|
||||||
ctx.request.body = await addRev(
|
ctx.request.body = await addRev(
|
||||||
fixTable(ctx.request.body, ctx.params),
|
fixTable(ctx.request.body, ctx.params),
|
||||||
ctx.params.tableId
|
ctx.params.tableId
|
||||||
|
@ -41,7 +42,7 @@ export async function update(ctx: any, next: any) {
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function destroy(ctx: any, next: any) {
|
export async function destroy(ctx: UserCtx, next: Next) {
|
||||||
await controller.destroy(ctx)
|
await controller.destroy(ctx)
|
||||||
ctx.body = ctx.table
|
ctx.body = ctx.table
|
||||||
await next()
|
await next()
|
||||||
|
|
|
@ -7,16 +7,18 @@ import {
|
||||||
import { publicApiUserFix } from "../../../utilities/users"
|
import { publicApiUserFix } from "../../../utilities/users"
|
||||||
import { db as dbCore } from "@budibase/backend-core"
|
import { db as dbCore } from "@budibase/backend-core"
|
||||||
import { search as stringSearch } from "./utils"
|
import { search as stringSearch } from "./utils"
|
||||||
import { BBContext, User } from "@budibase/types"
|
import { UserCtx, User } from "@budibase/types"
|
||||||
|
import { Next } from "koa"
|
||||||
|
import { sdk } from "@budibase/pro"
|
||||||
|
|
||||||
function isLoggedInUser(ctx: BBContext, user: User) {
|
function isLoggedInUser(ctx: UserCtx, user: User) {
|
||||||
const loggedInId = ctx.user?._id
|
const loggedInId = ctx.user?._id
|
||||||
const globalUserId = dbCore.getGlobalIDFromUserMetadataID(loggedInId!)
|
const globalUserId = dbCore.getGlobalIDFromUserMetadataID(loggedInId!)
|
||||||
// check both just incase
|
// check both just incase
|
||||||
return globalUserId === user._id || loggedInId === user._id
|
return globalUserId === user._id || loggedInId === user._id
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUser(ctx: BBContext, userId?: string) {
|
function getUser(ctx: UserCtx, userId?: string) {
|
||||||
if (userId) {
|
if (userId) {
|
||||||
ctx.params = { userId }
|
ctx.params = { userId }
|
||||||
} else if (!ctx.params?.userId) {
|
} else if (!ctx.params?.userId) {
|
||||||
|
@ -25,42 +27,38 @@ function getUser(ctx: BBContext, userId?: string) {
|
||||||
return readGlobalUser(ctx)
|
return readGlobalUser(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function search(ctx: BBContext, next: any) {
|
export async function search(ctx: UserCtx, next: Next) {
|
||||||
const { name } = ctx.request.body
|
const { name } = ctx.request.body
|
||||||
const users = await allGlobalUsers(ctx)
|
const users = await allGlobalUsers(ctx)
|
||||||
ctx.body = stringSearch(users, name, "email")
|
ctx.body = stringSearch(users, name, "email")
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function create(ctx: BBContext, next: any) {
|
export async function create(ctx: UserCtx, next: Next) {
|
||||||
const response = await saveGlobalUser(publicApiUserFix(ctx))
|
ctx = publicApiUserFix(await sdk.publicApi.users.roleCheck(ctx))
|
||||||
|
const response = await saveGlobalUser(ctx)
|
||||||
ctx.body = await getUser(ctx, response._id)
|
ctx.body = await getUser(ctx, response._id)
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function read(ctx: BBContext, next: any) {
|
export async function read(ctx: UserCtx, next: Next) {
|
||||||
ctx.body = await readGlobalUser(ctx)
|
ctx.body = await readGlobalUser(ctx)
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function update(ctx: BBContext, next: any) {
|
export async function update(ctx: UserCtx, next: Next) {
|
||||||
const user = await readGlobalUser(ctx)
|
const user = await readGlobalUser(ctx)
|
||||||
ctx.request.body = {
|
ctx.request.body = {
|
||||||
...ctx.request.body,
|
...ctx.request.body,
|
||||||
_rev: user._rev,
|
_rev: user._rev,
|
||||||
}
|
}
|
||||||
// disallow updating your own role - always overwrite with DB roles
|
ctx = publicApiUserFix(await sdk.publicApi.users.roleCheck(ctx, user))
|
||||||
if (isLoggedInUser(ctx, user)) {
|
const response = await saveGlobalUser(ctx)
|
||||||
ctx.request.body.builder = user.builder
|
|
||||||
ctx.request.body.admin = user.admin
|
|
||||||
ctx.request.body.roles = user.roles
|
|
||||||
}
|
|
||||||
const response = await saveGlobalUser(publicApiUserFix(ctx))
|
|
||||||
ctx.body = await getUser(ctx, response._id)
|
ctx.body = await getUser(ctx, response._id)
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function destroy(ctx: BBContext, next: any) {
|
export async function destroy(ctx: UserCtx, next: Next) {
|
||||||
const user = await getUser(ctx)
|
const user = await getUser(ctx)
|
||||||
// disallow deleting yourself
|
// disallow deleting yourself
|
||||||
if (isLoggedInUser(ctx, user)) {
|
if (isLoggedInUser(ctx, user)) {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
EmptyFilterOption,
|
EmptyFilterOption,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import sdk from "../../../sdk"
|
import sdk from "../../../sdk"
|
||||||
|
import * as utils from "./utils"
|
||||||
import { dataFilters } from "@budibase/shared-core"
|
import { dataFilters } from "@budibase/shared-core"
|
||||||
|
|
||||||
export async function handleRequest(
|
export async function handleRequest(
|
||||||
|
@ -52,7 +53,7 @@ export async function handleRequest(
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function patch(ctx: UserCtx<PatchRowRequest, PatchRowResponse>) {
|
export async function patch(ctx: UserCtx<PatchRowRequest, PatchRowResponse>) {
|
||||||
const tableId = ctx.params.tableId
|
const tableId = utils.getTableId(ctx)
|
||||||
const { _id, ...rowData } = ctx.request.body
|
const { _id, ...rowData } = ctx.request.body
|
||||||
|
|
||||||
const validateResult = await sdk.rows.utils.validate({
|
const validateResult = await sdk.rows.utils.validate({
|
||||||
|
@ -79,7 +80,7 @@ export async function patch(ctx: UserCtx<PatchRowRequest, PatchRowResponse>) {
|
||||||
|
|
||||||
export async function save(ctx: UserCtx) {
|
export async function save(ctx: UserCtx) {
|
||||||
const inputs = ctx.request.body
|
const inputs = ctx.request.body
|
||||||
const tableId = ctx.params.tableId
|
const tableId = utils.getTableId(ctx)
|
||||||
const validateResult = await sdk.rows.utils.validate({
|
const validateResult = await sdk.rows.utils.validate({
|
||||||
row: inputs,
|
row: inputs,
|
||||||
tableId,
|
tableId,
|
||||||
|
@ -107,12 +108,12 @@ export async function save(ctx: UserCtx) {
|
||||||
|
|
||||||
export async function find(ctx: UserCtx) {
|
export async function find(ctx: UserCtx) {
|
||||||
const id = ctx.params.rowId
|
const id = ctx.params.rowId
|
||||||
const tableId = ctx.params.tableId
|
const tableId = utils.getTableId(ctx)
|
||||||
return sdk.rows.external.getRow(tableId, id)
|
return sdk.rows.external.getRow(tableId, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function destroy(ctx: UserCtx) {
|
export async function destroy(ctx: UserCtx) {
|
||||||
const tableId = ctx.params.tableId
|
const tableId = utils.getTableId(ctx)
|
||||||
const _id = ctx.request.body._id
|
const _id = ctx.request.body._id
|
||||||
const { row } = (await handleRequest(Operation.DELETE, tableId, {
|
const { row } = (await handleRequest(Operation.DELETE, tableId, {
|
||||||
id: breakRowIdField(_id),
|
id: breakRowIdField(_id),
|
||||||
|
@ -123,7 +124,7 @@ export async function destroy(ctx: UserCtx) {
|
||||||
|
|
||||||
export async function bulkDestroy(ctx: UserCtx) {
|
export async function bulkDestroy(ctx: UserCtx) {
|
||||||
const { rows } = ctx.request.body
|
const { rows } = ctx.request.body
|
||||||
const tableId = ctx.params.tableId
|
const tableId = utils.getTableId(ctx)
|
||||||
let promises: Promise<Row[] | { row: Row; table: Table }>[] = []
|
let promises: Promise<Row[] | { row: Row; table: Table }>[] = []
|
||||||
for (let row of rows) {
|
for (let row of rows) {
|
||||||
promises.push(
|
promises.push(
|
||||||
|
@ -139,7 +140,7 @@ export async function bulkDestroy(ctx: UserCtx) {
|
||||||
|
|
||||||
export async function fetchEnrichedRow(ctx: UserCtx) {
|
export async function fetchEnrichedRow(ctx: UserCtx) {
|
||||||
const id = ctx.params.rowId
|
const id = ctx.params.rowId
|
||||||
const tableId = ctx.params.tableId
|
const tableId = utils.getTableId(ctx)
|
||||||
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||||
const datasource: Datasource = await sdk.datasources.get(datasourceId!)
|
const datasource: Datasource = await sdk.datasources.get(datasourceId!)
|
||||||
if (!tableName) {
|
if (!tableName) {
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
import controller from "../../controllers/public/roles"
|
||||||
|
import Endpoint from "./utils/Endpoint"
|
||||||
|
|
||||||
|
const write = []
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /roles/assign:
|
||||||
|
* post:
|
||||||
|
* operationId: roleAssign
|
||||||
|
* summary: Assign a role to a list of users
|
||||||
|
* description: This is a business/enterprise only endpoint
|
||||||
|
* tags:
|
||||||
|
* - roles
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/rolesAssign'
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Returns a list of updated user IDs
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/rolesOutput'
|
||||||
|
*/
|
||||||
|
write.push(new Endpoint("post", "/roles/assign", controller.assign))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /roles/unassign:
|
||||||
|
* post:
|
||||||
|
* operationId: roleUnAssign
|
||||||
|
* summary: Un-assign a role from a list of users
|
||||||
|
* description: This is a business/enterprise only endpoint
|
||||||
|
* tags:
|
||||||
|
* - roles
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/rolesUnAssign'
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Returns a list of updated user IDs
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/rolesOutput'
|
||||||
|
*/
|
||||||
|
write.push(new Endpoint("post", "/roles/unassign", controller.unAssign))
|
||||||
|
|
||||||
|
export default { write, read: [] }
|
|
@ -1,38 +0,0 @@
|
||||||
const setup = require("../../tests/utilities")
|
|
||||||
const { generateMakeRequest } = require("./utils")
|
|
||||||
|
|
||||||
const workerRequests = require("../../../../utilities/workerRequests")
|
|
||||||
|
|
||||||
let config = setup.getConfig()
|
|
||||||
let apiKey, globalUser, makeRequest
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
await config.init()
|
|
||||||
globalUser = await config.globalUser()
|
|
||||||
apiKey = await config.generateApiKey(globalUser._id)
|
|
||||||
makeRequest = generateMakeRequest(apiKey)
|
|
||||||
workerRequests.readGlobalUser.mockReturnValue(globalUser)
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(setup.afterAll)
|
|
||||||
|
|
||||||
describe("check user endpoints", () => {
|
|
||||||
it("should not allow a user to update their own roles", async () => {
|
|
||||||
const res = await makeRequest("put", `/users/${globalUser._id}`, {
|
|
||||||
...globalUser,
|
|
||||||
roles: {
|
|
||||||
"app_1": "ADMIN",
|
|
||||||
}
|
|
||||||
})
|
|
||||||
expect(workerRequests.saveGlobalUser.mock.lastCall[0].body.data.roles["app_1"]).toBeUndefined()
|
|
||||||
expect(res.status).toBe(200)
|
|
||||||
expect(res.body.data.roles["app_1"]).toBeUndefined()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should not allow a user to delete themselves", async () => {
|
|
||||||
const res = await makeRequest("delete", `/users/${globalUser._id}`)
|
|
||||||
expect(res.status).toBe(405)
|
|
||||||
expect(workerRequests.deleteGlobalUser.mock.lastCall).toBeUndefined()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
import * as setup from "../../tests/utilities"
|
||||||
|
import { generateMakeRequest, MakeRequestResponse } from "./utils"
|
||||||
|
import { User } from "@budibase/types"
|
||||||
|
import { mocks } from "@budibase/backend-core/tests"
|
||||||
|
|
||||||
|
import * as workerRequests from "../../../../utilities/workerRequests"
|
||||||
|
|
||||||
|
const mockedWorkerReq = jest.mocked(workerRequests)
|
||||||
|
|
||||||
|
let config = setup.getConfig()
|
||||||
|
let apiKey: string, globalUser: User, makeRequest: MakeRequestResponse
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await config.init()
|
||||||
|
globalUser = await config.globalUser()
|
||||||
|
apiKey = await config.generateApiKey(globalUser._id)
|
||||||
|
makeRequest = generateMakeRequest(apiKey)
|
||||||
|
mockedWorkerReq.readGlobalUser.mockImplementation(() =>
|
||||||
|
Promise.resolve(globalUser)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(setup.afterAll)
|
||||||
|
|
||||||
|
function base() {
|
||||||
|
return {
|
||||||
|
tenantId: config.getTenantId(),
|
||||||
|
firstName: "Test",
|
||||||
|
lastName: "Test",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMock() {
|
||||||
|
mockedWorkerReq.readGlobalUser.mockImplementation(ctx => ctx.request.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("check user endpoints", () => {
|
||||||
|
it("should not allow a user to update their own roles", async () => {
|
||||||
|
const res = await makeRequest("put", `/users/${globalUser._id}`, {
|
||||||
|
...globalUser,
|
||||||
|
roles: {
|
||||||
|
app_1: "ADMIN",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(
|
||||||
|
mockedWorkerReq.saveGlobalUser.mock.lastCall?.[0].body.data.roles["app_1"]
|
||||||
|
).toBeUndefined()
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
expect(res.body.data.roles["app_1"]).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should not allow a user to delete themselves", async () => {
|
||||||
|
const res = await makeRequest("delete", `/users/${globalUser._id}`)
|
||||||
|
expect(res.status).toBe(405)
|
||||||
|
expect(mockedWorkerReq.deleteGlobalUser.mock.lastCall).toBeUndefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("no user role update in free", () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
updateMock()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should not allow 'roles' to be updated", async () => {
|
||||||
|
const res = await makeRequest("post", "/users", {
|
||||||
|
...base(),
|
||||||
|
roles: { app_a: "BASIC" },
|
||||||
|
})
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
expect(res.body.data.roles["app_a"]).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should not allow 'admin' to be updated", async () => {
|
||||||
|
const res = await makeRequest("post", "/users", {
|
||||||
|
...base(),
|
||||||
|
admin: { global: true },
|
||||||
|
})
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
expect(res.body.data.admin).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should not allow 'builder' to be updated", async () => {
|
||||||
|
const res = await makeRequest("post", "/users", {
|
||||||
|
...base(),
|
||||||
|
builder: { global: true },
|
||||||
|
})
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
expect(res.body.data.builder).toBeUndefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("no user role update in business", () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
updateMock()
|
||||||
|
mocks.licenses.usePublicApiUserRoles()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should allow 'roles' to be updated", async () => {
|
||||||
|
const res = await makeRequest("post", "/users", {
|
||||||
|
...base(),
|
||||||
|
roles: { app_a: "BASIC" },
|
||||||
|
})
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
expect(res.body.data.roles["app_a"]).toBe("BASIC")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should allow 'admin' to be updated", async () => {
|
||||||
|
mocks.licenses.usePublicApiUserRoles()
|
||||||
|
const res = await makeRequest("post", "/users", {
|
||||||
|
...base(),
|
||||||
|
admin: { global: true },
|
||||||
|
})
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
expect(res.body.data.admin.global).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should allow 'builder' to be updated", async () => {
|
||||||
|
mocks.licenses.usePublicApiUserRoles()
|
||||||
|
const res = await makeRequest("post", "/users", {
|
||||||
|
...base(),
|
||||||
|
builder: { global: true },
|
||||||
|
})
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
expect(res.body.data.builder.global).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
|
@ -34,6 +34,14 @@ export interface paths {
|
||||||
/** Based on query properties (currently only name) search for queries. */
|
/** Based on query properties (currently only name) search for queries. */
|
||||||
post: operations["querySearch"];
|
post: operations["querySearch"];
|
||||||
};
|
};
|
||||||
|
"/roles/assign": {
|
||||||
|
/** This is a business/enterprise only endpoint */
|
||||||
|
post: operations["roleAssign"];
|
||||||
|
};
|
||||||
|
"/roles/unassign": {
|
||||||
|
/** This is a business/enterprise only endpoint */
|
||||||
|
post: operations["roleUnAssign"];
|
||||||
|
};
|
||||||
"/tables/{tableId}/rows": {
|
"/tables/{tableId}/rows": {
|
||||||
/** Creates a row within the specified table. */
|
/** Creates a row within the specified table. */
|
||||||
post: operations["rowCreate"];
|
post: operations["rowCreate"];
|
||||||
|
@ -256,7 +264,8 @@ export interface components {
|
||||||
| "auto"
|
| "auto"
|
||||||
| "json"
|
| "json"
|
||||||
| "internal"
|
| "internal"
|
||||||
| "barcodeqr";
|
| "barcodeqr"
|
||||||
|
| "bigint";
|
||||||
/** @description A constraint can be applied to the column which will be validated against when a row is saved. */
|
/** @description A constraint can be applied to the column which will be validated against when a row is saved. */
|
||||||
constraints?: {
|
constraints?: {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
|
@ -362,7 +371,8 @@ export interface components {
|
||||||
| "auto"
|
| "auto"
|
||||||
| "json"
|
| "json"
|
||||||
| "internal"
|
| "internal"
|
||||||
| "barcodeqr";
|
| "barcodeqr"
|
||||||
|
| "bigint";
|
||||||
/** @description A constraint can be applied to the column which will be validated against when a row is saved. */
|
/** @description A constraint can be applied to the column which will be validated against when a row is saved. */
|
||||||
constraints?: {
|
constraints?: {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
|
@ -470,7 +480,8 @@ export interface components {
|
||||||
| "auto"
|
| "auto"
|
||||||
| "json"
|
| "json"
|
||||||
| "internal"
|
| "internal"
|
||||||
| "barcodeqr";
|
| "barcodeqr"
|
||||||
|
| "bigint";
|
||||||
/** @description A constraint can be applied to the column which will be validated against when a row is saved. */
|
/** @description A constraint can be applied to the column which will be validated against when a row is saved. */
|
||||||
constraints?: {
|
constraints?: {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
|
@ -577,17 +588,17 @@ export interface components {
|
||||||
lastName?: string;
|
lastName?: string;
|
||||||
/** @description If set to true forces the user to reset their password on first login. */
|
/** @description If set to true forces the user to reset their password on first login. */
|
||||||
forceResetPassword?: boolean;
|
forceResetPassword?: boolean;
|
||||||
/** @description Describes if the user is a builder user or not. */
|
/** @description Describes if the user is a builder user or not. This field can only be set on a business or enterprise license. */
|
||||||
builder?: {
|
builder?: {
|
||||||
/** @description If set to true the user will be able to build any app in the system. */
|
/** @description If set to true the user will be able to build any app in the system. */
|
||||||
global?: boolean;
|
global?: boolean;
|
||||||
};
|
};
|
||||||
/** @description Describes if the user is an admin user or not. */
|
/** @description Describes if the user is an admin user or not. This field can only be set on a business or enterprise license. */
|
||||||
admin?: {
|
admin?: {
|
||||||
/** @description If set to true the user will be able to administrate the system. */
|
/** @description If set to true the user will be able to administrate the system. */
|
||||||
global?: boolean;
|
global?: boolean;
|
||||||
};
|
};
|
||||||
/** @description Contains the roles of the user per app (assuming they are not a builder user). */
|
/** @description Contains the roles of the user per app (assuming they are not a builder user). This field can only be set on a business or enterprise license. */
|
||||||
roles: { [key: string]: string };
|
roles: { [key: string]: string };
|
||||||
};
|
};
|
||||||
userOutput: {
|
userOutput: {
|
||||||
|
@ -607,17 +618,17 @@ export interface components {
|
||||||
lastName?: string;
|
lastName?: string;
|
||||||
/** @description If set to true forces the user to reset their password on first login. */
|
/** @description If set to true forces the user to reset their password on first login. */
|
||||||
forceResetPassword?: boolean;
|
forceResetPassword?: boolean;
|
||||||
/** @description Describes if the user is a builder user or not. */
|
/** @description Describes if the user is a builder user or not. This field can only be set on a business or enterprise license. */
|
||||||
builder?: {
|
builder?: {
|
||||||
/** @description If set to true the user will be able to build any app in the system. */
|
/** @description If set to true the user will be able to build any app in the system. */
|
||||||
global?: boolean;
|
global?: boolean;
|
||||||
};
|
};
|
||||||
/** @description Describes if the user is an admin user or not. */
|
/** @description Describes if the user is an admin user or not. This field can only be set on a business or enterprise license. */
|
||||||
admin?: {
|
admin?: {
|
||||||
/** @description If set to true the user will be able to administrate the system. */
|
/** @description If set to true the user will be able to administrate the system. */
|
||||||
global?: boolean;
|
global?: boolean;
|
||||||
};
|
};
|
||||||
/** @description Contains the roles of the user per app (assuming they are not a builder user). */
|
/** @description Contains the roles of the user per app (assuming they are not a builder user). This field can only be set on a business or enterprise license. */
|
||||||
roles: { [key: string]: string };
|
roles: { [key: string]: string };
|
||||||
/** @description The ID of the user. */
|
/** @description The ID of the user. */
|
||||||
_id: string;
|
_id: string;
|
||||||
|
@ -640,17 +651,17 @@ export interface components {
|
||||||
lastName?: string;
|
lastName?: string;
|
||||||
/** @description If set to true forces the user to reset their password on first login. */
|
/** @description If set to true forces the user to reset their password on first login. */
|
||||||
forceResetPassword?: boolean;
|
forceResetPassword?: boolean;
|
||||||
/** @description Describes if the user is a builder user or not. */
|
/** @description Describes if the user is a builder user or not. This field can only be set on a business or enterprise license. */
|
||||||
builder?: {
|
builder?: {
|
||||||
/** @description If set to true the user will be able to build any app in the system. */
|
/** @description If set to true the user will be able to build any app in the system. */
|
||||||
global?: boolean;
|
global?: boolean;
|
||||||
};
|
};
|
||||||
/** @description Describes if the user is an admin user or not. */
|
/** @description Describes if the user is an admin user or not. This field can only be set on a business or enterprise license. */
|
||||||
admin?: {
|
admin?: {
|
||||||
/** @description If set to true the user will be able to administrate the system. */
|
/** @description If set to true the user will be able to administrate the system. */
|
||||||
global?: boolean;
|
global?: boolean;
|
||||||
};
|
};
|
||||||
/** @description Contains the roles of the user per app (assuming they are not a builder user). */
|
/** @description Contains the roles of the user per app (assuming they are not a builder user). This field can only be set on a business or enterprise license. */
|
||||||
roles: { [key: string]: string };
|
roles: { [key: string]: string };
|
||||||
/** @description The ID of the user. */
|
/** @description The ID of the user. */
|
||||||
_id: string;
|
_id: string;
|
||||||
|
@ -712,6 +723,52 @@ export interface components {
|
||||||
/** @description The name to be used when searching - this will be used in a case insensitive starts with match. */
|
/** @description The name to be used when searching - this will be used in a case insensitive starts with match. */
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
rolesAssign: {
|
||||||
|
/** @description Allow setting users to builders per app. */
|
||||||
|
appBuilder?: {
|
||||||
|
/** @description The app that the users should have app builder privileges granted for. */
|
||||||
|
appId: string;
|
||||||
|
};
|
||||||
|
/** @description Add/remove global builder permissions from the list of users. */
|
||||||
|
builder?: boolean;
|
||||||
|
/** @description Add/remove global admin permissions from the list of users. */
|
||||||
|
admin?: boolean;
|
||||||
|
/** @description Add/remove a per-app role, such as BASIC, ADMIN etc. */
|
||||||
|
role?: {
|
||||||
|
/** @description The role ID, such as BASIC, ADMIN or a custom role ID. */
|
||||||
|
roleId: string;
|
||||||
|
/** @description The app that the role relates to. */
|
||||||
|
appId: string;
|
||||||
|
};
|
||||||
|
/** @description The user IDs to be updated to add/remove the specified roles. */
|
||||||
|
userIds: string[];
|
||||||
|
};
|
||||||
|
rolesUnAssign: {
|
||||||
|
/** @description Allow setting users to builders per app. */
|
||||||
|
appBuilder?: {
|
||||||
|
/** @description The app that the users should have app builder privileges granted for. */
|
||||||
|
appId: string;
|
||||||
|
};
|
||||||
|
/** @description Add/remove global builder permissions from the list of users. */
|
||||||
|
builder?: boolean;
|
||||||
|
/** @description Add/remove global admin permissions from the list of users. */
|
||||||
|
admin?: boolean;
|
||||||
|
/** @description Add/remove a per-app role, such as BASIC, ADMIN etc. */
|
||||||
|
role?: {
|
||||||
|
/** @description The role ID, such as BASIC, ADMIN or a custom role ID. */
|
||||||
|
roleId: string;
|
||||||
|
/** @description The app that the role relates to. */
|
||||||
|
appId: string;
|
||||||
|
};
|
||||||
|
/** @description The user IDs to be updated to add/remove the specified roles. */
|
||||||
|
userIds: string[];
|
||||||
|
};
|
||||||
|
rolesOutput: {
|
||||||
|
data: {
|
||||||
|
/** @description The updated users' IDs */
|
||||||
|
userIds: string[];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
parameters: {
|
parameters: {
|
||||||
/** @description The ID of the table which this request is targeting. */
|
/** @description The ID of the table which this request is targeting. */
|
||||||
|
@ -907,6 +964,38 @@ export interface operations {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
/** This is a business/enterprise only endpoint */
|
||||||
|
roleAssign: {
|
||||||
|
responses: {
|
||||||
|
/** Returns a list of updated user IDs */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["rolesOutput"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["rolesAssign"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** This is a business/enterprise only endpoint */
|
||||||
|
roleUnAssign: {
|
||||||
|
responses: {
|
||||||
|
/** Returns a list of updated user IDs */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["rolesOutput"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["rolesUnAssign"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
/** Creates a row within the specified table. */
|
/** Creates a row within the specified table. */
|
||||||
rowCreate: {
|
rowCreate: {
|
||||||
parameters: {
|
parameters: {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { InternalTables } from "../db/utils"
|
import { InternalTables } from "../db/utils"
|
||||||
import { getGlobalUser } from "./global"
|
import { getGlobalUser } from "./global"
|
||||||
import { context, db as dbCore, roles } from "@budibase/backend-core"
|
import { context, roles } from "@budibase/backend-core"
|
||||||
import { BBContext } from "@budibase/types"
|
import { UserCtx } from "@budibase/types"
|
||||||
|
|
||||||
export async function getFullUser(ctx: BBContext, userId: string) {
|
export async function getFullUser(ctx: UserCtx, userId: string) {
|
||||||
const global = await getGlobalUser(userId)
|
const global = await getGlobalUser(userId)
|
||||||
let metadata: any = {}
|
let metadata: any = {}
|
||||||
|
|
||||||
|
@ -29,21 +29,12 @@ export async function getFullUser(ctx: BBContext, userId: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function publicApiUserFix(ctx: BBContext) {
|
export function publicApiUserFix(ctx: UserCtx) {
|
||||||
if (!ctx.request.body) {
|
if (!ctx.request.body) {
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
if (!ctx.request.body._id && ctx.params.userId) {
|
if (!ctx.request.body._id && ctx.params.userId) {
|
||||||
ctx.request.body._id = ctx.params.userId
|
ctx.request.body._id = ctx.params.userId
|
||||||
}
|
}
|
||||||
if (!ctx.request.body.roles) {
|
|
||||||
ctx.request.body.roles = {}
|
|
||||||
} else {
|
|
||||||
const newRoles: { [key: string]: any } = {}
|
|
||||||
for (let [appId, role] of Object.entries(ctx.request.body.roles)) {
|
|
||||||
newRoles[dbCore.getProdAppID(appId)] = role
|
|
||||||
}
|
|
||||||
ctx.request.body.roles = newRoles
|
|
||||||
}
|
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ export enum Feature {
|
||||||
SYNC_AUTOMATIONS = "syncAutomations",
|
SYNC_AUTOMATIONS = "syncAutomations",
|
||||||
APP_BUILDERS = "appBuilders",
|
APP_BUILDERS = "appBuilders",
|
||||||
OFFLINE = "offline",
|
OFFLINE = "offline",
|
||||||
|
USER_ROLE_PUBLIC_API = "userRolePublicApi",
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PlanFeatures = { [key in PlanType]: Feature[] | undefined }
|
export type PlanFeatures = { [key in PlanType]: Feature[] | undefined }
|
||||||
|
|
Loading…
Reference in New Issue