From 3b54f4db555a68f0bc5571c8cf658ec3ef690140 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Tue, 20 Aug 2024 16:29:36 +0300 Subject: [PATCH 1/4] feat(backend): Add Delete user profiel image --- packages/backend/src/api/endpoints/UserApi.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/backend/src/api/endpoints/UserApi.ts b/packages/backend/src/api/endpoints/UserApi.ts index 028793682db..20efe2f1917 100644 --- a/packages/backend/src/api/endpoints/UserApi.ts +++ b/packages/backend/src/api/endpoints/UserApi.ts @@ -277,4 +277,12 @@ export class UserAPI extends AbstractAPI { path: joinPaths(basePath, userId, 'unlock'), }); } + + public async deleteUserProfileImage(userId: string) { + this.requireId(userId); + return this.request({ + method: 'DELETE', + path: joinPaths(basePath, userId, 'profile_image'), + }); + } } From fdcabb565512860ac54f6083d86c6b3f784d4311 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Tue, 20 Aug 2024 16:30:07 +0300 Subject: [PATCH 2/4] feat(backend): Add Delete user profiel image --- packages/backend/src/api/endpoints/UserApi.ts | 520 +++++++++--------- 1 file changed, 266 insertions(+), 254 deletions(-) diff --git a/packages/backend/src/api/endpoints/UserApi.ts b/packages/backend/src/api/endpoints/UserApi.ts index 20efe2f1917..e52deee322b 100644 --- a/packages/backend/src/api/endpoints/UserApi.ts +++ b/packages/backend/src/api/endpoints/UserApi.ts @@ -1,288 +1,300 @@ -import type { ClerkPaginationRequest, OAuthProvider } from '@clerk/types'; +import type { ClerkPaginationRequest, OAuthProvider } from "@clerk/types"; -import runtime from '../../runtime'; -import { joinPaths } from '../../util/path'; -import type { OauthAccessToken, OrganizationMembership, User } from '../resources'; -import type { PaginatedResourceResponse } from '../resources/Deserializer'; -import { AbstractAPI } from './AbstractApi'; -import type { WithSign } from './util-types'; +import runtime from "../../runtime"; +import { joinPaths } from "../../util/path"; +import type { + OauthAccessToken, + OrganizationMembership, + User, +} from "../resources"; +import type { PaginatedResourceResponse } from "../resources/Deserializer"; +import { AbstractAPI } from "./AbstractApi"; +import type { WithSign } from "./util-types"; -const basePath = '/users'; +const basePath = "/users"; type UserCountParams = { - emailAddress?: string[]; - phoneNumber?: string[]; - username?: string[]; - web3Wallet?: string[]; - query?: string; - userId?: string[]; - externalId?: string[]; + emailAddress?: string[]; + phoneNumber?: string[]; + username?: string[]; + web3Wallet?: string[]; + query?: string; + userId?: string[]; + externalId?: string[]; }; type UserListParams = ClerkPaginationRequest< - UserCountParams & { - orderBy?: WithSign< - | 'created_at' - | 'updated_at' - | 'email_address' - | 'web3wallet' - | 'first_name' - | 'last_name' - | 'phone_number' - | 'username' - | 'last_active_at' - | 'last_sign_in_at' - >; - last_active_at_since?: number; - organizationId?: string[]; - } + UserCountParams & { + orderBy?: WithSign< + | "created_at" + | "updated_at" + | "email_address" + | "web3wallet" + | "first_name" + | "last_name" + | "phone_number" + | "username" + | "last_active_at" + | "last_sign_in_at" + >; + last_active_at_since?: number; + organizationId?: string[]; + } >; type UserMetadataParams = { - publicMetadata?: UserPublicMetadata; - privateMetadata?: UserPrivateMetadata; - unsafeMetadata?: UserUnsafeMetadata; + publicMetadata?: UserPublicMetadata; + privateMetadata?: UserPrivateMetadata; + unsafeMetadata?: UserUnsafeMetadata; }; type PasswordHasher = - | 'argon2i' - | 'argon2id' - | 'awscognito' - | 'bcrypt' - | 'bcrypt_sha256_django' - | 'md5' - | 'pbkdf2_sha256' - | 'pbkdf2_sha256_django' - | 'pbkdf2_sha1' - | 'phpass' - | 'scrypt_firebase' - | 'scrypt_werkzeug' - | 'sha256'; + | "argon2i" + | "argon2id" + | "awscognito" + | "bcrypt" + | "bcrypt_sha256_django" + | "md5" + | "pbkdf2_sha256" + | "pbkdf2_sha256_django" + | "pbkdf2_sha1" + | "phpass" + | "scrypt_firebase" + | "scrypt_werkzeug" + | "sha256"; type UserPasswordHashingParams = { - passwordDigest: string; - passwordHasher: PasswordHasher; + passwordDigest: string; + passwordHasher: PasswordHasher; }; type CreateUserParams = { - externalId?: string; - emailAddress?: string[]; - phoneNumber?: string[]; - username?: string; - password?: string; - firstName?: string; - lastName?: string; - skipPasswordChecks?: boolean; - skipPasswordRequirement?: boolean; - totpSecret?: string; - backupCodes?: string[]; - createdAt?: Date; + externalId?: string; + emailAddress?: string[]; + phoneNumber?: string[]; + username?: string; + password?: string; + firstName?: string; + lastName?: string; + skipPasswordChecks?: boolean; + skipPasswordRequirement?: boolean; + totpSecret?: string; + backupCodes?: string[]; + createdAt?: Date; } & UserMetadataParams & - (UserPasswordHashingParams | object); + (UserPasswordHashingParams | object); type UpdateUserParams = { - firstName?: string; - lastName?: string; - username?: string; - password?: string; - skipPasswordChecks?: boolean; - signOutOfOtherSessions?: boolean; - primaryEmailAddressID?: string; - primaryPhoneNumberID?: string; - primaryWeb3WalletID?: string; - profileImageID?: string; - totpSecret?: string; - backupCodes?: string[]; - externalId?: string; - createdAt?: Date; - createOrganizationEnabled?: boolean; - createOrganizationsLimit?: number; + firstName?: string; + lastName?: string; + username?: string; + password?: string; + skipPasswordChecks?: boolean; + signOutOfOtherSessions?: boolean; + primaryEmailAddressID?: string; + primaryPhoneNumberID?: string; + primaryWeb3WalletID?: string; + profileImageID?: string; + totpSecret?: string; + backupCodes?: string[]; + externalId?: string; + createdAt?: Date; + createOrganizationEnabled?: boolean; + createOrganizationsLimit?: number; } & UserMetadataParams & - (UserPasswordHashingParams | object); + (UserPasswordHashingParams | object); type GetOrganizationMembershipListParams = ClerkPaginationRequest<{ - userId: string; + userId: string; }>; type VerifyPasswordParams = { - userId: string; - password: string; + userId: string; + password: string; }; type VerifyTOTPParams = { - userId: string; - code: string; + userId: string; + code: string; }; export class UserAPI extends AbstractAPI { - public async getUserList(params: UserListParams = {}) { - const { limit, offset, orderBy, ...userCountParams } = params; - // TODO(dimkl): Temporary change to populate totalCount using a 2nd BAPI call to /users/count endpoint - // until we update the /users endpoint to be paginated in a next BAPI version. - // In some edge cases the data.length != totalCount due to a creation of a user between the 2 api responses - const [data, totalCount] = await Promise.all([ - this.request({ - method: 'GET', - path: basePath, - queryParams: params, - }), - this.getCount(userCountParams), - ]); - return { data, totalCount } as PaginatedResourceResponse; - } - - public async getUser(userId: string) { - this.requireId(userId); - return this.request({ - method: 'GET', - path: joinPaths(basePath, userId), - }); - } - - public async createUser(params: CreateUserParams) { - return this.request({ - method: 'POST', - path: basePath, - bodyParams: params, - }); - } - - public async updateUser(userId: string, params: UpdateUserParams = {}) { - this.requireId(userId); - - return this.request({ - method: 'PATCH', - path: joinPaths(basePath, userId), - bodyParams: params, - }); - } - - public async updateUserProfileImage(userId: string, params: { file: Blob | File }) { - this.requireId(userId); - - const formData = new runtime.FormData(); - formData.append('file', params?.file); - - return this.request({ - method: 'POST', - path: joinPaths(basePath, userId, 'profile_image'), - formData, - }); - } - - public async updateUserMetadata(userId: string, params: UserMetadataParams) { - this.requireId(userId); - - return this.request({ - method: 'PATCH', - path: joinPaths(basePath, userId, 'metadata'), - bodyParams: params, - }); - } - - public async deleteUser(userId: string) { - this.requireId(userId); - return this.request({ - method: 'DELETE', - path: joinPaths(basePath, userId), - }); - } - - public async getCount(params: UserCountParams = {}) { - return this.request({ - method: 'GET', - path: joinPaths(basePath, 'count'), - queryParams: params, - }); - } - - public async getUserOauthAccessToken(userId: string, provider: `oauth_${OAuthProvider}`) { - this.requireId(userId); - return this.request>({ - method: 'GET', - path: joinPaths(basePath, userId, 'oauth_access_tokens', provider), - queryParams: { paginated: true }, - }); - } - - public async disableUserMFA(userId: string) { - this.requireId(userId); - return this.request({ - method: 'DELETE', - path: joinPaths(basePath, userId, 'mfa'), - }); - } - - public async getOrganizationMembershipList(params: GetOrganizationMembershipListParams) { - const { userId, limit, offset } = params; - this.requireId(userId); - - return this.request>({ - method: 'GET', - path: joinPaths(basePath, userId, 'organization_memberships'), - queryParams: { limit, offset }, - }); - } - - public async verifyPassword(params: VerifyPasswordParams) { - const { userId, password } = params; - this.requireId(userId); - - return this.request<{ verified: true }>({ - method: 'POST', - path: joinPaths(basePath, userId, 'verify_password'), - bodyParams: { password }, - }); - } - - public async verifyTOTP(params: VerifyTOTPParams) { - const { userId, code } = params; - this.requireId(userId); - - return this.request<{ verified: true; code_type: 'totp' }>({ - method: 'POST', - path: joinPaths(basePath, userId, 'verify_totp'), - bodyParams: { code }, - }); - } - - public async banUser(userId: string) { - this.requireId(userId); - return this.request({ - method: 'POST', - path: joinPaths(basePath, userId, 'ban'), - }); - } - - public async unbanUser(userId: string) { - this.requireId(userId); - return this.request({ - method: 'POST', - path: joinPaths(basePath, userId, 'unban'), - }); - } - - public async lockUser(userId: string) { - this.requireId(userId); - return this.request({ - method: 'POST', - path: joinPaths(basePath, userId, 'lock'), - }); - } - - public async unlockUser(userId: string) { - this.requireId(userId); - return this.request({ - method: 'POST', - path: joinPaths(basePath, userId, 'unlock'), - }); - } - - public async deleteUserProfileImage(userId: string) { - this.requireId(userId); - return this.request({ - method: 'DELETE', - path: joinPaths(basePath, userId, 'profile_image'), - }); - } + public async getUserList(params: UserListParams = {}) { + const { limit, offset, orderBy, ...userCountParams } = params; + // TODO(dimkl): Temporary change to populate totalCount using a 2nd BAPI call to /users/count endpoint + // until we update the /users endpoint to be paginated in a next BAPI version. + // In some edge cases the data.length != totalCount due to a creation of a user between the 2 api responses + const [data, totalCount] = await Promise.all([ + this.request({ + method: "GET", + path: basePath, + queryParams: params, + }), + this.getCount(userCountParams), + ]); + return { data, totalCount } as PaginatedResourceResponse; + } + + public async getUser(userId: string) { + this.requireId(userId); + return this.request({ + method: "GET", + path: joinPaths(basePath, userId), + }); + } + + public async createUser(params: CreateUserParams) { + return this.request({ + method: "POST", + path: basePath, + bodyParams: params, + }); + } + + public async updateUser(userId: string, params: UpdateUserParams = {}) { + this.requireId(userId); + + return this.request({ + method: "PATCH", + path: joinPaths(basePath, userId), + bodyParams: params, + }); + } + + public async updateUserProfileImage( + userId: string, + params: { file: Blob | File }, + ) { + this.requireId(userId); + + const formData = new runtime.FormData(); + formData.append("file", params?.file); + + return this.request({ + method: "POST", + path: joinPaths(basePath, userId, "profile_image"), + formData, + }); + } + + public async updateUserMetadata(userId: string, params: UserMetadataParams) { + this.requireId(userId); + + return this.request({ + method: "PATCH", + path: joinPaths(basePath, userId, "metadata"), + bodyParams: params, + }); + } + + public async deleteUser(userId: string) { + this.requireId(userId); + return this.request({ + method: "DELETE", + path: joinPaths(basePath, userId), + }); + } + + public async getCount(params: UserCountParams = {}) { + return this.request({ + method: "GET", + path: joinPaths(basePath, "count"), + queryParams: params, + }); + } + + public async getUserOauthAccessToken( + userId: string, + provider: `oauth_${OAuthProvider}`, + ) { + this.requireId(userId); + return this.request>({ + method: "GET", + path: joinPaths(basePath, userId, "oauth_access_tokens", provider), + queryParams: { paginated: true }, + }); + } + + public async disableUserMFA(userId: string) { + this.requireId(userId); + return this.request({ + method: "DELETE", + path: joinPaths(basePath, userId, "mfa"), + }); + } + + public async getOrganizationMembershipList( + params: GetOrganizationMembershipListParams, + ) { + const { userId, limit, offset } = params; + this.requireId(userId); + + return this.request>({ + method: "GET", + path: joinPaths(basePath, userId, "organization_memberships"), + queryParams: { limit, offset }, + }); + } + + public async verifyPassword(params: VerifyPasswordParams) { + const { userId, password } = params; + this.requireId(userId); + + return this.request<{ verified: true }>({ + method: "POST", + path: joinPaths(basePath, userId, "verify_password"), + bodyParams: { password }, + }); + } + + public async verifyTOTP(params: VerifyTOTPParams) { + const { userId, code } = params; + this.requireId(userId); + + return this.request<{ verified: true; code_type: "totp" }>({ + method: "POST", + path: joinPaths(basePath, userId, "verify_totp"), + bodyParams: { code }, + }); + } + + public async banUser(userId: string) { + this.requireId(userId); + return this.request({ + method: "POST", + path: joinPaths(basePath, userId, "ban"), + }); + } + + public async unbanUser(userId: string) { + this.requireId(userId); + return this.request({ + method: "POST", + path: joinPaths(basePath, userId, "unban"), + }); + } + + public async lockUser(userId: string) { + this.requireId(userId); + return this.request({ + method: "POST", + path: joinPaths(basePath, userId, "lock"), + }); + } + + public async unlockUser(userId: string) { + this.requireId(userId); + return this.request({ + method: "POST", + path: joinPaths(basePath, userId, "unlock"), + }); + } + + public async deleteUserProfileImage(userId: string) { + this.requireId(userId); + return this.request({ + method: "DELETE", + path: joinPaths(basePath, userId, "profile_image"), + }); + } } From 33dea4d7283795da09d39024337b25f6599559d2 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Tue, 20 Aug 2024 16:32:16 +0300 Subject: [PATCH 3/4] chore(repo): Add changeset --- .changeset/few-teachers-brake.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/few-teachers-brake.md diff --git a/.changeset/few-teachers-brake.md b/.changeset/few-teachers-brake.md new file mode 100644 index 00000000000..f18743a28a1 --- /dev/null +++ b/.changeset/few-teachers-brake.md @@ -0,0 +1,5 @@ +--- +"@clerk/backend": minor +--- + +Add `deleteUserProfileImage` method to the UserAPI class. From c7c6c35c5465e0dcb25dbf35d2cc8ebe94e57a98 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Tue, 20 Aug 2024 16:36:26 +0300 Subject: [PATCH 4/4] chore(backend): Apply formatting --- packages/backend/src/api/endpoints/UserApi.ts | 520 +++++++++--------- 1 file changed, 254 insertions(+), 266 deletions(-) diff --git a/packages/backend/src/api/endpoints/UserApi.ts b/packages/backend/src/api/endpoints/UserApi.ts index e52deee322b..20efe2f1917 100644 --- a/packages/backend/src/api/endpoints/UserApi.ts +++ b/packages/backend/src/api/endpoints/UserApi.ts @@ -1,300 +1,288 @@ -import type { ClerkPaginationRequest, OAuthProvider } from "@clerk/types"; +import type { ClerkPaginationRequest, OAuthProvider } from '@clerk/types'; -import runtime from "../../runtime"; -import { joinPaths } from "../../util/path"; -import type { - OauthAccessToken, - OrganizationMembership, - User, -} from "../resources"; -import type { PaginatedResourceResponse } from "../resources/Deserializer"; -import { AbstractAPI } from "./AbstractApi"; -import type { WithSign } from "./util-types"; +import runtime from '../../runtime'; +import { joinPaths } from '../../util/path'; +import type { OauthAccessToken, OrganizationMembership, User } from '../resources'; +import type { PaginatedResourceResponse } from '../resources/Deserializer'; +import { AbstractAPI } from './AbstractApi'; +import type { WithSign } from './util-types'; -const basePath = "/users"; +const basePath = '/users'; type UserCountParams = { - emailAddress?: string[]; - phoneNumber?: string[]; - username?: string[]; - web3Wallet?: string[]; - query?: string; - userId?: string[]; - externalId?: string[]; + emailAddress?: string[]; + phoneNumber?: string[]; + username?: string[]; + web3Wallet?: string[]; + query?: string; + userId?: string[]; + externalId?: string[]; }; type UserListParams = ClerkPaginationRequest< - UserCountParams & { - orderBy?: WithSign< - | "created_at" - | "updated_at" - | "email_address" - | "web3wallet" - | "first_name" - | "last_name" - | "phone_number" - | "username" - | "last_active_at" - | "last_sign_in_at" - >; - last_active_at_since?: number; - organizationId?: string[]; - } + UserCountParams & { + orderBy?: WithSign< + | 'created_at' + | 'updated_at' + | 'email_address' + | 'web3wallet' + | 'first_name' + | 'last_name' + | 'phone_number' + | 'username' + | 'last_active_at' + | 'last_sign_in_at' + >; + last_active_at_since?: number; + organizationId?: string[]; + } >; type UserMetadataParams = { - publicMetadata?: UserPublicMetadata; - privateMetadata?: UserPrivateMetadata; - unsafeMetadata?: UserUnsafeMetadata; + publicMetadata?: UserPublicMetadata; + privateMetadata?: UserPrivateMetadata; + unsafeMetadata?: UserUnsafeMetadata; }; type PasswordHasher = - | "argon2i" - | "argon2id" - | "awscognito" - | "bcrypt" - | "bcrypt_sha256_django" - | "md5" - | "pbkdf2_sha256" - | "pbkdf2_sha256_django" - | "pbkdf2_sha1" - | "phpass" - | "scrypt_firebase" - | "scrypt_werkzeug" - | "sha256"; + | 'argon2i' + | 'argon2id' + | 'awscognito' + | 'bcrypt' + | 'bcrypt_sha256_django' + | 'md5' + | 'pbkdf2_sha256' + | 'pbkdf2_sha256_django' + | 'pbkdf2_sha1' + | 'phpass' + | 'scrypt_firebase' + | 'scrypt_werkzeug' + | 'sha256'; type UserPasswordHashingParams = { - passwordDigest: string; - passwordHasher: PasswordHasher; + passwordDigest: string; + passwordHasher: PasswordHasher; }; type CreateUserParams = { - externalId?: string; - emailAddress?: string[]; - phoneNumber?: string[]; - username?: string; - password?: string; - firstName?: string; - lastName?: string; - skipPasswordChecks?: boolean; - skipPasswordRequirement?: boolean; - totpSecret?: string; - backupCodes?: string[]; - createdAt?: Date; + externalId?: string; + emailAddress?: string[]; + phoneNumber?: string[]; + username?: string; + password?: string; + firstName?: string; + lastName?: string; + skipPasswordChecks?: boolean; + skipPasswordRequirement?: boolean; + totpSecret?: string; + backupCodes?: string[]; + createdAt?: Date; } & UserMetadataParams & - (UserPasswordHashingParams | object); + (UserPasswordHashingParams | object); type UpdateUserParams = { - firstName?: string; - lastName?: string; - username?: string; - password?: string; - skipPasswordChecks?: boolean; - signOutOfOtherSessions?: boolean; - primaryEmailAddressID?: string; - primaryPhoneNumberID?: string; - primaryWeb3WalletID?: string; - profileImageID?: string; - totpSecret?: string; - backupCodes?: string[]; - externalId?: string; - createdAt?: Date; - createOrganizationEnabled?: boolean; - createOrganizationsLimit?: number; + firstName?: string; + lastName?: string; + username?: string; + password?: string; + skipPasswordChecks?: boolean; + signOutOfOtherSessions?: boolean; + primaryEmailAddressID?: string; + primaryPhoneNumberID?: string; + primaryWeb3WalletID?: string; + profileImageID?: string; + totpSecret?: string; + backupCodes?: string[]; + externalId?: string; + createdAt?: Date; + createOrganizationEnabled?: boolean; + createOrganizationsLimit?: number; } & UserMetadataParams & - (UserPasswordHashingParams | object); + (UserPasswordHashingParams | object); type GetOrganizationMembershipListParams = ClerkPaginationRequest<{ - userId: string; + userId: string; }>; type VerifyPasswordParams = { - userId: string; - password: string; + userId: string; + password: string; }; type VerifyTOTPParams = { - userId: string; - code: string; + userId: string; + code: string; }; export class UserAPI extends AbstractAPI { - public async getUserList(params: UserListParams = {}) { - const { limit, offset, orderBy, ...userCountParams } = params; - // TODO(dimkl): Temporary change to populate totalCount using a 2nd BAPI call to /users/count endpoint - // until we update the /users endpoint to be paginated in a next BAPI version. - // In some edge cases the data.length != totalCount due to a creation of a user between the 2 api responses - const [data, totalCount] = await Promise.all([ - this.request({ - method: "GET", - path: basePath, - queryParams: params, - }), - this.getCount(userCountParams), - ]); - return { data, totalCount } as PaginatedResourceResponse; - } - - public async getUser(userId: string) { - this.requireId(userId); - return this.request({ - method: "GET", - path: joinPaths(basePath, userId), - }); - } - - public async createUser(params: CreateUserParams) { - return this.request({ - method: "POST", - path: basePath, - bodyParams: params, - }); - } - - public async updateUser(userId: string, params: UpdateUserParams = {}) { - this.requireId(userId); - - return this.request({ - method: "PATCH", - path: joinPaths(basePath, userId), - bodyParams: params, - }); - } - - public async updateUserProfileImage( - userId: string, - params: { file: Blob | File }, - ) { - this.requireId(userId); - - const formData = new runtime.FormData(); - formData.append("file", params?.file); - - return this.request({ - method: "POST", - path: joinPaths(basePath, userId, "profile_image"), - formData, - }); - } - - public async updateUserMetadata(userId: string, params: UserMetadataParams) { - this.requireId(userId); - - return this.request({ - method: "PATCH", - path: joinPaths(basePath, userId, "metadata"), - bodyParams: params, - }); - } - - public async deleteUser(userId: string) { - this.requireId(userId); - return this.request({ - method: "DELETE", - path: joinPaths(basePath, userId), - }); - } - - public async getCount(params: UserCountParams = {}) { - return this.request({ - method: "GET", - path: joinPaths(basePath, "count"), - queryParams: params, - }); - } - - public async getUserOauthAccessToken( - userId: string, - provider: `oauth_${OAuthProvider}`, - ) { - this.requireId(userId); - return this.request>({ - method: "GET", - path: joinPaths(basePath, userId, "oauth_access_tokens", provider), - queryParams: { paginated: true }, - }); - } - - public async disableUserMFA(userId: string) { - this.requireId(userId); - return this.request({ - method: "DELETE", - path: joinPaths(basePath, userId, "mfa"), - }); - } - - public async getOrganizationMembershipList( - params: GetOrganizationMembershipListParams, - ) { - const { userId, limit, offset } = params; - this.requireId(userId); - - return this.request>({ - method: "GET", - path: joinPaths(basePath, userId, "organization_memberships"), - queryParams: { limit, offset }, - }); - } - - public async verifyPassword(params: VerifyPasswordParams) { - const { userId, password } = params; - this.requireId(userId); - - return this.request<{ verified: true }>({ - method: "POST", - path: joinPaths(basePath, userId, "verify_password"), - bodyParams: { password }, - }); - } - - public async verifyTOTP(params: VerifyTOTPParams) { - const { userId, code } = params; - this.requireId(userId); - - return this.request<{ verified: true; code_type: "totp" }>({ - method: "POST", - path: joinPaths(basePath, userId, "verify_totp"), - bodyParams: { code }, - }); - } - - public async banUser(userId: string) { - this.requireId(userId); - return this.request({ - method: "POST", - path: joinPaths(basePath, userId, "ban"), - }); - } - - public async unbanUser(userId: string) { - this.requireId(userId); - return this.request({ - method: "POST", - path: joinPaths(basePath, userId, "unban"), - }); - } - - public async lockUser(userId: string) { - this.requireId(userId); - return this.request({ - method: "POST", - path: joinPaths(basePath, userId, "lock"), - }); - } - - public async unlockUser(userId: string) { - this.requireId(userId); - return this.request({ - method: "POST", - path: joinPaths(basePath, userId, "unlock"), - }); - } - - public async deleteUserProfileImage(userId: string) { - this.requireId(userId); - return this.request({ - method: "DELETE", - path: joinPaths(basePath, userId, "profile_image"), - }); - } + public async getUserList(params: UserListParams = {}) { + const { limit, offset, orderBy, ...userCountParams } = params; + // TODO(dimkl): Temporary change to populate totalCount using a 2nd BAPI call to /users/count endpoint + // until we update the /users endpoint to be paginated in a next BAPI version. + // In some edge cases the data.length != totalCount due to a creation of a user between the 2 api responses + const [data, totalCount] = await Promise.all([ + this.request({ + method: 'GET', + path: basePath, + queryParams: params, + }), + this.getCount(userCountParams), + ]); + return { data, totalCount } as PaginatedResourceResponse; + } + + public async getUser(userId: string) { + this.requireId(userId); + return this.request({ + method: 'GET', + path: joinPaths(basePath, userId), + }); + } + + public async createUser(params: CreateUserParams) { + return this.request({ + method: 'POST', + path: basePath, + bodyParams: params, + }); + } + + public async updateUser(userId: string, params: UpdateUserParams = {}) { + this.requireId(userId); + + return this.request({ + method: 'PATCH', + path: joinPaths(basePath, userId), + bodyParams: params, + }); + } + + public async updateUserProfileImage(userId: string, params: { file: Blob | File }) { + this.requireId(userId); + + const formData = new runtime.FormData(); + formData.append('file', params?.file); + + return this.request({ + method: 'POST', + path: joinPaths(basePath, userId, 'profile_image'), + formData, + }); + } + + public async updateUserMetadata(userId: string, params: UserMetadataParams) { + this.requireId(userId); + + return this.request({ + method: 'PATCH', + path: joinPaths(basePath, userId, 'metadata'), + bodyParams: params, + }); + } + + public async deleteUser(userId: string) { + this.requireId(userId); + return this.request({ + method: 'DELETE', + path: joinPaths(basePath, userId), + }); + } + + public async getCount(params: UserCountParams = {}) { + return this.request({ + method: 'GET', + path: joinPaths(basePath, 'count'), + queryParams: params, + }); + } + + public async getUserOauthAccessToken(userId: string, provider: `oauth_${OAuthProvider}`) { + this.requireId(userId); + return this.request>({ + method: 'GET', + path: joinPaths(basePath, userId, 'oauth_access_tokens', provider), + queryParams: { paginated: true }, + }); + } + + public async disableUserMFA(userId: string) { + this.requireId(userId); + return this.request({ + method: 'DELETE', + path: joinPaths(basePath, userId, 'mfa'), + }); + } + + public async getOrganizationMembershipList(params: GetOrganizationMembershipListParams) { + const { userId, limit, offset } = params; + this.requireId(userId); + + return this.request>({ + method: 'GET', + path: joinPaths(basePath, userId, 'organization_memberships'), + queryParams: { limit, offset }, + }); + } + + public async verifyPassword(params: VerifyPasswordParams) { + const { userId, password } = params; + this.requireId(userId); + + return this.request<{ verified: true }>({ + method: 'POST', + path: joinPaths(basePath, userId, 'verify_password'), + bodyParams: { password }, + }); + } + + public async verifyTOTP(params: VerifyTOTPParams) { + const { userId, code } = params; + this.requireId(userId); + + return this.request<{ verified: true; code_type: 'totp' }>({ + method: 'POST', + path: joinPaths(basePath, userId, 'verify_totp'), + bodyParams: { code }, + }); + } + + public async banUser(userId: string) { + this.requireId(userId); + return this.request({ + method: 'POST', + path: joinPaths(basePath, userId, 'ban'), + }); + } + + public async unbanUser(userId: string) { + this.requireId(userId); + return this.request({ + method: 'POST', + path: joinPaths(basePath, userId, 'unban'), + }); + } + + public async lockUser(userId: string) { + this.requireId(userId); + return this.request({ + method: 'POST', + path: joinPaths(basePath, userId, 'lock'), + }); + } + + public async unlockUser(userId: string) { + this.requireId(userId); + return this.request({ + method: 'POST', + path: joinPaths(basePath, userId, 'unlock'), + }); + } + + public async deleteUserProfileImage(userId: string) { + this.requireId(userId); + return this.request({ + method: 'DELETE', + path: joinPaths(basePath, userId, 'profile_image'), + }); + } }