From 0633a3de65922beeea097d933706406bc125e642 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 8 Nov 2023 10:03:22 +0000 Subject: [PATCH 1/2] WIP --- packages/server/src/api/controllers/auth.ts | 2 +- packages/server/src/api/controllers/user.ts | 6 +-- .../tests/{user.spec.js => user.spec.ts} | 27 ++++++----- .../server/src/tests/utilities/api/index.ts | 3 ++ .../server/src/tests/utilities/api/user.ts | 48 +++++++++++++++++++ packages/server/src/utilities/users.ts | 12 +++-- packages/types/src/api/web/app/index.ts | 1 + packages/types/src/api/web/app/user.ts | 3 ++ 8 files changed, 81 insertions(+), 21 deletions(-) rename packages/server/src/api/routes/tests/{user.spec.js => user.spec.ts} (89%) create mode 100644 packages/server/src/tests/utilities/api/user.ts create mode 100644 packages/types/src/api/web/app/user.ts diff --git a/packages/server/src/api/controllers/auth.ts b/packages/server/src/api/controllers/auth.ts index eabfe10bab..9b1b78ed9e 100644 --- a/packages/server/src/api/controllers/auth.ts +++ b/packages/server/src/api/controllers/auth.ts @@ -26,7 +26,7 @@ export async function fetchSelf(ctx: UserCtx) { } const appId = context.getAppId() - let user: ContextUser = await getFullUser(ctx, userId) + let user: ContextUser = await getFullUser(userId) // this shouldn't be returned by the app self delete user.roles // forward the csrf token from the session diff --git a/packages/server/src/api/controllers/user.ts b/packages/server/src/api/controllers/user.ts index b6c3e7c6bd..bfe206e98a 100644 --- a/packages/server/src/api/controllers/user.ts +++ b/packages/server/src/api/controllers/user.ts @@ -1,10 +1,10 @@ import { generateUserFlagID, InternalTables } from "../../db/utils" import { getFullUser } from "../../utilities/users" import { context } from "@budibase/backend-core" -import { Ctx, UserCtx } from "@budibase/types" +import { Ctx, FetchUserMetadataResponse, UserCtx } from "@budibase/types" import sdk from "../../sdk" -export async function fetchMetadata(ctx: Ctx) { +export async function fetchMetadata(ctx: Ctx) { ctx.body = await sdk.users.fetchMetadata() } @@ -44,7 +44,7 @@ export async function destroyMetadata(ctx: UserCtx) { } export async function findMetadata(ctx: UserCtx) { - ctx.body = await getFullUser(ctx, ctx.params.id) + ctx.body = await getFullUser(ctx.params.id) } export async function setFlag(ctx: UserCtx) { diff --git a/packages/server/src/api/routes/tests/user.spec.js b/packages/server/src/api/routes/tests/user.spec.ts similarity index 89% rename from packages/server/src/api/routes/tests/user.spec.js rename to packages/server/src/api/routes/tests/user.spec.ts index e8ffd8df2b..caae54bc68 100644 --- a/packages/server/src/api/routes/tests/user.spec.js +++ b/packages/server/src/api/routes/tests/user.spec.ts @@ -1,7 +1,6 @@ -const { roles, utils } = require("@budibase/backend-core") -const { checkPermissionsEndpoint } = require("./utilities/TestFunctions") -const setup = require("./utilities") -const { BUILTIN_ROLE_IDS } = roles +import { roles, utils } from "@budibase/backend-core" +import { checkPermissionsEndpoint } from "./utilities/TestFunctions" +import * as setup from "./utilities" jest.setTimeout(30000) @@ -47,8 +46,8 @@ describe("/users", () => { request, method: "GET", url: `/api/users/metadata`, - passRole: BUILTIN_ROLE_IDS.ADMIN, - failRole: BUILTIN_ROLE_IDS.PUBLIC, + passRole: roles.BUILTIN_ROLE_IDS.ADMIN, + failRole: roles.BUILTIN_ROLE_IDS.PUBLIC, }) }) }) @@ -56,7 +55,7 @@ describe("/users", () => { describe("update", () => { it("should be able to update the user", async () => { const user = await config.createUser({ id: `us_update${utils.newid()}` }) - user.roleId = BUILTIN_ROLE_IDS.BASIC + user.roleId = roles.BUILTIN_ROLE_IDS.BASIC delete user._rev const res = await request .put(`/api/users/metadata`) @@ -74,14 +73,18 @@ describe("/users", () => { const res1 = await request .put(`/api/users/metadata`) .set(config.defaultHeaders()) - .send({ ...user, roleId: BUILTIN_ROLE_IDS.BASIC }) + .send({ ...user, roleId: roles.BUILTIN_ROLE_IDS.BASIC }) .expect(200) .expect("Content-Type", /json/) const res = await request .put(`/api/users/metadata`) .set(config.defaultHeaders()) - .send({ ...user, _rev: res1.body.rev, roleId: BUILTIN_ROLE_IDS.POWER }) + .send({ + ...user, + _rev: res1.body.rev, + roleId: roles.BUILTIN_ROLE_IDS.POWER, + }) .expect(200) .expect("Content-Type", /json/) @@ -95,14 +98,14 @@ describe("/users", () => { await request .put(`/api/users/metadata`) .set(config.defaultHeaders()) - .send({ ...user, roleId: BUILTIN_ROLE_IDS.BASIC }) + .send({ ...user, roleId: roles.BUILTIN_ROLE_IDS.BASIC }) .expect(200) .expect("Content-Type", /json/) await request .put(`/api/users/metadata`) .set(config.defaultHeaders()) - .send({ ...user, roleId: BUILTIN_ROLE_IDS.POWER }) + .send({ ...user, roleId: roles.BUILTIN_ROLE_IDS.POWER }) .expect(409) .expect("Content-Type", /json/) }) @@ -129,7 +132,7 @@ describe("/users", () => { .expect(200) .expect("Content-Type", /json/) expect(res.body._id).toEqual(user._id) - expect(res.body.roleId).toEqual(BUILTIN_ROLE_IDS.ADMIN) + expect(res.body.roleId).toEqual(roles.BUILTIN_ROLE_IDS.ADMIN) expect(res.body.tableId).toBeDefined() }) }) diff --git a/packages/server/src/tests/utilities/api/index.ts b/packages/server/src/tests/utilities/api/index.ts index c553e7b8f4..20b96f7a99 100644 --- a/packages/server/src/tests/utilities/api/index.ts +++ b/packages/server/src/tests/utilities/api/index.ts @@ -9,6 +9,7 @@ import { ScreenAPI } from "./screen" import { ApplicationAPI } from "./application" import { BackupAPI } from "./backup" import { AttachmentAPI } from "./attachment" +import { UserAPI } from "./user" export default class API { table: TableAPI @@ -21,6 +22,7 @@ export default class API { application: ApplicationAPI backup: BackupAPI attachment: AttachmentAPI + user: UserAPI constructor(config: TestConfiguration) { this.table = new TableAPI(config) @@ -33,5 +35,6 @@ export default class API { this.application = new ApplicationAPI(config) this.backup = new BackupAPI(config) this.attachment = new AttachmentAPI(config) + this.user = new UserAPI(config) } } diff --git a/packages/server/src/tests/utilities/api/user.ts b/packages/server/src/tests/utilities/api/user.ts new file mode 100644 index 0000000000..2066315778 --- /dev/null +++ b/packages/server/src/tests/utilities/api/user.ts @@ -0,0 +1,48 @@ +import { FetchUserMetadataResponse } from "@budibase/types" +import TestConfiguration from "../TestConfiguration" +import { TestAPI } from "./base" + +export class UserAPI extends TestAPI { + constructor(config: TestConfiguration) { + super(config) + } + + fetch = async ( + { expectStatus } = { expectStatus: 200 } + ): Promise => { + const res = await this.request + .get(`/api/users/metadata`) + .set(this.config.defaultHeaders()) + .expect("Content-Type", /json/) + + if (res.status !== expectStatus) { + throw new Error( + `Expected status ${expectStatus} but got ${ + res.status + } with body ${JSON.stringify(res.body)}` + ) + } + + return res.body + } + + get = async ( + id: string, + { expectStatus } = { expectStatus: 200 } + ): Promise => { + const res = await this.request + .get(`/api/users/metadata/${id}`) + .set(this.config.defaultHeaders()) + .expect("Content-Type", /json/) + + if (res.status !== expectStatus) { + throw new Error( + `Expected status ${expectStatus} but got ${ + res.status + } with body ${JSON.stringify(res.body)}` + ) + } + + return res.body + } +} diff --git a/packages/server/src/utilities/users.ts b/packages/server/src/utilities/users.ts index bbc1370355..73b2f48b15 100644 --- a/packages/server/src/utilities/users.ts +++ b/packages/server/src/utilities/users.ts @@ -1,11 +1,13 @@ import { InternalTables } from "../db/utils" import { getGlobalUser } from "./global" import { context, roles } from "@budibase/backend-core" -import { UserCtx } from "@budibase/types" +import { ContextUserMetadata, UserCtx, UserMetadata } from "@budibase/types" -export async function getFullUser(ctx: UserCtx, userId: string) { +export async function getFullUser( + userId: string +): Promise { const global = await getGlobalUser(userId) - let metadata: any = {} + let metadata: UserMetadata | undefined = undefined // always prefer the user metadata _id and _rev delete global._id @@ -14,11 +16,11 @@ export async function getFullUser(ctx: UserCtx, userId: string) { try { // this will throw an error if the db doesn't exist, or there is no appId const db = context.getAppDB() - metadata = await db.get(userId) + metadata = await db.get(userId) + delete metadata.csrfToken } catch (err) { // it is fine if there is no user metadata yet } - delete metadata.csrfToken return { ...metadata, ...global, diff --git a/packages/types/src/api/web/app/index.ts b/packages/types/src/api/web/app/index.ts index f5b876009b..cb1cea2b08 100644 --- a/packages/types/src/api/web/app/index.ts +++ b/packages/types/src/api/web/app/index.ts @@ -6,3 +6,4 @@ export * from "./rows" export * from "./table" export * from "./permission" export * from "./attachment" +export * from "./user" diff --git a/packages/types/src/api/web/app/user.ts b/packages/types/src/api/web/app/user.ts new file mode 100644 index 0000000000..2e0eeee7f8 --- /dev/null +++ b/packages/types/src/api/web/app/user.ts @@ -0,0 +1,3 @@ +import { ContextUserMetadata } from "src/documents" + +export type FetchUserMetadataResponse = ContextUserMetadata[] From d146df5f7367959bccc6d3ce3b02c9098e8e4e4e Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 8 Nov 2023 11:53:00 +0000 Subject: [PATCH 2/2] Convert user.spec.js to user.spec.ts --- .../src/api/controllers/row/internal.ts | 3 +- packages/server/src/api/controllers/user.ts | 48 ++++-- .../server/src/api/routes/tests/user.spec.ts | 149 +++++------------- .../src/tests/utilities/TestConfiguration.ts | 2 +- .../server/src/tests/utilities/api/user.ts | 115 +++++++++++++- packages/types/src/api/web/app/user.ts | 8 +- packages/types/src/documents/account/flag.ts | 5 + packages/types/src/documents/account/index.ts | 1 + 8 files changed, 201 insertions(+), 130 deletions(-) create mode 100644 packages/types/src/documents/account/flag.ts diff --git a/packages/server/src/api/controllers/row/internal.ts b/packages/server/src/api/controllers/row/internal.ts index d53345a239..fe7d94547a 100644 --- a/packages/server/src/api/controllers/row/internal.ts +++ b/packages/server/src/api/controllers/row/internal.ts @@ -2,7 +2,6 @@ import * as linkRows from "../../../db/linkedRows" import { generateRowID, getMultiIDParams, - getTableIDFromRowID, InternalTables, } from "../../../db/utils" import * as userController from "../user" @@ -89,7 +88,7 @@ export async function patch(ctx: UserCtx) { if (isUserTable) { // the row has been updated, need to put it into the ctx ctx.request.body = row as any - await userController.updateMetadata(ctx) + await userController.updateMetadata(ctx as any) return { row: ctx.body as Row, table } } diff --git a/packages/server/src/api/controllers/user.ts b/packages/server/src/api/controllers/user.ts index bfe206e98a..108e29fd3d 100644 --- a/packages/server/src/api/controllers/user.ts +++ b/packages/server/src/api/controllers/user.ts @@ -1,14 +1,26 @@ import { generateUserFlagID, InternalTables } from "../../db/utils" import { getFullUser } from "../../utilities/users" import { context } from "@budibase/backend-core" -import { Ctx, FetchUserMetadataResponse, UserCtx } from "@budibase/types" +import { + ContextUserMetadata, + Ctx, + FetchUserMetadataResponse, + FindUserMetadataResponse, + Flags, + SetFlagRequest, + UserCtx, + UserMetadata, +} from "@budibase/types" import sdk from "../../sdk" +import { DocumentInsertResponse } from "@budibase/nano" -export async function fetchMetadata(ctx: Ctx) { +export async function fetchMetadata(ctx: Ctx) { ctx.body = await sdk.users.fetchMetadata() } -export async function updateSelfMetadata(ctx: UserCtx) { +export async function updateSelfMetadata( + ctx: UserCtx +) { // overwrite the ID with current users ctx.request.body._id = ctx.user?._id // make sure no stale rev @@ -18,19 +30,21 @@ export async function updateSelfMetadata(ctx: UserCtx) { await updateMetadata(ctx) } -export async function updateMetadata(ctx: UserCtx) { +export async function updateMetadata( + ctx: UserCtx +) { const db = context.getAppDB() const user = ctx.request.body - // this isn't applicable to the user - delete user.roles - const metadata = { + const metadata: ContextUserMetadata = { tableId: InternalTables.USER_METADATA, ...user, } + // this isn't applicable to the user + delete metadata.roles ctx.body = await db.put(metadata) } -export async function destroyMetadata(ctx: UserCtx) { +export async function destroyMetadata(ctx: UserCtx) { const db = context.getAppDB() try { const dbUser = await sdk.users.get(ctx.params.id) @@ -43,11 +57,15 @@ export async function destroyMetadata(ctx: UserCtx) { } } -export async function findMetadata(ctx: UserCtx) { +export async function findMetadata( + ctx: UserCtx +) { ctx.body = await getFullUser(ctx.params.id) } -export async function setFlag(ctx: UserCtx) { +export async function setFlag( + ctx: UserCtx +) { const userId = ctx.user?._id const { flag, value } = ctx.request.body if (!flag) { @@ -55,9 +73,9 @@ export async function setFlag(ctx: UserCtx) { } const flagDocId = generateUserFlagID(userId!) const db = context.getAppDB() - let doc + let doc: Flags try { - doc = await db.get(flagDocId) + doc = await db.get(flagDocId) } catch (err) { doc = { _id: flagDocId } } @@ -66,13 +84,13 @@ export async function setFlag(ctx: UserCtx) { ctx.body = { message: "Flag set successfully" } } -export async function getFlags(ctx: UserCtx) { +export async function getFlags(ctx: UserCtx) { const userId = ctx.user?._id const docId = generateUserFlagID(userId!) const db = context.getAppDB() - let doc + let doc: Flags try { - doc = await db.get(docId) + doc = await db.get(docId) } catch (err) { doc = { _id: docId } } diff --git a/packages/server/src/api/routes/tests/user.spec.ts b/packages/server/src/api/routes/tests/user.spec.ts index caae54bc68..e6349099d7 100644 --- a/packages/server/src/api/routes/tests/user.spec.ts +++ b/packages/server/src/api/routes/tests/user.spec.ts @@ -1,6 +1,7 @@ import { roles, utils } from "@budibase/backend-core" import { checkPermissionsEndpoint } from "./utilities/TestFunctions" import * as setup from "./utilities" +import { UserMetadata } from "@budibase/types" jest.setTimeout(30000) @@ -28,15 +29,13 @@ describe("/users", () => { it("returns a list of users from an instance db", async () => { await config.createUser({ id: "uuidx" }) await config.createUser({ id: "uuidy" }) - const res = await request - .get(`/api/users/metadata`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect(res.body.length).toBe(3) - expect(res.body.find(u => u._id === `ro_ta_users_us_uuidx`)).toBeDefined() - expect(res.body.find(u => u._id === `ro_ta_users_us_uuidy`)).toBeDefined() + const res = await config.api.user.fetch() + expect(res.length).toBe(3) + + const ids = res.map(u => u._id) + expect(ids).toContain(`ro_ta_users_us_uuidx`) + expect(ids).toContain(`ro_ta_users_us_uuidy`) }) it("should apply authorization to endpoint", async () => { @@ -54,86 +53,61 @@ describe("/users", () => { describe("update", () => { it("should be able to update the user", async () => { - const user = await config.createUser({ id: `us_update${utils.newid()}` }) + const user: UserMetadata = await config.createUser({ + id: `us_update${utils.newid()}`, + }) user.roleId = roles.BUILTIN_ROLE_IDS.BASIC delete user._rev - const res = await request - .put(`/api/users/metadata`) - .set(config.defaultHeaders()) - .send(user) - .expect(200) - .expect("Content-Type", /json/) - expect(res.body.ok).toEqual(true) + const res = await config.api.user.update(user) + expect(res.ok).toEqual(true) }) it("should be able to update the user multiple times", async () => { const user = await config.createUser() delete user._rev - const res1 = await request - .put(`/api/users/metadata`) - .set(config.defaultHeaders()) - .send({ ...user, roleId: roles.BUILTIN_ROLE_IDS.BASIC }) - .expect(200) - .expect("Content-Type", /json/) - - const res = await request - .put(`/api/users/metadata`) - .set(config.defaultHeaders()) - .send({ - ...user, - _rev: res1.body.rev, - roleId: roles.BUILTIN_ROLE_IDS.POWER, - }) - .expect(200) - .expect("Content-Type", /json/) - - expect(res.body.ok).toEqual(true) + const res1 = await config.api.user.update({ + ...user, + roleId: roles.BUILTIN_ROLE_IDS.BASIC, + }) + const res2 = await config.api.user.update({ + ...user, + _rev: res1.rev, + roleId: roles.BUILTIN_ROLE_IDS.POWER, + }) + expect(res2.ok).toEqual(true) }) it("should require the _rev field for multiple updates", async () => { const user = await config.createUser() delete user._rev - await request - .put(`/api/users/metadata`) - .set(config.defaultHeaders()) - .send({ ...user, roleId: roles.BUILTIN_ROLE_IDS.BASIC }) - .expect(200) - .expect("Content-Type", /json/) - - await request - .put(`/api/users/metadata`) - .set(config.defaultHeaders()) - .send({ ...user, roleId: roles.BUILTIN_ROLE_IDS.POWER }) - .expect(409) - .expect("Content-Type", /json/) + await config.api.user.update({ + ...user, + roleId: roles.BUILTIN_ROLE_IDS.BASIC, + }) + await config.api.user.update( + { ...user, roleId: roles.BUILTIN_ROLE_IDS.POWER }, + { expectStatus: 409 } + ) }) }) describe("destroy", () => { it("should be able to delete the user", async () => { const user = await config.createUser() - const res = await request - .delete(`/api/users/metadata/${user._id}`) - .set(config.defaultHeaders()) - .expect(200) - .expect("Content-Type", /json/) - expect(res.body.message).toBeDefined() + const res = await config.api.user.destroy(user._id!) + expect(res.message).toBeDefined() }) }) describe("find", () => { it("should be able to find the user", async () => { const user = await config.createUser() - const res = await request - .get(`/api/users/metadata/${user._id}`) - .set(config.defaultHeaders()) - .expect(200) - .expect("Content-Type", /json/) - expect(res.body._id).toEqual(user._id) - expect(res.body.roleId).toEqual(roles.BUILTIN_ROLE_IDS.ADMIN) - expect(res.body.tableId).toBeDefined() + const res = await config.api.user.find(user._id!) + expect(res._id).toEqual(user._id) + expect(res.roleId).toEqual(roles.BUILTIN_ROLE_IDS.ADMIN) + expect(res.tableId).toBeDefined() }) }) @@ -153,59 +127,18 @@ describe("/users", () => { it("should be able to set a flag on the user", async () => { await config.createUser() - const res = await request - .post(`/api/users/flags`) - .set(config.defaultHeaders()) - .send({ value: "test", flag: "test" }) - .expect(200) - .expect("Content-Type", /json/) - expect(res.body.message).toEqual("Flag set successfully") + const res = await config.api.user.setFlag("test", true) + expect(res.message).toEqual("Flag set successfully") }) }) describe("getFlags", () => { it("should get flags for a specific user", async () => { - let flagData = { value: "test", flag: "test" } await config.createUser() - await request - .post(`/api/users/flags`) - .set(config.defaultHeaders()) - .send(flagData) - .expect(200) - .expect("Content-Type", /json/) + await config.api.user.setFlag("test", "test") - const res = await request - .get(`/api/users/flags`) - .set(config.defaultHeaders()) - .expect(200) - .expect("Content-Type", /json/) - expect(res.body[flagData.value]).toEqual(flagData.flag) - }) - }) - - describe("setFlag", () => { - it("should throw an error if a flag is not provided", async () => { - await config.createUser() - const res = await request - .post(`/api/users/flags`) - .set(config.defaultHeaders()) - .send({ value: "test" }) - .expect(400) - .expect("Content-Type", /json/) - expect(res.body.message).toEqual( - "Must supply a 'flag' field in request body." - ) - }) - - it("should be able to set a flag on the user", async () => { - await config.createUser() - const res = await request - .post(`/api/users/flags`) - .set(config.defaultHeaders()) - .send({ value: "test", flag: "test" }) - .expect(200) - .expect("Content-Type", /json/) - expect(res.body.message).toEqual("Flag set successfully") + const res = await config.api.user.getFlags() + expect(res.test).toEqual("test") }) }) }) diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index 04c0552457..6877561fcb 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -264,7 +264,7 @@ class TestConfiguration { admin = false, email = this.defaultUserValues.email, roles, - }: any = {}) { + }: any = {}): Promise { const db = tenancy.getTenantDB(this.getTenantId()) let existing try { diff --git a/packages/server/src/tests/utilities/api/user.ts b/packages/server/src/tests/utilities/api/user.ts index 2066315778..2ed23c0461 100644 --- a/packages/server/src/tests/utilities/api/user.ts +++ b/packages/server/src/tests/utilities/api/user.ts @@ -1,6 +1,12 @@ -import { FetchUserMetadataResponse } from "@budibase/types" +import { + FetchUserMetadataResponse, + FindUserMetadataResponse, + Flags, + UserMetadata, +} from "@budibase/types" import TestConfiguration from "../TestConfiguration" import { TestAPI } from "./base" +import { DocumentInsertResponse } from "@budibase/nano" export class UserAPI extends TestAPI { constructor(config: TestConfiguration) { @@ -26,10 +32,10 @@ export class UserAPI extends TestAPI { return res.body } - get = async ( + find = async ( id: string, { expectStatus } = { expectStatus: 200 } - ): Promise => { + ): Promise => { const res = await this.request .get(`/api/users/metadata/${id}`) .set(this.config.defaultHeaders()) @@ -45,4 +51,107 @@ export class UserAPI extends TestAPI { return res.body } + + update = async ( + user: UserMetadata, + { expectStatus } = { expectStatus: 200 } + ): Promise => { + const res = await this.request + .put(`/api/users/metadata`) + .set(this.config.defaultHeaders()) + .send(user) + .expect("Content-Type", /json/) + + if (res.status !== expectStatus) { + throw new Error( + `Expected status ${expectStatus} but got ${ + res.status + } with body ${JSON.stringify(res.body)}` + ) + } + + return res.body as DocumentInsertResponse + } + + updateSelf = async ( + user: UserMetadata, + { expectStatus } = { expectStatus: 200 } + ): Promise => { + const res = await this.request + .post(`/api/users/metadata/self`) + .set(this.config.defaultHeaders()) + .send(user) + .expect("Content-Type", /json/) + + if (res.status !== expectStatus) { + throw new Error( + `Expected status ${expectStatus} but got ${ + res.status + } with body ${JSON.stringify(res.body)}` + ) + } + + return res.body as DocumentInsertResponse + } + + destroy = async ( + id: string, + { expectStatus } = { expectStatus: 200 } + ): Promise<{ message: string }> => { + const res = await this.request + .delete(`/api/users/metadata/${id}`) + .set(this.config.defaultHeaders()) + .expect("Content-Type", /json/) + + if (res.status !== expectStatus) { + throw new Error( + `Expected status ${expectStatus} but got ${ + res.status + } with body ${JSON.stringify(res.body)}` + ) + } + + return res.body as { message: string } + } + + setFlag = async ( + flag: string, + value: any, + { expectStatus } = { expectStatus: 200 } + ): Promise<{ message: string }> => { + const res = await this.request + .post(`/api/users/flags`) + .set(this.config.defaultHeaders()) + .send({ flag, value }) + .expect("Content-Type", /json/) + + if (res.status !== expectStatus) { + throw new Error( + `Expected status ${expectStatus} but got ${ + res.status + } with body ${JSON.stringify(res.body)}` + ) + } + + return res.body as { message: string } + } + + getFlags = async ( + { expectStatus } = { expectStatus: 200 } + ): Promise => { + const res = await this.request + .get(`/api/users/flags`) + .set(this.config.defaultHeaders()) + .expect("Content-Type", /json/) + + if (res.status !== expectStatus) { + throw new Error( + `Expected status ${expectStatus} but got ${ + res.status + } with body ${JSON.stringify(res.body)}` + ) + } + + return res.body as Flags + } } diff --git a/packages/types/src/api/web/app/user.ts b/packages/types/src/api/web/app/user.ts index 2e0eeee7f8..7faec83e9c 100644 --- a/packages/types/src/api/web/app/user.ts +++ b/packages/types/src/api/web/app/user.ts @@ -1,3 +1,9 @@ -import { ContextUserMetadata } from "src/documents" +import { ContextUserMetadata } from "../../../" export type FetchUserMetadataResponse = ContextUserMetadata[] +export type FindUserMetadataResponse = ContextUserMetadata + +export interface SetFlagRequest { + flag: string + value: any +} diff --git a/packages/types/src/documents/account/flag.ts b/packages/types/src/documents/account/flag.ts new file mode 100644 index 0000000000..a214348fe7 --- /dev/null +++ b/packages/types/src/documents/account/flag.ts @@ -0,0 +1,5 @@ +import { Document } from "../../" + +export interface Flags extends Document { + [key: string]: any +} diff --git a/packages/types/src/documents/account/index.ts b/packages/types/src/documents/account/index.ts index 663fb91b58..1e0c800f39 100644 --- a/packages/types/src/documents/account/index.ts +++ b/packages/types/src/documents/account/index.ts @@ -1,2 +1,3 @@ export * from "./account" export * from "./user" +export * from "./flag"