feat(medusa): allow users deletion (#13960)
## Summary
**What** — What changes are introduced in this PR?
Allow users to delete other users and prevent them from deleting themselves.
**Why** — Why are these changes relevant or necessary?
Inability to delete other users causes old users that maybe don't work anymore with the business to have access still.
**How** — How have these changes been implemented?
Inverted the check in the admin delete user endpoint, to allow users deleting other users but themselves.
**Testing** — How have these changes been tested, or how can the reviewer test the feature?
Integration tests
---
## Examples
Provide examples or code snippets that demonstrate how this feature works, or how it can be used in practice.
This helps with documentation and ensures maintainers can quickly understand and verify the change.
```ts
// Example usage
```
---
## Checklist
Please ensure the following before requesting a review:
- [x] I have added a **changeset** for this PR
- Every non-breaking change should be marked as a **patch**
- To add a changeset, run `yarn changeset` and follow the prompts
- [x] The changes are covered by relevant **tests**
- [x] I have verified the code works as intended locally
- [x] I have linked the related issue(s) if applicable
---
## Additional Context
Add any additional context, related issues, or references that might help the reviewer understand this PR.
closes OPS-97
---
> [!NOTE]
> Enables deleting other users via admin DELETE endpoint while blocking self-deletion, with corresponding integration tests and changeset.
>
> - **Backend**
> - Update `DELETE /admin/users/:id` in `packages/medusa/src/api/admin/users/[id]/route.ts`:
> - Disallow self-deletion when `actor_id === id` with `NOT_ALLOWED` error.
> - Execute `removeUserAccountWorkflow` and return standard delete response.
> - **Tests**
> - Expand `integration-tests/http/__tests__/user/admin/user.spec.ts`:
> - Create a second admin user; delete it and verify auth identity `app_metadata` no longer includes `user_id`.
> - Confirm token still authenticates but access is revoked (401 on `/admin/users/me`).
> - Assert self-deletion returns 400 with message `"A user cannot delete itself"`.
> - **Changeset**
> - Add `.changeset/dull-plants-create.md` (patch for `@medusajs/medusa`).
>
> <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f1f8252b91593b8a8fb03dc9d26460d09a10cfaa. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup>
This commit is contained in:
@@ -106,14 +106,25 @@ medusaIntegrationTestRunner({
|
||||
|
||||
describe("DELETE /admin/users", () => {
|
||||
it("Deletes a user and updates associated auth identity", async () => {
|
||||
const userTwoAdminHeaders = {
|
||||
headers: { "x-medusa-access-token": "test_token" },
|
||||
}
|
||||
|
||||
const { user: userTwo, authIdentity: userTwoAuthIdentity } = await createAdminUser(
|
||||
dbConnection,
|
||||
userTwoAdminHeaders,
|
||||
container,
|
||||
{ email: "test@test.com" },
|
||||
)
|
||||
|
||||
const response = await api.delete(
|
||||
`/admin/users/${user.id}`,
|
||||
`/admin/users/${userTwo.id}`,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data).toEqual({
|
||||
id: user.id,
|
||||
id: userTwo.id,
|
||||
object: "user",
|
||||
deleted: true,
|
||||
})
|
||||
@@ -121,15 +132,15 @@ medusaIntegrationTestRunner({
|
||||
const authModule: IAuthModuleService = container.resolve(Modules.AUTH)
|
||||
|
||||
const updatedAuthIdentity = await authModule.retrieveAuthIdentity(
|
||||
authIdentity.id
|
||||
userTwoAuthIdentity.id
|
||||
)
|
||||
|
||||
// Ensure the auth identity has been updated to not contain the user's id
|
||||
expect(updatedAuthIdentity).toEqual(
|
||||
expect.objectContaining({
|
||||
id: authIdentity.id,
|
||||
id: userTwoAuthIdentity.id,
|
||||
app_metadata: expect.not.objectContaining({
|
||||
user_id: user.id,
|
||||
user_id: userTwo.id,
|
||||
}),
|
||||
})
|
||||
)
|
||||
@@ -137,7 +148,7 @@ medusaIntegrationTestRunner({
|
||||
// Authentication should still succeed
|
||||
const authenticateToken = (
|
||||
await api.post(`/auth/user/emailpass`, {
|
||||
email: user.email,
|
||||
email: userTwo.email,
|
||||
password: "somepassword",
|
||||
})
|
||||
).data.token
|
||||
@@ -156,22 +167,14 @@ medusaIntegrationTestRunner({
|
||||
expect(meResponse.response.status).toEqual(401)
|
||||
})
|
||||
|
||||
it("throws if you attempt to delete another user", async () => {
|
||||
const userModule = container.resolve(Modules.USER)
|
||||
|
||||
const userTwo = await userModule.createUsers({
|
||||
email: "test@test.com",
|
||||
password: "test",
|
||||
role: "member",
|
||||
})
|
||||
|
||||
it("throws if you attempt to delete your own user", async () => {
|
||||
const error = await api
|
||||
.delete(`/admin/users/${userTwo.id}`, adminHeaders)
|
||||
.delete(`/admin/users/${user.id}`, adminHeaders)
|
||||
.catch((e) => e)
|
||||
|
||||
expect(error.response.status).toEqual(400)
|
||||
expect(error.response.data.message).toEqual(
|
||||
"You are not allowed to delete other users"
|
||||
"A user cannot delete itself"
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user