From 04a2bbc61aba8016d84b649273a60dc3c7c6effb Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 20 Oct 2023 15:45:35 +0100 Subject: [PATCH 1/4] Two fixes here - a quick fix for the builder side panel, making sure it fills up with users correctly (not all, but enough to make it look more pleasant) as well as dropping user search endpoint permissions to allow basic users to access it for user columns. --- packages/backend-core/src/users/db.ts | 10 +++++----- packages/backend-core/src/users/users.ts | 9 ++++++--- .../_components/BuilderSidePanel.svelte | 3 ++- packages/types/src/api/web/user.ts | 1 + .../worker/src/api/controllers/global/users.ts | 7 ++++++- .../src/api/routes/global/tests/users.spec.ts | 6 +++++- packages/worker/src/api/routes/global/users.ts | 3 ++- packages/worker/src/tests/api/users.ts | 14 ++++++++++---- 8 files changed, 37 insertions(+), 16 deletions(-) diff --git a/packages/backend-core/src/users/db.ts b/packages/backend-core/src/users/db.ts index 8bb6300d4e..daa09bee6f 100644 --- a/packages/backend-core/src/users/db.ts +++ b/packages/backend-core/src/users/db.ts @@ -164,14 +164,14 @@ export class UserDB { } } - static async getUsersByAppAccess(appId?: string) { - const opts: any = { + static async getUsersByAppAccess(opts: { appId?: string; limit?: number }) { + const params: any = { include_docs: true, - limit: 50, + limit: opts.limit || 50, } let response: User[] = await usersCore.searchGlobalUsersByAppAccess( - appId, - opts + opts.appId, + params ) return response } diff --git a/packages/backend-core/src/users/users.ts b/packages/backend-core/src/users/users.ts index a64997224e..bad108ab84 100644 --- a/packages/backend-core/src/users/users.ts +++ b/packages/backend-core/src/users/users.ts @@ -19,6 +19,7 @@ import { SearchUsersRequest, User, ContextUser, + DatabaseQueryOpts, } from "@budibase/types" import { getGlobalDB } from "../context" import * as context from "../context" @@ -241,12 +242,14 @@ export const paginatedUsers = async ({ bookmark, query, appId, + limit, }: SearchUsersRequest = {}) => { const db = getGlobalDB() + const pageLimit = limit ? limit + 1 : PAGE_LIMIT + 1 // get one extra document, to have the next page - const opts: any = { + const opts: DatabaseQueryOpts = { include_docs: true, - limit: PAGE_LIMIT + 1, + limit: pageLimit, } // add a startkey if the page was specified (anchor) if (bookmark) { @@ -269,7 +272,7 @@ export const paginatedUsers = async ({ const response = await db.allDocs(getGlobalUserParams(null, opts)) userList = response.rows.map((row: any) => row.doc) } - return pagination(userList, PAGE_LIMIT, { + return pagination(userList, pageLimit, { paginate: true, property, getKey, diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index c93a41f541..a7d9584330 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -114,8 +114,9 @@ query: { appId: query || !filterByAppAccess ? null : prodAppId, email: query, - paginated: query || !filterByAppAccess ? null : false, }, + limit: 50, + paginate: query || !filterByAppAccess ? null : false, }) await usersFetch.refresh() diff --git a/packages/types/src/api/web/user.ts b/packages/types/src/api/web/user.ts index a1e039cfd7..3a5bd16bdf 100644 --- a/packages/types/src/api/web/user.ts +++ b/packages/types/src/api/web/user.ts @@ -55,6 +55,7 @@ export interface SearchUsersRequest { bookmark?: string query?: SearchQuery appId?: string + limit?: number paginate?: boolean } diff --git a/packages/worker/src/api/controllers/global/users.ts b/packages/worker/src/api/controllers/global/users.ts index 8de3a1444e..bfe9bdf284 100644 --- a/packages/worker/src/api/controllers/global/users.ts +++ b/packages/worker/src/api/controllers/global/users.ts @@ -189,7 +189,10 @@ export const destroy = async (ctx: any) => { export const getAppUsers = async (ctx: Ctx) => { const body = ctx.request.body - const users = await userSdk.db.getUsersByAppAccess(body?.appId) + const users = await userSdk.db.getUsersByAppAccess({ + appId: body.appId, + limit: body.limit, + }) ctx.body = { data: users } } @@ -203,8 +206,10 @@ export const search = async (ctx: Ctx) => { } if (body.paginate === false) { + console.log("not paginated") await getAppUsers(ctx) } else { + console.log("paginated") const paginated = await userSdk.core.paginatedUsers(body) // user hashed password shouldn't ever be returned for (let user of paginated.data) { diff --git a/packages/worker/src/api/routes/global/tests/users.spec.ts b/packages/worker/src/api/routes/global/tests/users.spec.ts index a446d10ed0..846b98a7ae 100644 --- a/packages/worker/src/api/routes/global/tests/users.spec.ts +++ b/packages/worker/src/api/routes/global/tests/users.spec.ts @@ -569,9 +569,13 @@ describe("/api/global/users", () => { { query: { equal: { firstName: user.firstName } }, }, - 501 + { status: 501 } ) }) + + it("should throw an error if public query performed", async () => { + await config.api.users.searchUsers({}, { status: 403, noHeaders: true }) + }) }) describe("DELETE /api/global/users/:userId", () => { diff --git a/packages/worker/src/api/routes/global/users.ts b/packages/worker/src/api/routes/global/users.ts index a57f7834ac..3c9cfd2f41 100644 --- a/packages/worker/src/api/routes/global/users.ts +++ b/packages/worker/src/api/routes/global/users.ts @@ -72,7 +72,8 @@ router ) .get("/api/global/users", auth.builderOrAdmin, controller.fetch) - .post("/api/global/users/search", auth.builderOrAdmin, controller.search) + // search can be used by any user now, to retrieve users for user column + .post("/api/global/users/search", controller.search) .delete("/api/global/users/:id", auth.adminOnly, controller.destroy) .get( "/api/global/users/count/:appId", diff --git a/packages/worker/src/tests/api/users.ts b/packages/worker/src/tests/api/users.ts index b2a19bcb28..ca25e2f9ca 100644 --- a/packages/worker/src/tests/api/users.ts +++ b/packages/worker/src/tests/api/users.ts @@ -134,13 +134,19 @@ export class UserAPI extends TestAPI { .expect(status ? status : 200) } - searchUsers = ({ query }: { query?: SearchQuery }, status = 200) => { - return this.request + searchUsers = ( + { query }: { query?: SearchQuery }, + opts?: { status?: number; noHeaders?: boolean } + ) => { + const req = this.request .post("/api/global/users/search") - .set(this.config.defaultHeaders()) .send({ query }) .expect("Content-Type", /json/) - .expect(status ? status : 200) + .expect(opts?.status ? opts.status : 200) + if (!opts?.noHeaders) { + req.set(this.config.defaultHeaders()) + } + return req } getUser = (userId: string, opts?: TestAPIOpts) => { From 8c744ea7a99ab68e7388094ab74c6fc5ba708e78 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 20 Oct 2023 15:57:45 +0100 Subject: [PATCH 2/4] PR comments. --- packages/worker/src/api/controllers/global/users.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/worker/src/api/controllers/global/users.ts b/packages/worker/src/api/controllers/global/users.ts index bfe9bdf284..de1a605890 100644 --- a/packages/worker/src/api/controllers/global/users.ts +++ b/packages/worker/src/api/controllers/global/users.ts @@ -206,10 +206,8 @@ export const search = async (ctx: Ctx) => { } if (body.paginate === false) { - console.log("not paginated") await getAppUsers(ctx) } else { - console.log("paginated") const paginated = await userSdk.core.paginatedUsers(body) // user hashed password shouldn't ever be returned for (let user of paginated.data) { From 8a939dd3e60cb8dc5f0d9e8703fd5a41c7879e1c Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 20 Oct 2023 17:02:24 +0200 Subject: [PATCH 3/4] Update pro submodule ref --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index 570d14aa44..56d968bfe6 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 570d14aa44aa88f4d053856322210f0008ba5c76 +Subproject commit 56d968bfe6998e1077d3fce4eb1c9e483d1d6fc9 From 97fc794a2b198f2466dd1ec41e4371de8fd8a224 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Fri, 20 Oct 2023 15:15:17 +0000 Subject: [PATCH 4/4] Bump version to 2.11.41 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 75db3b9b55..4b2bbb05d5 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.11.40", + "version": "2.11.41", "npmClient": "yarn", "packages": [ "packages/*"