Merge pull request #8954 from Budibase/api-tests-user-management

APItests for user management, permissions and app specific roles
This commit is contained in:
Pedro Silva 2022-12-19 14:52:12 +00:00 committed by GitHub
commit 17e87ed054
12 changed files with 987 additions and 25 deletions

View File

@ -13,12 +13,13 @@ export default class AppApi {
constructor(apiClient: InternalAPIClient) { constructor(apiClient: InternalAPIClient) {
this.api = apiClient this.api = apiClient
} }
// TODO Fix the fetch apps to receive an optional number of apps and compare if the received app is more or less.
// each possible scenario should have its own method.
async fetchEmptyAppList(): Promise<[Response, Application[]]> { async fetchEmptyAppList(): Promise<[Response, Application[]]> {
const response = await this.api.get(`/applications?status=all`) const response = await this.api.get(`/applications?status=all`)
const json = await response.json() const json = await response.json()
expect(response).toHaveStatusCode(200) expect(response).toHaveStatusCode(200)
expect(json.length).toEqual(0) expect(json.length).toBeGreaterThanOrEqual(0)
return [response, json] return [response, json]
} }
@ -32,9 +33,9 @@ export default class AppApi {
async canRender(): Promise<[Response, boolean]> { async canRender(): Promise<[Response, boolean]> {
const response = await this.api.get("/routing/client") const response = await this.api.get("/routing/client")
expect(response).toHaveStatusCode(200)
const json = await response.json() const json = await response.json()
const publishedAppRenders = Object.keys(json.routes).length > 0 const publishedAppRenders = Object.keys(json.routes).length > 0
expect(response).toHaveStatusCode(200)
expect(publishedAppRenders).toBe(true) expect(publishedAppRenders).toBe(true)
return [response, publishedAppRenders] return [response, publishedAppRenders]
} }

View File

@ -8,7 +8,7 @@ export default class AuthApi {
this.api = apiClient this.api = apiClient
} }
async login(): Promise<[Response, any]> { async loginAsAdmin(): Promise<[Response, any]> {
const response = await this.api.post(`/global/auth/default/login`, { const response = await this.api.post(`/global/auth/default/login`, {
body: { body: {
username: process.env.BB_ADMIN_USER_EMAIL, username: process.env.BB_ADMIN_USER_EMAIL,
@ -20,6 +20,19 @@ export default class AuthApi {
return [response, cookie] return [response, cookie]
} }
async login(email: String, password: String): Promise<[Response, any]> {
const response = await this.api.post(`/global/auth/default/login`, {
body: {
username: email,
password: password,
},
})
expect(response).toHaveStatusCode(200)
const cookie = response.headers.get("set-cookie")
this.api.cookie = cookie as any
return [response, cookie]
}
async logout(): Promise<any> { async logout(): Promise<any> {
return this.api.post(`/global/auth/logout`) return this.api.post(`/global/auth/logout`)
} }

View File

@ -4,6 +4,7 @@ import InternalAPIClient from "./InternalAPIClient"
import TablesApi from "./tables" import TablesApi from "./tables"
import RowApi from "./rows" import RowApi from "./rows"
import ScreenApi from "./screens" import ScreenApi from "./screens"
import UserManagementApi from "./userManagement"
export default class TestConfiguration<T> { export default class TestConfiguration<T> {
applications: ApplicationApi applications: ApplicationApi
@ -12,6 +13,7 @@ export default class TestConfiguration<T> {
context: T context: T
tables: TablesApi tables: TablesApi
rows: RowApi rows: RowApi
users: UserManagementApi
constructor(apiClient: InternalAPIClient) { constructor(apiClient: InternalAPIClient) {
this.applications = new ApplicationApi(apiClient) this.applications = new ApplicationApi(apiClient)
@ -19,11 +21,16 @@ export default class TestConfiguration<T> {
this.rows = new RowApi(apiClient) this.rows = new RowApi(apiClient)
this.auth = new AuthApi(apiClient) this.auth = new AuthApi(apiClient)
this.screen = new ScreenApi(apiClient) this.screen = new ScreenApi(apiClient)
this.users = new UserManagementApi(apiClient)
this.context = <T>{} this.context = <T>{}
} }
async beforeAll() { async loginAsAdmin() {
await this.auth.login() await this.auth.login(<string>process.env.BB_ADMIN_USER_EMAIL, <string>process.env.BB_ADMIN_USER_PASSWORD)
}
async login(email: string, password: string) {
await this.auth.login(email, password)
} }
async afterAll() { async afterAll() {

View File

@ -39,6 +39,14 @@ export default class TablesApi {
return [response, json] return [response, json]
} }
async forbiddenSave(body: any): Promise<[Response, Table]> {
const response = await this.api.post(`/tables`, { body })
const json = await response.json()
expect(response).toHaveStatusCode(403)
return [response, json]
}
async delete( async delete(
id: string, id: string,
revId: string revId: string

View File

@ -0,0 +1,133 @@
import { Response } from "node-fetch"
import { Role, User, UserDeletedEvent, UserRoles } from "@budibase/types"
import InternalAPIClient from "./InternalAPIClient"
import { responseMessage } from "../fixtures/types/responseMessage"
export default class UserManagementApi {
api: InternalAPIClient
constructor(apiClient: InternalAPIClient) {
this.api = apiClient
}
async search(): Promise<[Response, Partial<User>[]]> {
const response = await this.api.post(`/global/users/search`, {})
const json = await response.json()
expect(response).toHaveStatusCode(200)
expect(json.data.length).toBeGreaterThan(0)
return [response, json]
}
async getSelf(): Promise<[Response, Partial<User>]> {
const response = await this.api.get(`/global/self`)
const json = await response.json()
expect(response).toHaveStatusCode(200)
return [response, json]
}
async getAll(): Promise<[Response, Partial<User>[]]> {
const response = await this.api.get(`/global/users`)
const json = await response.json()
expect(response).toHaveStatusCode(200)
expect(json.length).toBeGreaterThan(0)
return [response, json]
}
// This endpoint is used for one or more users when we want add users with passwords set.
async addMultiple(userList: Partial<User>[]): Promise<[Response, any]> {
const body = {
create: {
users: userList,
groups: []
}
}
const response = await this.api.post(`/global/users/bulk`, { body })
const json = await response.json()
expect(response).toHaveStatusCode(200)
expect(json.created.unsuccessful.length).toEqual(0)
expect(json.created.successful.length).toEqual(body.create.users.length)
return [response, json]
}
async deleteMultiple(userId: string[]): Promise<[Response, responseMessage]> {
const body = {
delete: {
userIds: [
userId
]
}
}
const response = await this.api.post(`/global/users/bulk`, { body })
const json = await response.json()
expect(response).toHaveStatusCode(200)
expect(json.deleted.successful.length).toEqual(1)
expect(json.deleted.unsuccessful.length).toEqual(0)
expect(json.deleted.successful[0].userId).toEqual(userId)
return [response, json]
}
async delete(userId: string): Promise<[Response, UserDeletedEvent]> {
const response = await this.api.del(`/global/users/${userId}`)
const json = await response.json()
expect(response).toHaveStatusCode(200)
expect(json.message).toEqual(`User ${userId} deleted.`)
return [response, json]
}
async invite(body: any): Promise<[Response, responseMessage]> {
const response = await this.api.post(`/global/users/multi/invite`, { body })
const json = await response.json()
expect(response).toHaveStatusCode(200)
expect(json.unsuccessful.length).toEqual(0)
expect(json.successful.length).toEqual(body.length)
return [response, json]
}
async getRoles(): Promise<[Response, Role[]]> {
const response = await this.api.get(`/roles`)
const json = await response.json()
expect(response).toHaveStatusCode(200)
return [response, json]
}
async updateInfo(body: any): Promise<[Response, User]> {
const response = await this.api.post(`/global/users/`, { body })
const json = await response.json()
expect(response).toHaveStatusCode(200)
expect(json._id).toEqual(body._id)
expect(json._rev).not.toEqual(body._rev)
return [response, json]
}
async forcePasswordReset(body: any): Promise<[Response, User]> {
const response = await this.api.post(`/global/users/`, { body })
const json = await response.json()
expect(response).toHaveStatusCode(200)
expect(json._id).toEqual(body._id)
expect(json._rev).not.toEqual(body._rev)
return [response, json]
}
async getInfo(userId: string): Promise<[Response, User]> {
const response = await this.api.get(`/global/users/${userId}`)
const json = await response.json()
expect(response).toHaveStatusCode(200)
return [response, json]
}
async changeSelfPassword(body: Partial<User>): Promise<[Response, User]> {
const response = await this.api.post(`/global/self`, { body })
const json = await response.json()
expect(response).toHaveStatusCode(200)
expect(json._id).toEqual(body._id)
expect(json._rev).not.toEqual(body._rev)
return [response, json]
}
async createRole(body: Partial<UserRoles>): Promise<[Response, UserRoles]> {
const response = await this.api.post(`/roles`, { body })
const json = await response.json()
expect(response).toHaveStatusCode(200)
return [response, json]
}
}

View File

@ -1,7 +1,9 @@
import generator from "../../generator" import generator from "../../generator"
import { Application } from "@budibase/server/api/controllers/public/mapping/types" import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import { Template } from "@budibase/types"
import { App } from "@budibase/types"
const generate = ( export const generateApp = (
overrides: Partial<Application> = {} overrides: Partial<Application> = {}
): Partial<Application> => ({ ): Partial<Application> => ({
name: generator.word() + generator.hash(), name: generator.word() + generator.hash(),
@ -9,4 +11,15 @@ const generate = (
...overrides, ...overrides,
}) })
export default generate // Applications type doesn't work here, save to add useTemplate parameter?
export const appFromTemplate = (): any => {
return ({
name: generator.word(),
url: `/${generator.word()}`,
useTemplate: "true",
templateName: "Near Miss Register",
templateKey: "app/near-miss-register",
templateFile: undefined,
})
}

View File

@ -0,0 +1,80 @@
import generator from "../../generator";
import { User } from "@budibase/types";
const generateDeveloper = (): Partial<User> => {
const randomId = generator.guid();
return ({
email: `pedro+${randomId}@budibase.com`,
password: randomId,
roles: {},
forceResetPassword: true,
builder: {
global: true
}
})
}
const generateAdmin = (): Partial<User> => {
const randomId = generator.guid();
return ({
email: `pedro+${randomId}@budibase.com`,
password: randomId,
roles: {},
forceResetPassword: true,
admin: {
global: true
},
builder: {
global: true
}
})
}
const generateAppUser = (): Partial<User> => {
const randomId = generator.guid();
return ({
email: `pedro+${randomId}@budibase.com`,
password: randomId,
roles: {},
forceResetPassword: true,
admin: {
global: false
},
builder: {
global: false
}
})
}
export const generateInviteUser = (): Object[] => {
const randomId = generator.guid();
return [{
email: `pedro+${randomId}@budibase.com`,
userInfo: {
userGroups: []
}
}]
}
export const generateUser = (amount: number = 1, role?: string): Partial<User>[] => {
const userList: Partial<User>[] = [];
for (let i = 0; i < amount; i++) {
switch (role) {
case "admin":
userList.push(generateAdmin());
break;
case "developer":
userList.push(generateDeveloper());
break;
case "appUser":
userList.push(generateAppUser());
break;
default:
userList.push(generateAppUser());
break;
}
}
return userList
}

View File

@ -2,7 +2,7 @@ import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types" import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import { db } from "@budibase/backend-core" import { db } from "@budibase/backend-core"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient" import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import generateApp from "../../../config/internal-api/fixtures/applications" import { generateApp, appFromTemplate } from "../../../config/internal-api/fixtures/applications"
import generator from "../../../config/generator" import generator from "../../../config/generator"
import generateScreen from "../../../config/internal-api/fixtures/screens" import generateScreen from "../../../config/internal-api/fixtures/screens"
@ -11,23 +11,14 @@ describe("Internal API - Application creation, update, publish and delete", () =
const config = new TestConfiguration<Application>(api) const config = new TestConfiguration<Application>(api)
beforeAll(async () => { beforeAll(async () => {
await config.beforeAll() await config.loginAsAdmin()
}) })
afterAll(async () => { afterAll(async () => {
await config.afterAll() await config.afterAll()
}) })
async function createAppFromTemplate() {
return config.applications.create({
name: generator.word(),
url: `/${generator.word()}`,
useTemplate: "true",
templateName: "Near Miss Register",
templateKey: "app/near-miss-register",
templateFile: undefined,
})
}
it("Get applications without applications", async () => { it("Get applications without applications", async () => {
await config.applications.fetchEmptyAppList() await config.applications.fetchEmptyAppList()
}) })
@ -59,8 +50,7 @@ describe("Internal API - Application creation, update, publish and delete", () =
it("Publish app", async () => { it("Publish app", async () => {
// create the app // create the app
const appName = generator.word() const app = await config.applications.create(appFromTemplate())
const app = await createAppFromTemplate()
config.applications.api.appId = app.appId config.applications.api.appId = app.appId
// check preview renders // check preview renders

View File

@ -1,7 +1,7 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration" import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { App } from "@budibase/types" import { App } from "@budibase/types"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient" import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import generateApp from "../../../config/internal-api/fixtures/applications" import { generateApp, appFromTemplate } from "../../../config/internal-api/fixtures/applications"
import { Screen } from "@budibase/types" import { Screen } from "@budibase/types"
import generateScreen from "../../../config/internal-api/fixtures/screens" import generateScreen from "../../../config/internal-api/fixtures/screens"
@ -11,7 +11,7 @@ describe("Internal API - /screens endpoints", () => {
const appConfig = new TestConfiguration<App>(api) const appConfig = new TestConfiguration<App>(api)
beforeAll(async () => { beforeAll(async () => {
await config.beforeAll() await config.loginAsAdmin()
}) })
afterAll(async () => { afterAll(async () => {

View File

@ -13,7 +13,7 @@ describe("Internal API - Application creation, update, publish and delete", () =
const config = new TestConfiguration<Application>(api) const config = new TestConfiguration<Application>(api)
beforeAll(async () => { beforeAll(async () => {
await config.beforeAll() await config.loginAsAdmin()
}) })
afterAll(async () => { afterAll(async () => {

View File

@ -0,0 +1,627 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import { generateApp, appFromTemplate } from "../../../config/internal-api/fixtures/applications"
import { generateUser } from "../../../config/internal-api/fixtures/userManagement"
import { User } from "@budibase/types"
import { generateNewColumnForTable, generateTable } from "../../../config/internal-api/fixtures/table"
import generateScreen from "../../../config/internal-api/fixtures/screens"
import { db } from "@budibase/backend-core"
describe("Internal API - App Specific Roles & Permissions", () => {
const api = new InternalAPIClient()
const config = new TestConfiguration<Application>(api)
// Before each test, login as admin. Some tests will require login as a different user
beforeEach(async () => {
await config.loginAsAdmin()
})
afterAll(async () => {
await config.afterAll()
})
it("Add BASIC user to app", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(appUser)
const app = await config.applications.create(appFromTemplate())
config.applications.api.appId = app.appId
const [userInfoResponse, userInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
const body: User = {
...userInfoJson,
roles: {
[<string>app.appId]: "BASIC",
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
expect(changedUserInfoJson.roles[<string>app.appId]).toEqual("BASIC")
})
it("Add ADMIN user to app", async () => {
const adminUser = generateUser(1, "admin")
expect(adminUser[0].builder?.global).toEqual(true)
expect(adminUser[0].admin?.global).toEqual(true)
const [createUserResponse, createUserJson] = await config.users.addMultiple(adminUser)
//const app = await config.applications.create(generateApp())
//config.applications.api.appId = app.appId
const app = await config.applications.create(appFromTemplate())
config.applications.api.appId = app.appId
const [userInfoResponse, userInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
const body: User = {
...userInfoJson,
roles: {
[<string>app.appId]: "ADMIN",
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
expect(changedUserInfoJson.roles[<string>app.appId]).toEqual("ADMIN")
// publish app
await config.applications.publish(<string>app.appId)
// check published app renders
config.applications.api.appId = db.getProdAppID(app.appId!)
await config.applications.canRender()
})
it("Add POWER user to app", async () => {
const powerUser = generateUser(1, 'developer')
expect(powerUser[0].builder?.global).toEqual(true)
const [createUserResponse, createUserJson] = await config.users.addMultiple(powerUser)
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
const [userInfoResponse, userInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
const body: User = {
...userInfoJson,
roles: {
[<string>app.appId]: "POWER",
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
expect(changedUserInfoJson.roles[<string>app.appId]).toEqual("POWER")
})
describe("Check Access for default roles", () => {
it("Check Table access for app user", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(appUser)
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
const [userInfoResponse, userInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
const body: User = {
...userInfoJson,
roles: {
[<string>app.appId]: "BASIC",
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
expect(changedUserInfoJson.roles[<string>app.appId]).toEqual("BASIC")
const [createdTableResponse, createdTableData] = await config.tables.save(
generateTable()
)
await config.login(<string>appUser[0].email, <string>appUser[0].password)
const newColumn = generateNewColumnForTable(createdTableData)
await config.tables.forbiddenSave(
newColumn)
await config.tables.forbiddenSave(generateTable())
})
it("Check Table access for developer", async () => {
const developer = generateUser(1, 'developer')
expect(developer[0].builder?.global).toEqual(true)
const [createUserResponse, createUserJson] = await config.users.addMultiple(developer)
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
const [userInfoResponse, userInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
const body: User = {
...userInfoJson,
roles: {
[<string>app.appId]: "POWER",
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
expect(changedUserInfoJson.roles[<string>app.appId]).toEqual("POWER")
const [createdTableResponse, createdTableData] = await config.tables.save(
generateTable()
)
await config.login(<string>developer[0].email, <string>developer[0].password)
const newColumn = generateNewColumnForTable(createdTableData)
const [addColumnResponse, addColumnData] = await config.tables.save(
newColumn,
true
)
})
it("Check Table access for admin", async () => {
const adminUser = generateUser(1, "admin")
expect(adminUser[0].builder?.global).toEqual(true)
expect(adminUser[0].admin?.global).toEqual(true)
const [createUserResponse, createUserJson] = await config.users.addMultiple(adminUser)
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
const [userInfoResponse, userInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
const body: User = {
...userInfoJson,
roles: {
[<string>app.appId]: "ADMIN",
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
expect(changedUserInfoJson.roles[<string>app.appId]).toEqual("ADMIN")
await config.login(<string>adminUser[0].email, <string>adminUser[0].password)
const [createdTableResponse, createdTableData] = await config.tables.save(
generateTable()
)
const newColumn = generateNewColumnForTable(createdTableData)
const [addColumnResponse, addColumnData] = await config.tables.save(
newColumn,
true
)
})
})
describe("Screen Access for App specific roles", () => {
it("Check Screen access for BASIC Role", async () => {
// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: "BASIC",
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual("BASIC")
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] = await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with BASIC user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] = await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
expect(appPackageJson.screens[0].routing.roleId).toEqual("BASIC")
})
it("Check Screen access for POWER role", async () => {
// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: "POWER",
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual("POWER")
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] = await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with POWER user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] = await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(2)
})
it("Check Screen access for ADMIN role", async () => {
// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: "ADMIN",
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual("ADMIN")
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] = await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with ADMIN user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] = await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(3)
})
})
describe("Screen Access for custom roles", () => {
it("Custom role access for level 1 permissions", async () => {
// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "public",
name: "level 1"
}
const [createRoleResponse, createRoleJson] = await config.users.createRole(role)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] = await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] = await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
it("Custom role access for level 2 permissions", async () => {// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "read_only",
name: "level 2"
}
const [createRoleResponse, createRoleJson] = await config.users.createRole(role)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] = await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] = await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
it("Custom role access for level 3 permissions", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "write",
name: "level 3"
}
const [createRoleResponse, createRoleJson] = await config.users.createRole(role)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] = await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] = await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
it("Custom role access for level 4 permissions", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "power",
name: "level 4"
}
const [createRoleResponse, createRoleJson] = await config.users.createRole(role)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] = await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] = await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
it("Custom role access for level 5 permissions", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "admin",
name: "level 5"
}
const [createRoleResponse, createRoleJson] = await config.users.createRole(role)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] = await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] = await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
})
})

View File

@ -0,0 +1,90 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import { generateUser } from "../../../config/internal-api/fixtures/userManagement"
import { User } from "@budibase/types"
describe("Internal API - User Management & Permissions", () => {
const api = new InternalAPIClient()
const config = new TestConfiguration<Application>(api)
// Before each test, login as admin. Some tests will require login as a different user
beforeEach(async () => {
await config.loginAsAdmin()
})
afterAll(async () => {
await config.afterAll()
})
it("Add Users with different roles", async () => {
await config.users.search()
await config.users.getRoles()
const admin = generateUser(1, "admin")
expect(admin[0].builder?.global).toEqual(true)
expect(admin[0].admin?.global).toEqual(true)
const developer = generateUser(1, "developer")
expect(developer[0].builder?.global).toEqual(true)
const appUser = generateUser(1, "appUser")
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const userList = [...admin, ...developer, ...appUser]
await config.users.addMultiple(userList)
const [allUsersResponse, allUsersJson] = await config.users.getAll()
expect(allUsersJson.length).toBeGreaterThan(0)
})
it("Delete User", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [userResponse, userJson] = await config.users.addMultiple(appUser)
const userId = userJson.created.successful[0]._id
await config.users.delete(<string>userId)
})
it("Reset Password", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [userResponse, userJson] = await config.users.addMultiple(appUser)
const [userInfoResponse, userInfoJson] = await config.users.getInfo(userJson.created.successful[0]._id)
const body: User = {
...userInfoJson,
password: "newPassword"
}
await config.users.forcePasswordReset(body)
})
it("Change User information", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [userResponse, userJson] = await config.users.addMultiple(appUser)
const [userInfoResponse, userInfoJson] = await config.users.getInfo(userJson.created.successful[0]._id)
const body: User = {
...userInfoJson,
firstName: "newFirstName",
lastName: "newLastName",
builder: {
global: true
}
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] = await config.users.getInfo(userJson.created.successful[0]._id)
expect(changedUserInfoJson.builder?.global).toBeDefined()
expect(changedUserInfoJson.builder?.global).toEqual(true)
})
})