Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(medusa): Implement listAndCount for UserService and update list endpoint #6190

Merged
merged 15 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/lucky-snails-mix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@medusajs/medusa": patch
"@medusajs/medusa-js": patch
"@medusajs/medusa-react": patch
---

fix(medusa): Implements `listAndCount` method for UserService, and updates list endpoint to accept the expected params.
fix(medusa-js): Update `admin.users.list` to accept query params.
fix(medusa-react): Update `useAdminUsers` hook to accept query params.
85 changes: 66 additions & 19 deletions integration-tests/api/__tests__/admin/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,25 +75,72 @@ describe("/admin/users", () => {

expect(response.status).toEqual(200)

expect(response.data.users).toMatchSnapshot([
{
id: "admin_user",
email: "admin@medusa.js",
api_token: "test_token",
role: "admin",
created_at: expect.any(String),
updated_at: expect.any(String),
},
{
id: "member-user",
role: "member",
email: "member@test.com",
first_name: "member",
last_name: "user",
created_at: expect.any(String),
updated_at: expect.any(String),
},
])
expect(response.data.users).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: "admin_user",
email: "admin@medusa.js",
api_token: "test_token",
role: "admin",
created_at: expect.any(String),
updated_at: expect.any(String),
}),
expect.objectContaining({
id: "member-user",
role: "member",
email: "member@test.com",
first_name: "member",
last_name: "user",
created_at: expect.any(String),
updated_at: expect.any(String),
}),
])
)
})

it("lists users that match the free text search", async () => {
const api = useApi()

const response = await api.get("/admin/users?q=member", adminReqConfig)

expect(response.status).toEqual(200)

expect(response.data.users.length).toEqual(1)
expect(response.data.users).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: "member-user",
role: "member",
email: "member@test.com",
first_name: "member",
last_name: "user",
created_at: expect.any(String),
updated_at: expect.any(String),
}),
])
)
})

it("orders users by created_at", async () => {
const api = useApi()

const response = await api.get(
"/admin/users?order=created_at",
adminReqConfig
)

expect(response.status).toEqual(200)
expect(response.data.users.length).toBeGreaterThan(0)

for (let i = 0; i < response.data.users.length - 1; i++) {
const user1 = response.data.users[i]
const user2 = response.data.users[i + 1]

const date1 = new Date(user1.created_at)
const date2 = new Date(user2.created_at)

expect(date1.getTime()).toBeLessThanOrEqual(date2.getTime())
}
})
})

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import { SetRelation, Merge } from "../core/ModelUtils"

export interface AdminGetUsersParams {
/**
* Filter by a user ID.
*/
id?: string
/**
* Filter by email.
*/
email?: string
/**
* Filter by first name.
*/
first_name?: string
/**
* Filter by last name.
*/
last_name?: string
/**
* term used to search users' first name, last name, and email.
*/
q?: string
/**
* A user field to sort-order the retrieved users by.
*/
order?: string
/**
* Filter by a creation date range.
*/
created_at?: {
/**
* filter by dates less than this date
*/
lt?: string
/**
* filter by dates greater than this date
*/
gt?: string
/**
* filter by dates less than or equal to this date
*/
lte?: string
/**
* filter by dates greater than or equal to this date
*/
gte?: string
}
/**
* Filter by an update date range.
*/
updated_at?: {
/**
* filter by dates less than this date
*/
lt?: string
/**
* filter by dates greater than this date
*/
gt?: string
/**
* filter by dates less than or equal to this date
*/
lte?: string
/**
* filter by dates greater than or equal to this date
*/
gte?: string
}
/**
* Filter by a deletion date range.
*/
deleted_at?: {
/**
* filter by dates less than this date
*/
lt?: string
/**
* filter by dates greater than this date
*/
gt?: string
/**
* filter by dates less than or equal to this date
*/
lte?: string
/**
* filter by dates greater than or equal to this date
*/
gte?: string
}
/**
* The number of users to skip when retrieving the users.
*/
offset?: number
/**
* Limit the number of users returned.
*/
limit?: number
/**
* Comma-separated relations that should be expanded in the returned users.
*/
expand?: string
/**
* Comma-separated fields that should be included in the returned users.
*/
fields?: string
}
1 change: 1 addition & 0 deletions packages/generated/client-types/src/lib/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export type { AdminGetStockLocationsParams } from "./AdminGetStockLocationsParam
export type { AdminGetSwapsParams } from "./AdminGetSwapsParams"
export type { AdminGetTaxRatesParams } from "./AdminGetTaxRatesParams"
export type { AdminGetTaxRatesTaxRateParams } from "./AdminGetTaxRatesTaxRateParams"
export type { AdminGetUsersParams } from "./AdminGetUsersParams"
export type { AdminGetVariantParams } from "./AdminGetVariantParams"
export type { AdminGetVariantsParams } from "./AdminGetVariantsParams"
export type { AdminGetVariantsVariantInventoryRes } from "./AdminGetVariantsVariantInventoryRes"
Expand Down
53 changes: 39 additions & 14 deletions packages/medusa-js/src/resources/admin/users.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,38 @@
import {
AdminDeleteUserRes,
AdminGetUsersParams,
AdminResetPasswordRequest,
AdminResetPasswordTokenRequest,
AdminUserRes,
AdminUsersListRes,
} from "@medusajs/medusa"
import qs from "qs"
import {
ResponsePromise,
AdminCreateUserPayload,
AdminUpdateUserPayload,
ResponsePromise,
} from "../.."
import BaseResource from "../base"

/**
* This class is used to send requests to [Admin User API Routes](https://docs.medusajs.com/api/admin#users). All its method
* are available in the JS Client under the `medusa.admin.users` property.
*
*
* All methods in this class require {@link AdminAuthResource.createSession | user authentication}.
*
*
* A store can have more than one user, each having the same privileges. Admins can manage users, their passwords, and more.
*
*
* Related Guide: [How to manage users](https://docs.medusajs.com/modules/users/admin/manage-users).
*/
class AdminUsersResource extends BaseResource {

/**
* Generate a password token for an admin user with a given email. This also triggers the `user.password_reset` event. So, if you have a Notification Service installed
* that can handle this event, a notification, such as an email, will be sent to the user. The token is triggered as part of the `user.password_reset` event's payload.
* that can handle this event, a notification, such as an email, will be sent to the user. The token is triggered as part of the `user.password_reset` event's payload.
* That token must be used later to reset the password using the {@link resetPassword} method.
* @param {AdminResetPasswordTokenRequest} payload - The user's reset details.
* @param {Record<string, any>} customHeaders - Custom headers to attach to the request.
* @returns {ResponsePromise<void>} Resolves when the token is generated successfully.
*
*
* @example
* import Medusa from "@medusajs/medusa-js"
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
Expand Down Expand Up @@ -60,7 +61,7 @@ class AdminUsersResource extends BaseResource {
* @param {AdminResetPasswordRequest} payload - The reset details.
* @param {Record<string, any>} customHeaders - Custom headers to attach to the request.
* @returns {ResponsePromise<AdminUserRes>} Resolves to the user's details.
*
*
* @example
* import Medusa from "@medusajs/medusa-js"
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
Expand All @@ -86,7 +87,7 @@ class AdminUsersResource extends BaseResource {
* @param {string} id - The user's ID.
* @param {Record<string, any>} customHeaders - Custom headers to attach to the request.
* @returns {ResponsePromise<AdminUserRes>} Resolves to the user's details.
*
*
* @example
* import Medusa from "@medusajs/medusa-js"
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
Expand All @@ -109,7 +110,7 @@ class AdminUsersResource extends BaseResource {
* @param {AdminCreateUserPayload} payload - The user to create.
* @param {Record<string, any>} customHeaders - Custom headers to attach to the request.
* @returns {ResponsePromise<AdminUserRes>} Resolves to the user's details.
*
*
* @example
* import Medusa from "@medusajs/medusa-js"
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
Expand All @@ -136,7 +137,7 @@ class AdminUsersResource extends BaseResource {
* @param {AdminUpdateUserPayload} payload - The attributes to update in the user.
* @param {Record<string, any>} customHeaders - Custom headers to attach to the request.
* @returns {ResponsePromise<AdminUserRes>} Resolves to the user's details.
*
*
* @example
* import Medusa from "@medusajs/medusa-js"
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
Expand All @@ -162,7 +163,7 @@ class AdminUsersResource extends BaseResource {
* @param {string} id - The user's ID.
* @param {Record<string, any>} customHeaders - Custom headers to attach to the request.
* @returns {ResponsePromise<AdminDeleteUserRes>} Resolves to the deletion operation's details.
*
*
* @example
* import Medusa from "@medusajs/medusa-js"
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
Expand All @@ -184,20 +185,44 @@ class AdminUsersResource extends BaseResource {
* Retrieve all admin users.
* @param {Record<string, any>} customHeaders - Custom headers to attach to the request.
* @returns {ResponsePromise<AdminUsersListRes>} Resolves to the list of users.
*
*
* @example
* To list users:
*
* import Medusa from "@medusajs/medusa-js"
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
* // must be previously logged in or use api token
* medusa.admin.users.list()
* .then(({ users }) => {
* console.log(users.length);
* })
*
* By default, only the first `20` users are returned. You can control pagination by specifying the `limit` and `offset` properties:
*
* ```ts
* import Medusa from "@medusajs/medusa-js"
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
* // must be previously logged in or use api token
* medusa.admin.users.list({
* limit,
* offset
* })
* .then(({ users, limit, offset, count }) => {
* console.log(users.length);
* })
* ```
*/
list(
query?: AdminGetUsersParams,
customHeaders: Record<string, any> = {}
): ResponsePromise<AdminUsersListRes> {
const path = `/admin/users`
let path = `/admin/users`

if (query) {
const queryString = qs.stringify(query)
path += `?${queryString}`
}

return this.client.request("GET", path, undefined, {}, customHeaders)
}
}
Expand Down
Loading
Loading