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:
Shahed Nasser
2024-09-13 10:17:36 +03:00
committed by GitHub
parent f0c470cb08
commit 1eccf394df
3 changed files with 329 additions and 49 deletions

View File

@@ -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.

View File

@@ -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, youll 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 restaurants 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, youll create the workflow that creates a delivery. Youll 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, youll 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, youll 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, youll 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, youll add functionalities to update the deliverys s
---
## Step 12: Accept Delivery API Route
## Step 13: Accept Delivery API Route
In this step, youll 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, youll 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, youll add the API route that restaurants use to indicate theyre 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, youll 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, youll add the API route that the driver uses to indicate theyve 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, youll 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, youll learn how to implement real-time tracking of a delivery in a Next.js-based storefront.

View File

@@ -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",