chore(core-flows,types): improve TSDocs of user-related workflows (#11017)
This commit is contained in:
@@ -11,7 +11,36 @@ export type SetAuthAppMetadataStepInput = {
|
||||
|
||||
export const setAuthAppMetadataStepId = "set-auth-app-metadata"
|
||||
/**
|
||||
* This step sets the `app_metadata` property of an auth identity.
|
||||
* This step sets the `app_metadata` property of an auth identity. This is useful to
|
||||
* associate a user (whether it's an admin user or customer) with an auth identity
|
||||
* that allows them to authenticate into Medusa.
|
||||
*
|
||||
* You can learn more about auth identites in
|
||||
* [this documentation](https://docs.medusajs.com/resources/commerce-modules/auth/auth-identity-and-actor-types).
|
||||
*
|
||||
* To use this for a custom actor type, check out [this guide](https://docs.medusajs.com/resources/commerce-modules/auth/create-actor-type)
|
||||
* that explains how to create a custom `manager` actor type and manage its users.
|
||||
*
|
||||
* @example
|
||||
* To associate an auth identity with an actor type (user, customer, or other actor types):
|
||||
*
|
||||
* ```ts
|
||||
* const data = setAuthAppMetadataStep({
|
||||
* authIdentityId: "au_1234",
|
||||
* actorType: "user", // or `customer`, or custom type
|
||||
* value: "user_123"
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* To remove the association with an actor type, such as when deleting the user:
|
||||
*
|
||||
* ```ts
|
||||
* const data = setAuthAppMetadataStep({
|
||||
* authIdentityId: "au_1234",
|
||||
* actorType: "user", // or `customer`, or custom type
|
||||
* value: null
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export const setAuthAppMetadataStep = createStep(
|
||||
setAuthAppMetadataStepId,
|
||||
|
||||
@@ -10,6 +10,35 @@ import {
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { emitEventStep, useRemoteQueryStep } from "../../common"
|
||||
|
||||
/**
|
||||
* This workflow generates a reset password token for a user. It's used by the
|
||||
* [Generate Reset Password Token for Admin](https://docs.medusajs.com/api/admin#auth_postactor_typeauth_providerresetpassword)
|
||||
* and [Generate Reset Password Token for Customer](https://docs.medusajs.com/api/store#auth_postactor_typeauth_providerresetpassword)
|
||||
* API Routes.
|
||||
*
|
||||
* The workflow emits the `auth.password_reset` event, which you can listen to in
|
||||
* a [subscriber](https://docs.medusajs.com/learn/fundamentals/events-and-subscribers). Follow
|
||||
* [this guide](https://docs.medusajs.com/resources/commerce-modules/auth/reset-password) to learn
|
||||
* how to handle this event.
|
||||
*
|
||||
* You can use this workflow within your customizations or your own custom workflows, allowing you to
|
||||
* generate reset password tokens within your custom flows.
|
||||
*
|
||||
* @example
|
||||
* const { result } = await generateResetPasswordTokenWorkflow(container)
|
||||
* .run({
|
||||
* input: {
|
||||
* entityId: "example@gmail.com",
|
||||
* actorType: "customer",
|
||||
* provider: "emailpass",
|
||||
* secret: "jwt_123" // jwt secret
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* @summary
|
||||
*
|
||||
* Generate a reset password token for a user or customer.
|
||||
*/
|
||||
export const generateResetPasswordTokenWorkflow = createWorkflow(
|
||||
"generate-reset-password-token",
|
||||
(input: {
|
||||
|
||||
@@ -5,6 +5,13 @@ import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||
export const createInviteStepId = "create-invite-step"
|
||||
/**
|
||||
* This step creates one or more invites.
|
||||
*
|
||||
* @example
|
||||
* const data = createInviteStep([
|
||||
* {
|
||||
* email: "example@gmail.com"
|
||||
* }
|
||||
* ])
|
||||
*/
|
||||
export const createInviteStep = createStep(
|
||||
createInviteStepId,
|
||||
|
||||
@@ -2,13 +2,18 @@ import { IUserModuleService } from "@medusajs/framework/types"
|
||||
import { Modules } from "@medusajs/framework/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
/**
|
||||
* The IDs of the invites to delete.
|
||||
*/
|
||||
export type DeleteInvitesStepInput = string[]
|
||||
|
||||
export const deleteInvitesStepId = "delete-invites-step"
|
||||
/**
|
||||
* This step deletes one or more invites.
|
||||
*/
|
||||
export const deleteInvitesStep = createStep(
|
||||
deleteInvitesStepId,
|
||||
async (input: string[], { container }) => {
|
||||
async (input: DeleteInvitesStepInput, { container }) => {
|
||||
const service: IUserModuleService = container.resolve(Modules.USER)
|
||||
|
||||
await service.softDeleteInvites(input)
|
||||
|
||||
@@ -3,13 +3,18 @@ import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
import { Modules } from "@medusajs/framework/utils"
|
||||
|
||||
/**
|
||||
* The IDs of the invites to refresh.
|
||||
*/
|
||||
export type RefreshInviteTokensStepInput = string[]
|
||||
|
||||
export const refreshInviteTokensStepId = "refresh-invite-tokens-step"
|
||||
/**
|
||||
* This step refreshes the tokens of one or more invites.
|
||||
*/
|
||||
export const refreshInviteTokensStep = createStep(
|
||||
refreshInviteTokensStepId,
|
||||
async (input: string[], { container }) => {
|
||||
async (input: RefreshInviteTokensStepInput, { container }) => {
|
||||
const service: IUserModuleService = container.resolve(Modules.USER)
|
||||
|
||||
const invites = await service.refreshInviteTokens(input)
|
||||
|
||||
@@ -2,13 +2,19 @@ import { IUserModuleService } from "@medusajs/framework/types"
|
||||
import { Modules } from "@medusajs/framework/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
/**
|
||||
* The token to validate.
|
||||
*/
|
||||
export type ValidateTokenStepInput = string
|
||||
|
||||
export const validateTokenStepId = "validate-invite-token-step"
|
||||
/**
|
||||
* This step validates a specified token and returns its associated invite.
|
||||
* If not valid, the step throws an error.
|
||||
*/
|
||||
export const validateTokenStep = createStep(
|
||||
validateTokenStepId,
|
||||
async (input: string, { container }) => {
|
||||
async (input: ValidateTokenStepInput, { container }) => {
|
||||
const userModuleService: IUserModuleService = container.resolve(
|
||||
Modules.USER
|
||||
)
|
||||
|
||||
@@ -15,7 +15,33 @@ import { validateTokenStep } from "../steps/validate-token"
|
||||
|
||||
export const acceptInviteWorkflowId = "accept-invite-workflow"
|
||||
/**
|
||||
* This workflow accepts an invite and creates a user.
|
||||
* This workflow accepts an invite and creates a user. It's used by the
|
||||
* [Accept Invite Admin API Route](https://docs.medusajs.com/api/admin#invites_postinvitesaccept).
|
||||
*
|
||||
* The workflow throws an error if the specified token is not valid. Also, the workflow
|
||||
* requires an auth identity to be created previously. You can create an auth identity
|
||||
* using the [Retrieve Registration JWT Token API Route](https://docs.medusajs.com/api/admin#auth_postactor_typeauth_provider_register).
|
||||
*
|
||||
* You can use this workflow within your customizations or your own custom workflows, allowing you to
|
||||
* accept invites within your custom flows.
|
||||
*
|
||||
* @example
|
||||
* const { result } = await acceptInviteWorkflow(container)
|
||||
* .run({
|
||||
* input: {
|
||||
* invite_token: "sk_123",
|
||||
* auth_identity_id: "au_123",
|
||||
* user: {
|
||||
* email: "example@gmail.com",
|
||||
* first_name: "John",
|
||||
* last_name: "Doe",
|
||||
* }
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* @summary
|
||||
*
|
||||
* Accept invite and create user.
|
||||
*/
|
||||
export const acceptInviteWorkflow = createWorkflow(
|
||||
acceptInviteWorkflowId,
|
||||
|
||||
@@ -10,7 +10,27 @@ import { emitEventStep } from "../../common/steps/emit-event"
|
||||
import { createInviteStep } from "../steps"
|
||||
export const createInvitesWorkflowId = "create-invite-step"
|
||||
/**
|
||||
* This workflow creates one or more invites.
|
||||
* This workflow creates one or more user invites. It's used by the
|
||||
* [Create Invite Admin API Route](https://docs.medusajs.com/api/admin#invites_postinvites).
|
||||
*
|
||||
* You can use this workflow within your customizations or your own custom workflows, allowing you to
|
||||
* create invites within your custom flows.
|
||||
*
|
||||
* @example
|
||||
* const { result } = await createInvitesWorkflow(container)
|
||||
* .run({
|
||||
* input: {
|
||||
* invites: [
|
||||
* {
|
||||
* email: "example@gmail.com"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* @summary
|
||||
*
|
||||
* Create one or more user invites.
|
||||
*/
|
||||
export const createInvitesWorkflow = createWorkflow(
|
||||
createInvitesWorkflowId,
|
||||
|
||||
@@ -10,7 +10,23 @@ import { deleteInvitesStep } from "../steps"
|
||||
|
||||
export const deleteInvitesWorkflowId = "delete-invites-workflow"
|
||||
/**
|
||||
* This workflow deletes one or more invites.
|
||||
* This workflow deletes one or more user invites. It's used by the
|
||||
* [Delete Invites Admin API Route](https://docs.medusajs.com/api/admin#invites_deleteinvitesid).
|
||||
*
|
||||
* You can use this workflow within your customizations or your own custom workflows, allowing you to
|
||||
* delete invites within your custom flows.
|
||||
*
|
||||
* @example
|
||||
* const { result } = await deleteInvitesWorkflow(container)
|
||||
* .run({
|
||||
* input: {
|
||||
* ids: ["invite_123"]
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* @summary
|
||||
*
|
||||
* Delete one or more user invites.
|
||||
*/
|
||||
export const deleteInvitesWorkflow = createWorkflow(
|
||||
deleteInvitesWorkflowId,
|
||||
|
||||
@@ -12,7 +12,27 @@ import { refreshInviteTokensStep } from "../steps/refresh-invite-tokens"
|
||||
|
||||
export const refreshInviteTokensWorkflowId = "refresh-invite-tokens-workflow"
|
||||
/**
|
||||
* This workflow refreshes the token of one or more invites.
|
||||
* This workflow refreshes the token of one or more user invites, updating the
|
||||
* token and the expiry date. It's used by the
|
||||
* [Refresh Invite Token Admin API Route](https://docs.medusajs.com/api/admin#invites_postinvitesidresend).
|
||||
*
|
||||
* This workflow is useful to trigger resending invite tokens. It emits the `invite.resent` event,
|
||||
* which you can listen to in a [Subscriber](https://docs.medusajs.com/learn/fundamentals/events-and-subscribers).
|
||||
*
|
||||
* You can use this workflow within your customizations or your own custom workflows, allowing you to
|
||||
* refresh invite tokens within your custom flows.
|
||||
*
|
||||
* @example
|
||||
* const { result } = await refreshInviteTokensWorkflow(container)
|
||||
* .run({
|
||||
* input: {
|
||||
* invite_ids: ["invite_123"]
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* @summary
|
||||
*
|
||||
* Refresh user invite tokens.
|
||||
*/
|
||||
export const refreshInviteTokensWorkflow = createWorkflow(
|
||||
refreshInviteTokensWorkflowId,
|
||||
|
||||
@@ -4,7 +4,17 @@ import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
export const createUsersStepId = "create-users-step"
|
||||
/**
|
||||
* This step creates one or more users.
|
||||
* This step creates one or more users. To allow these users to log in,
|
||||
* you must attach an auth identity to each user using the {@link setAuthAppMetadataStep}.
|
||||
*
|
||||
* @example
|
||||
* const data = createUsersStep([
|
||||
* {
|
||||
* email: "example@gmail.com",
|
||||
* first_name: "John",
|
||||
* last_name: "Doe",
|
||||
* }
|
||||
* ])
|
||||
*/
|
||||
export const createUsersStep = createStep(
|
||||
createUsersStepId,
|
||||
|
||||
@@ -2,13 +2,18 @@ import { IUserModuleService } from "@medusajs/framework/types"
|
||||
import { Modules } from "@medusajs/framework/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
/**
|
||||
* The IDs of the users to delete.
|
||||
*/
|
||||
export type DeleteUsersStepInput = string[]
|
||||
|
||||
export const deleteUsersStepId = "delete-users-step"
|
||||
/**
|
||||
* This step deletes one or more stores.
|
||||
* This step deletes one or more users.
|
||||
*/
|
||||
export const deleteUsersStep = createStep(
|
||||
deleteUsersStepId,
|
||||
async (input: string[], { container }) => {
|
||||
async (input: DeleteUsersStepInput, { container }) => {
|
||||
const service: IUserModuleService = container.resolve(Modules.USER)
|
||||
|
||||
await service.softDeleteUsers(input)
|
||||
|
||||
@@ -4,7 +4,15 @@ import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
export const updateUsersStepId = "update-users-step"
|
||||
/**
|
||||
* This step updates one or more stores.
|
||||
* This step updates one or more users.
|
||||
*
|
||||
* @example
|
||||
* const data = updateUsersStep([
|
||||
* {
|
||||
* id: "user_123",
|
||||
* last_name: "Doe",
|
||||
* }
|
||||
* ])
|
||||
*/
|
||||
export const updateUsersStep = createStep(
|
||||
updateUsersStepId,
|
||||
|
||||
@@ -8,14 +8,46 @@ import {
|
||||
import { setAuthAppMetadataStep } from "../../auth"
|
||||
import { createUsersWorkflow } from "./create-users"
|
||||
|
||||
/**
|
||||
* The details of the user account to create.
|
||||
*/
|
||||
export type CreateUserAccountWorkflowInput = {
|
||||
/**
|
||||
* The ID of the auth identity to attach the user to.
|
||||
*/
|
||||
authIdentityId: string
|
||||
/**
|
||||
* The details of the user to create.
|
||||
*/
|
||||
userData: CreateUserDTO
|
||||
}
|
||||
|
||||
export const createUserAccountWorkflowId = "create-user-account"
|
||||
/**
|
||||
* This workflow creates an authentication identity for a user.
|
||||
* This workflow creates a user and attaches it to an auth identity.
|
||||
*
|
||||
* You can create an auth identity first using the [Retrieve Registration JWT Token API Route](https://docs.medusajs.com/api/admin#auth_postactor_typeauth_provider_register).
|
||||
* Learn more about basic authentication flows in [this documentation](https://docs.medusajs.com/resources/commerce-modules/auth/authentication-route).
|
||||
*
|
||||
* You can use this workflow within your customizations or your own custom workflows, allowing you to
|
||||
* register or create user accounts within your custom flows.
|
||||
*
|
||||
* @example
|
||||
* const { result } = await createUserAccountWorkflow(container)
|
||||
* .run({
|
||||
* input: {
|
||||
* authIdentityId: "au_123",
|
||||
* userData: {
|
||||
* email: "example@gmail.com",
|
||||
* first_name: "John",
|
||||
* last_name: "Doe",
|
||||
* }
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* @summary
|
||||
*
|
||||
* Create a user account and attach an auth identity.
|
||||
*/
|
||||
export const createUserAccountWorkflow = createWorkflow(
|
||||
createUserAccountWorkflowId,
|
||||
|
||||
@@ -11,7 +11,31 @@ import { createUsersStep } from "../steps"
|
||||
|
||||
export const createUsersWorkflowId = "create-users-workflow"
|
||||
/**
|
||||
* This workflow creates one or more users.
|
||||
* This workflow creates one or more users. It's used by other workflows, such
|
||||
* as {@link acceptInviteWorkflow} to create a user for an invite.
|
||||
*
|
||||
* You can attach an auth identity to each user to allow the user to log in using the
|
||||
* {@link setAuthAppMetadataStep}. Learn more about auth identities in
|
||||
* [this documentation](https://docs.medusajs.com/resources/commerce-modules/auth/auth-identity-and-actor-types).
|
||||
*
|
||||
* You can use this workflow within your customizations or your own custom workflows, allowing you to
|
||||
* create users within your custom flows.
|
||||
*
|
||||
* @example
|
||||
* const { result } = await createUsersWorkflow(container)
|
||||
* .run({
|
||||
* input: {
|
||||
* users: [{
|
||||
* email: "example@gmail.com",
|
||||
* first_name: "John",
|
||||
* last_name: "Doe",
|
||||
* }]
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* @summary
|
||||
*
|
||||
* Create one or more users.
|
||||
*/
|
||||
export const createUsersWorkflow = createWorkflow(
|
||||
createUsersWorkflowId,
|
||||
|
||||
@@ -10,7 +10,26 @@ import { deleteUsersStep } from "../steps"
|
||||
|
||||
export const deleteUsersWorkflowId = "delete-user"
|
||||
/**
|
||||
* This workflow deletes one or more users.
|
||||
* This workflow deletes one or more users. It's used by other workflows
|
||||
* like {@link removeUserAccountWorkflow}. If you use this workflow directly,
|
||||
* you must also remove the association to the auth identity using the
|
||||
* {@link setAuthAppMetadataStep}. Learn more about auth identities in
|
||||
* [this documentation](https://docs.medusajs.com/resources/commerce-modules/auth/auth-identity-and-actor-types).
|
||||
*
|
||||
* You can use this workflow within your customizations or your own custom workflows, allowing you to
|
||||
* delete users within your custom flows.
|
||||
*
|
||||
* @example
|
||||
* const { result } = await deleteUsersWorkflow(container)
|
||||
* .run({
|
||||
* input: {
|
||||
* ids: ["user_123"]
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* @summary
|
||||
*
|
||||
* Delete one or more users.
|
||||
*/
|
||||
export const deleteUsersWorkflow = createWorkflow(
|
||||
deleteUsersWorkflowId,
|
||||
|
||||
@@ -9,12 +9,34 @@ import { setAuthAppMetadataStep } from "../../auth"
|
||||
import { useRemoteQueryStep } from "../../common"
|
||||
import { deleteUsersWorkflow } from "./delete-users"
|
||||
|
||||
/**
|
||||
* The data to remove a user account.
|
||||
*/
|
||||
export type RemoveUserAccountWorkflowInput = {
|
||||
/**
|
||||
* The ID of the user to remove.
|
||||
*/
|
||||
userId: string
|
||||
}
|
||||
export const removeUserAccountWorkflowId = "remove-user-account"
|
||||
/**
|
||||
* This workflow deletes a user and remove the association in the auth identity.
|
||||
* This workflow deletes a user and remove the association to its auth identity. It's used
|
||||
* by the [Delete User Admin API Route](https://docs.medusajs.com/api/admin#users_deleteusersid).
|
||||
*
|
||||
* You can use this workflow within your customizations or your own custom workflows, allowing you to
|
||||
* delete users within your custom flows.
|
||||
*
|
||||
* @example
|
||||
* const { result } = await removeUserAccountWorkflow(container)
|
||||
* .run({
|
||||
* input: {
|
||||
* userId: "user_123"
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* @summary
|
||||
*
|
||||
* Delete a user and remove the association to its auth identity.
|
||||
*/
|
||||
export const removeUserAccountWorkflow = createWorkflow(
|
||||
removeUserAccountWorkflowId,
|
||||
|
||||
@@ -11,7 +11,28 @@ import { updateUsersStep } from "../steps"
|
||||
|
||||
export const updateUsersWorkflowId = "update-users-workflow"
|
||||
/**
|
||||
* This workflow updates one or more users.
|
||||
* This workflow updates one or more users. It's used by the
|
||||
* [Update User Admin API Route](https://docs.medusajs.com/api/admin#users_postusersid).
|
||||
*
|
||||
* You can use this workflow within your customizations or your own custom workflows, allowing you to
|
||||
* update users within your custom flows.
|
||||
*
|
||||
* @example
|
||||
* const { result } = await updateUsersWorkflow(container)
|
||||
* .run({
|
||||
* input: {
|
||||
* updates: [
|
||||
* {
|
||||
* id: "user_123",
|
||||
* first_name: "John"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* @summary
|
||||
*
|
||||
* Update one or more users.
|
||||
*/
|
||||
export const updateUsersWorkflow = createWorkflow(
|
||||
updateUsersWorkflowId,
|
||||
|
||||
@@ -1,11 +1,38 @@
|
||||
/**
|
||||
* The data to accept the invite.
|
||||
*/
|
||||
export interface AcceptInviteWorkflowInputDTO {
|
||||
/**
|
||||
* The invite token.
|
||||
*/
|
||||
invite_token: string
|
||||
/**
|
||||
* The ID of the auth identity to associate the user with.
|
||||
*/
|
||||
auth_identity_id: string
|
||||
/**
|
||||
* The user to create.
|
||||
*/
|
||||
user: {
|
||||
/**
|
||||
* The email of the user.
|
||||
*/
|
||||
email?: string
|
||||
/**
|
||||
* The first name of the user.
|
||||
*/
|
||||
first_name?: string | null
|
||||
/**
|
||||
* The last name of the user.
|
||||
*/
|
||||
last_name?: string | null
|
||||
/**
|
||||
* The avatar URL of the user.
|
||||
*/
|
||||
avatar_url?: string | null
|
||||
/**
|
||||
* Custom key-value pairs of data to store in the user.
|
||||
*/
|
||||
metadata?: Record<string, unknown> | null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { CreateInviteDTO } from "../../user"
|
||||
|
||||
/**
|
||||
* The data to create invites.
|
||||
*/
|
||||
export interface CreateInvitesWorkflowInputDTO {
|
||||
/**
|
||||
* The invites to create.
|
||||
*/
|
||||
invites: CreateInviteDTO[]
|
||||
}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* The data to delete user invites.
|
||||
*/
|
||||
export interface DeleteInvitesWorkflowInput {
|
||||
/**
|
||||
* The IDs of the invites to delete.
|
||||
*/
|
||||
ids: string[]
|
||||
}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* The data to refresh invite tokens.
|
||||
*/
|
||||
export interface ResendInvitesWorkflowInputDTO {
|
||||
/**
|
||||
* The IDs of the invites to refresh.
|
||||
*/
|
||||
invite_ids: string[]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { CreateUserDTO } from "../../user"
|
||||
|
||||
/**
|
||||
* The data to create users.
|
||||
*/
|
||||
export interface CreateUsersWorkflowInputDTO {
|
||||
/**
|
||||
* The users to create.
|
||||
*/
|
||||
users: CreateUserDTO[]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { UpdateUserDTO } from "../../user"
|
||||
|
||||
/**
|
||||
* The data to update users.
|
||||
*/
|
||||
export interface UpdateUsersWorkflowInputDTO {
|
||||
/**
|
||||
* The users to update.
|
||||
*/
|
||||
updates: UpdateUserDTO[]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user