docs: added docs for deleting user of actor type (#9104)
- Added to general guide on creating actor type how to delete its user later. - Added to restaurant delivery recipe how to delete a restaurant admin
This commit is contained in:
@@ -295,3 +295,124 @@ curl 'http://localhost:9000/manager/me' \
|
||||
```
|
||||
|
||||
Whenever you want to log in as a manager, use the `/auth/manager/emailpass` API route, as explained in step 3.
|
||||
|
||||
---
|
||||
|
||||
## Delete User of Actor Type
|
||||
|
||||
When you delete a user of the actor type, you must update its auth identity to remove the association to the user.
|
||||
|
||||
For example, create the following workflow that deletes a manager and updates its auth identity, create the file `src/workflows/delete-manager.ts` with the following content:
|
||||
|
||||
```ts title="src/workflows/delete-manager.ts" collapsibleLines="1-6" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
createStep,
|
||||
StepResponse,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
import ManagerModuleService from "../modules/manager/service"
|
||||
|
||||
export type DeleteManagerWorkflow = {
|
||||
id: string
|
||||
}
|
||||
|
||||
const deleteManagerStep = createStep(
|
||||
"delete-manager-step",
|
||||
async (
|
||||
{ id }: DeleteManagerWorkflow,
|
||||
{ container }) => {
|
||||
const managerModuleService: ManagerModuleService =
|
||||
container.resolve("managerModuleService")
|
||||
|
||||
const manager = await managerModuleService.retrieve(id)
|
||||
|
||||
await managerModuleService.deleteManagers(id)
|
||||
|
||||
return new StepResponse(undefined, { manager })
|
||||
},
|
||||
async ({ manager }, { container }) => {
|
||||
const managerModuleService: ManagerModuleService =
|
||||
container.resolve("managerModuleService")
|
||||
|
||||
await managerModuleService.createManagers(manager)
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
You add a step that deletes the manager using the `deleteManagers` method of the module's main service. In the compensation function, you create the manager again.
|
||||
|
||||
Next, in the same file, add the workflow that deletes a manager:
|
||||
|
||||
export const deleteHighlights = [
|
||||
["30", "manager_id", "If your actor type has a different name, such as vendor, change it to be `{actor_type}_id`."]
|
||||
]
|
||||
|
||||
```ts title="src/workflows/delete-manager.ts" collapsibleLines="1-15" expandButtonLabel="Show Imports" highlights={deleteHighlights}
|
||||
// other imports
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
import {
|
||||
WorkflowData,
|
||||
WorkflowResponse,
|
||||
createWorkflow,
|
||||
transform,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
import {
|
||||
setAuthAppMetadataStep,
|
||||
useRemoteQueryStep,
|
||||
} from "@medusajs/core-flows"
|
||||
|
||||
// ...
|
||||
|
||||
export const deleteManagerWorkflow = createWorkflow(
|
||||
"delete-manager",
|
||||
(
|
||||
input: WorkflowData<DeleteManagerWorkflow>
|
||||
): WorkflowResponse<string> => {
|
||||
deleteManagerStep(input)
|
||||
|
||||
const authIdentities = useRemoteQueryStep({
|
||||
entry_point: "auth_identity",
|
||||
fields: ["id"],
|
||||
variables: {
|
||||
filters: {
|
||||
app_metadata: {
|
||||
// the ID is of the format `{actor_type}_id`.
|
||||
manager_id: input.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const authIdentity = transform(
|
||||
{ authIdentities },
|
||||
({ authIdentities }) => {
|
||||
const authIdentity = authIdentities[0]
|
||||
|
||||
if (!authIdentity) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
"Auth identity not found"
|
||||
)
|
||||
}
|
||||
|
||||
return authIdentity
|
||||
}
|
||||
)
|
||||
|
||||
setAuthAppMetadataStep({
|
||||
authIdentityId: authIdentity.id,
|
||||
actorType: "manager",
|
||||
value: null,
|
||||
})
|
||||
|
||||
return new WorkflowResponse(input.id)
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
In the workflow, you:
|
||||
|
||||
1. Use the `deleteManagerStep` defined earlier to delete the manager.
|
||||
2. Retrieve the auth identity of the manager using Query. To do that, you filter the `app_metadata` property of an auth identity, which holds the user's ID under `{actor_type_name}_id`. So, in this case, it's `manager_id`.
|
||||
3. Check that the auth identity exist, then, update the auth identity to remove the ID of the manager from it.
|
||||
|
||||
You can use this workflow when deleting a manager, such as in an API route.
|
||||
|
||||
@@ -858,11 +858,7 @@ const user = createUserStep(input.user)
|
||||
const authUserInput = transform({ input, user }, (data) => ({
|
||||
authIdentityId: data.input.auth_identity_id,
|
||||
actorType: data.input.user.actor_type,
|
||||
key:
|
||||
data.input.user.actor_type === "restaurant"
|
||||
? "restaurant_id"
|
||||
: "driver_id",
|
||||
value: user.id,
|
||||
value: data.user.id,
|
||||
}))
|
||||
|
||||
setAuthAppMetadataStep(authUserInput)
|
||||
@@ -1034,7 +1030,201 @@ This returns the created driver user.
|
||||
|
||||
---
|
||||
|
||||
## Step 8: Create Restaurant Product API Route
|
||||
## Step 8: Delete Restaurant Admin API Route
|
||||
|
||||
In this step, you'll create a workflow that deletes the restaurant admin and its association to its auth identity, then use it in an API route.
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
The same logic can be applied to delete a driver.
|
||||
|
||||
</Note>
|
||||
|
||||
### Create deleteRestaurantAdminStep
|
||||
|
||||
First, create the step that deletes the restaurant admin at `restaurant-marketplace/src/workflows/restaurant/steps/delete-restaurant-admin.ts`:
|
||||
|
||||
```ts title="restaurant-marketplace/src/workflows/restaurant/steps/delete-restaurant-admin.ts"
|
||||
import {
|
||||
createStep,
|
||||
StepResponse,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
import { RESTAURANT_MODULE } from "../../../modules/restaurant"
|
||||
import { DeleteRestaurantAdminWorkflow } from "../workflows/delete-restaurant-admin"
|
||||
|
||||
export const deleteRestaurantAdminStep = createStep(
|
||||
"delete-restaurant-admin",
|
||||
async ({ id }: DeleteRestaurantAdminWorkflow, { container }) => {
|
||||
const restaurantModuleService = container.resolve(
|
||||
RESTAURANT_MODULE
|
||||
)
|
||||
|
||||
const admin = await restaurantModuleService.retrieveRestaurantAdmin(id)
|
||||
|
||||
await restaurantModuleService.deleteRestaurantAdmins(id)
|
||||
|
||||
return new StepResponse(undefined, { admin })
|
||||
},
|
||||
async ({ admin }, { container }) => {
|
||||
const restaurantModuleService = container.resolve(
|
||||
RESTAURANT_MODULE
|
||||
)
|
||||
|
||||
await restaurantModuleService.createRestaurantAdmins(admin)
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
In this step, you resolve the Restaurant Module's service and delete the admin. In the compensation function, you create the admin again.
|
||||
|
||||
### Create deleteRestaurantAdminWorkflow
|
||||
|
||||
Then, create the workflow that deletes the restaurant admin at `restaurant-marketplace/src/workflows/restaurant/workflows/delete-restaurant-admin.ts`:
|
||||
|
||||
```ts title="restaurant-marketplace/src/workflows/restaurant/workflows/delete-restaurant-admin.ts" collapsibleLines="1-13" expandButtonLabel="Show Imports"
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
import {
|
||||
WorkflowData,
|
||||
WorkflowResponse,
|
||||
createWorkflow,
|
||||
transform,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
import {
|
||||
setAuthAppMetadataStep,
|
||||
useRemoteQueryStep,
|
||||
} from "@medusajs/core-flows"
|
||||
import { deleteRestaurantAdminStep } from "../steps/delete-restaurant-admin"
|
||||
|
||||
export type DeleteRestaurantAdminWorkflow = {
|
||||
id: string
|
||||
}
|
||||
|
||||
export const deleteRestaurantAdminWorkflow = createWorkflow(
|
||||
"delete-restaurant-admin",
|
||||
(
|
||||
input: WorkflowData<DeleteRestaurantAdminWorkflow>
|
||||
): WorkflowResponse<string> => {
|
||||
deleteRestaurantAdminStep(input)
|
||||
|
||||
// TODO update auth identity
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
So far, you only use the `deleteRestaurantAdminStep` in the workflow, which deletes the restaurant admin.
|
||||
|
||||
Replace the `TODO` with the following:
|
||||
|
||||
```ts title="restaurant-marketplace/src/workflows/restaurant/workflows/delete-restaurant-admin.ts"
|
||||
const authIdentities = useRemoteQueryStep({
|
||||
entry_point: "auth_identity",
|
||||
fields: ["id"],
|
||||
variables: {
|
||||
filters: {
|
||||
app_metadata: {
|
||||
restaurant_id: input.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const authIdentity = transform(
|
||||
{ authIdentities },
|
||||
({ authIdentities }) => {
|
||||
const authIdentity = authIdentities[0]
|
||||
|
||||
if (!authIdentity) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
"Auth identity not found"
|
||||
)
|
||||
}
|
||||
|
||||
return authIdentity
|
||||
}
|
||||
)
|
||||
|
||||
setAuthAppMetadataStep({
|
||||
authIdentityId: authIdentity.id,
|
||||
actorType: "restaurant",
|
||||
value: null,
|
||||
})
|
||||
|
||||
return new WorkflowResponse(input.id)
|
||||
```
|
||||
|
||||
After deleting the restaurant admin, you:
|
||||
|
||||
1. Retrieve its auth identity using Query. To do that, you filter its `app_metadata` property by checking that its `restaurant_id` property's value is the admin's ID. For drivers, you replace `restaurant_id` with `driver_id`.
|
||||
2. Check that the auth identity exists using the `transform` utility. Otherwise, throw an error.
|
||||
3. Unset the association between the auth identity and the restaurant admin using the `setAuthAppMetadataStep` imported from `@medusajs/core-flows`.
|
||||
|
||||
### Create API Route
|
||||
|
||||
Finally, add the API route that uses the workflow at `src/api/restaurants/[id]/admins/[admin_id]/route.ts`:
|
||||
|
||||
```ts title="src/api/restaurants/[id]/admins/[admin_id]/route.ts"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "@medusajs/medusa"
|
||||
import {
|
||||
deleteRestaurantAdminWorkflow,
|
||||
} from "../../../../../workflows/restaurant/workflows/delete-restaurant-admin"
|
||||
|
||||
export const DELETE = async (
|
||||
req: AuthenticatedMedusaRequest,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
await deleteRestaurantAdminWorkflow(req.scope).run({
|
||||
input: {
|
||||
id: req.params.admin_id,
|
||||
},
|
||||
})
|
||||
|
||||
res.json({ message: "success" })
|
||||
}
|
||||
```
|
||||
|
||||
You add a `DELETE` API route at `/restaurants/[id]/admins/[admin_id]`. In the route, you execute the workflow to delete the restaurant admin.
|
||||
|
||||
### Add Authentication Middleware
|
||||
|
||||
This API route should only be accessible by restaurant admins.
|
||||
|
||||
So, in the file `src/api/middlewares.ts`, add a new middleware:
|
||||
|
||||
```ts title="src/api/middlewares.ts"
|
||||
export default defineMiddlewares({
|
||||
routes: [
|
||||
// ...
|
||||
{
|
||||
method: ["POST", "DELETE"],
|
||||
matcher: "/restaurants/:id/**",
|
||||
middlewares: [
|
||||
authenticate(["restaurant", "user"], "bearer"),
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
This allows only restaurant admins and Medusa Admin users to access routes under the `/restaurants/[id]` prefix if the request method is `POST` or `DELETE`.
|
||||
|
||||
### Test API Route
|
||||
|
||||
To test it out, create another restaurant admin user, then send a `DELETE` request to `/restaurants/[id]/admins/[admin_id]`, authenticated as the first admin user you created:
|
||||
|
||||
```bash
|
||||
curl -X DELETE 'http://localhost:9000/restaurants/01J7GHGQTCAVY5C1AH1H733Q4G/admins/01J7GJKHWXF1YDMXH09EXEDCD6' \
|
||||
-H 'Authorization: Bearer {token}'
|
||||
```
|
||||
|
||||
Make sure to replace the first ID with the restaurant's ID, and the second ID with the ID of the admin to delete.
|
||||
|
||||
---
|
||||
|
||||
## Step 9: Create Restaurant Product API Route
|
||||
|
||||
In this step, you’ll create the API route that creates a product for a restaurant.
|
||||
|
||||
@@ -1144,29 +1334,6 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
||||
|
||||
The creates a `POST` API route at `/restaurants/[id]/products`. It accepts the products’ details in the request body, executes the `createRestaurantProductsWorkflow` to create the products, and returns the created products in the response.
|
||||
|
||||
### Add Authentication Middleware
|
||||
|
||||
This API route should only be accessible by restaurant admins.
|
||||
|
||||
So, in the file `src/api/middlewares.ts`, add a new middleware:
|
||||
|
||||
```ts title="src/api/middlewares.ts"
|
||||
export default defineMiddlewares({
|
||||
routes: [
|
||||
// ...
|
||||
{
|
||||
method: ["POST", "DELETE"],
|
||||
matcher: "/restaurants/:id/**",
|
||||
middlewares: [
|
||||
authenticate(["restaurant", "user"], "bearer"),
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
This allows only restaurant admins and Medusa Admin users to access routes under the `/restaurants/[id]` prefix if the request method is `POST` or `DELETE`.
|
||||
|
||||
### Test it Out
|
||||
|
||||
To create a product using the above API route, send a `POST` request to `/restaurants/[id]/products`, replacing `[id]` with the restaurant’s ID:
|
||||
@@ -1209,7 +1376,7 @@ The request returns the created product in the response.
|
||||
|
||||
---
|
||||
|
||||
## Step 9: Create Order Delivery Workflow
|
||||
## Step 10: Create Order Delivery Workflow
|
||||
|
||||
In this step, you’ll create the workflow that creates a delivery. You’ll use it at a later step once a customer places their order.
|
||||
|
||||
@@ -1362,7 +1529,7 @@ In the workflow, you:
|
||||
|
||||
---
|
||||
|
||||
## Step 10: Handle Delivery Workflow
|
||||
## Step 11: Handle Delivery Workflow
|
||||
|
||||
In this step, you’ll create the workflow that handles the different stages of the delivery. This workflow needs to run in the background to update the delivery when an action occurs.
|
||||
|
||||
@@ -1898,7 +2065,7 @@ In the next steps, you’ll execute the workflow and see it in action as you add
|
||||
|
||||
---
|
||||
|
||||
## Step 11: Create Order Delivery API Route
|
||||
## Step 12: Create Order Delivery API Route
|
||||
|
||||
In this step, you’ll create the API route that executes the workflows created by the previous two steps. This API route is used when a customer places their order.
|
||||
|
||||
@@ -2074,7 +2241,7 @@ In the upcoming steps, you’ll add functionalities to update the delivery’s s
|
||||
|
||||
---
|
||||
|
||||
## Step 12: Accept Delivery API Route
|
||||
## Step 13: Accept Delivery API Route
|
||||
|
||||
In this step, you’ll create an API route that a restaurant admin uses to accept a delivery. This moves the `handleDeliveryWorkflow` execution from `notifyRestaurantStep` to the next step.
|
||||
|
||||
@@ -2526,7 +2693,7 @@ Meaning that the `handleDeliveryWorkflow`'s execution has moved to the `awaitDri
|
||||
|
||||
---
|
||||
|
||||
## Step 13: Claim Delivery API Route
|
||||
## Step 14: Claim Delivery API Route
|
||||
|
||||
In this step, you’ll add the API route that allows a driver to claim a delivery.
|
||||
|
||||
@@ -2671,7 +2838,7 @@ This indicates that the `handleDeliveryWorkflow`'s execution continued past the
|
||||
|
||||
---
|
||||
|
||||
## Step 14: Prepare API Route
|
||||
## Step 15: Prepare API Route
|
||||
|
||||
In this step, you’ll add the API route that restaurants use to indicate they’re preparing the order.
|
||||
|
||||
@@ -2761,7 +2928,7 @@ This message indicates that the `handleDeliveryWorkflow`'s execution has moved t
|
||||
|
||||
---
|
||||
|
||||
## Step 15: Ready API Route
|
||||
## Step 16: Ready API Route
|
||||
|
||||
In this step, you’ll create the API route that restaurants use to indicate that a delivery is ready for pick up.
|
||||
|
||||
@@ -2853,7 +3020,7 @@ This message indicates that the `handleDeliveryWorkflow`'s execution has moved t
|
||||
|
||||
---
|
||||
|
||||
## Step 18: Pick Up Delivery API Route
|
||||
## Step 17: Pick Up Delivery API Route
|
||||
|
||||
In this step, you’ll add the API route that the driver uses to indicate they’ve picked up the delivery.
|
||||
|
||||
@@ -2993,7 +3160,7 @@ This message indicates that the `handleDeliveryWorkflow`'s execution has moved t
|
||||
|
||||
---
|
||||
|
||||
## Step 19: Complete Delivery API Route
|
||||
## Step 18: Complete Delivery API Route
|
||||
|
||||
In this step, you’ll create the API route that the driver uses to indicate that they completed the delivery.
|
||||
|
||||
@@ -3083,7 +3250,7 @@ As the route sets the status of the `awaitDeliveryStep` to successful in the `ha
|
||||
|
||||
---
|
||||
|
||||
## Step 20: Real-Time Tracking in the Storefront
|
||||
## Step 19: Real-Time Tracking in the Storefront
|
||||
|
||||
In this step, you’ll learn how to implement real-time tracking of a delivery in a Next.js-based storefront.
|
||||
|
||||
|
||||
@@ -225,12 +225,9 @@ export const generatedEditDates = {
|
||||
"app/commerce-modules/auth/_events/_events-table/page.mdx": "2024-07-03T19:27:13+03:00",
|
||||
"app/commerce-modules/auth/auth-flows/page.mdx": "2024-09-05T08:50:11.671Z",
|
||||
"app/commerce-modules/auth/_events/page.mdx": "2024-07-03T19:27:13+03:00",
|
||||
"app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx": "2024-07-31T17:01:33+03:00",
|
||||
"app/commerce-modules/api-key/page.mdx": "2024-09-05T14:59:37.604Z",
|
||||
"app/commerce-modules/auth/create-actor-type/page.mdx": "2024-07-31T17:01:33+03:00",
|
||||
"app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx": "2024-09-05T08:11:28.936Z",
|
||||
"app/commerce-modules/api-key/page.mdx": "2024-08-05T07:24:27+00:00",
|
||||
"app/commerce-modules/auth/create-actor-type/page.mdx": "2024-09-05T09:24:48.099Z",
|
||||
"app/commerce-modules/auth/create-actor-type/page.mdx": "2024-09-11T13:15:34.040Z",
|
||||
"app/architectural-modules/page.mdx": "2024-05-28T13:25:03+03:00",
|
||||
"app/commerce-modules/api-key/relations-to-other-modules/page.mdx": "2024-05-29T11:08:06+00:00",
|
||||
"app/architectural-modules/workflow-engine/redis/page.mdx": "2024-07-18T13:04:29+02:00",
|
||||
@@ -646,7 +643,7 @@ export const generatedEditDates = {
|
||||
"app/medusa-cli/commands/start/page.mdx": "2024-08-28T10:44:19.952Z",
|
||||
"app/medusa-cli/commands/telemtry/page.mdx": "2024-08-28T11:25:08.553Z",
|
||||
"app/medusa-cli/commands/user/page.mdx": "2024-08-28T10:44:52.489Z",
|
||||
"app/recipes/marketplace/examples/restaurant-delivery/page.mdx": "2024-08-29T09:20:26.842Z",
|
||||
"app/recipes/marketplace/examples/restaurant-delivery/page.mdx": "2024-09-11T13:29:33.305Z",
|
||||
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCreateCustomerGroup/page.mdx": "2024-08-30T00:11:02.074Z",
|
||||
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCreateReservation/page.mdx": "2024-08-30T00:11:02.342Z",
|
||||
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCustomerGroup/page.mdx": "2024-08-30T00:11:02.070Z",
|
||||
@@ -911,11 +908,6 @@ export const generatedEditDates = {
|
||||
"references/order/interfaces/order.UpdateOrderReturnWithSelectorDTO/page.mdx": "2024-09-06T11:12:03.118Z",
|
||||
"references/promotion/IPromotionModuleService/methods/promotion.IPromotionModuleService.updatePromotions/page.mdx": "2024-09-04T00:11:32.621Z",
|
||||
"references/promotion/interfaces/promotion.UpdatePromotionDTO/page.mdx": "2024-09-04T00:11:32.593Z",
|
||||
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminClaim/page.mdx": "2024-09-06T11:11:36.322Z",
|
||||
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminClaimOrderResponse/page.mdx": "2024-09-06T11:11:36.370Z",
|
||||
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminClaimPreviewResponse/page.mdx": "2024-09-06T11:11:36.390Z",
|
||||
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminOrderEditPreviewResponse/page.mdx": "2024-09-06T11:11:36.646Z",
|
||||
"references/types/interfaces/types.BaseClaim/page.mdx": "2024-09-06T11:11:36.238Z",
|
||||
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminClaim/page.mdx": "2024-09-04T00:11:02.573Z",
|
||||
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminClaimOrderResponse/page.mdx": "2024-09-04T00:11:02.625Z",
|
||||
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminClaimPreviewResponse/page.mdx": "2024-09-04T00:11:02.637Z",
|
||||
|
||||
Reference in New Issue
Block a user