Jelajahi Sumber

feat(core): Implement deleteRole mutation

Michael Bromley 6 tahun lalu
induk
melakukan
7b338a48f7

+ 7 - 0
packages/common/src/generated-types.ts

@@ -1777,6 +1777,8 @@ export type Mutation = {
   createRole: Role,
   /** Update an existing Role */
   updateRole: Role,
+  /** Delete an existing Role */
+  deleteRole: DeletionResponse,
   /** Create a new ShippingMethod */
   createShippingMethod: ShippingMethod,
   /** Update an existing ShippingMethod */
@@ -2110,6 +2112,11 @@ export type MutationUpdateRoleArgs = {
 };
 
 
+export type MutationDeleteRoleArgs = {
+  id: Scalars['ID']
+};
+
+
 export type MutationCreateShippingMethodArgs = {
   input: CreateShippingMethodInput
 };

+ 20 - 0
packages/core/e2e/graphql/generated-e2e-admin-types.ts

@@ -1780,6 +1780,8 @@ export type Mutation = {
     createRole: Role;
     /** Update an existing Role */
     updateRole: Role;
+    /** Delete an existing Role */
+    deleteRole: DeletionResponse;
     /** Create a new ShippingMethod */
     createShippingMethod: ShippingMethod;
     /** Update an existing ShippingMethod */
@@ -2053,6 +2055,10 @@ export type MutationUpdateRoleArgs = {
     input: UpdateRoleInput;
 };
 
+export type MutationDeleteRoleArgs = {
+    id: Scalars['ID'];
+};
+
 export type MutationCreateShippingMethodArgs = {
     input: CreateShippingMethodInput;
 };
@@ -4810,6 +4816,14 @@ export type UpdateRoleMutation = { __typename?: 'Mutation' } & {
     updateRole: { __typename?: 'Role' } & RoleFragment;
 };
 
+export type DeleteRoleMutationVariables = {
+    id: Scalars['ID'];
+};
+
+export type DeleteRoleMutation = { __typename?: 'Mutation' } & {
+    deleteRole: { __typename?: 'DeletionResponse' } & Pick<DeletionResponse, 'result' | 'message'>;
+};
+
 export type ShippingMethodFragment = { __typename?: 'ShippingMethod' } & Pick<
     ShippingMethod,
     'id' | 'code' | 'description'
@@ -6055,6 +6069,12 @@ export namespace UpdateRole {
     export type UpdateRole = RoleFragment;
 }
 
+export namespace DeleteRole {
+    export type Variables = DeleteRoleMutationVariables;
+    export type Mutation = DeleteRoleMutation;
+    export type DeleteRole = DeleteRoleMutation['deleteRole'];
+}
+
 export namespace ShippingMethod {
     export type Fragment = ShippingMethodFragment;
     export type Calculator = ShippingMethodFragment['calculator'];

+ 55 - 0
packages/core/e2e/role.e2e-spec.ts

@@ -15,6 +15,8 @@ import {
     CreateChannel,
     CreateRole,
     CurrencyCode,
+    DeleteRole,
+    DeletionResult,
     GetRole,
     GetRoles,
     LanguageCode,
@@ -232,6 +234,50 @@ describe('Role resolver', () => {
         }, `The role '${CUSTOMER_ROLE_CODE}' cannot be modified`),
     );
 
+    it(
+        'deleteRole is not allowed for Customer role',
+        assertThrowsWithMessage(async () => {
+            const customerRole = defaultRoles.find(r => r.code === CUSTOMER_ROLE_CODE);
+            if (!customerRole) {
+                fail(`Could not find Customer role`);
+                return;
+            }
+            return adminClient.query<DeleteRole.Mutation, DeleteRole.Variables>(DELETE_ROLE, {
+                id: customerRole.id,
+            });
+        }, `The role '${CUSTOMER_ROLE_CODE}' cannot be deleted`),
+    );
+
+    it(
+        'deleteRole is not allowed for SuperAdmin role',
+        assertThrowsWithMessage(async () => {
+            const superAdminRole = defaultRoles.find(r => r.code === SUPER_ADMIN_ROLE_CODE);
+            if (!superAdminRole) {
+                fail(`Could not find Customer role`);
+                return;
+            }
+            return adminClient.query<DeleteRole.Mutation, DeleteRole.Variables>(DELETE_ROLE, {
+                id: superAdminRole.id,
+            });
+        }, `The role '${SUPER_ADMIN_ROLE_CODE}' cannot be deleted`),
+    );
+
+    it('deleteRole deletes a role', async () => {
+        const { deleteRole } = await adminClient.query<DeleteRole.Mutation, DeleteRole.Variables>(
+            DELETE_ROLE,
+            {
+                id: createdRole.id,
+            },
+        );
+
+        expect(deleteRole.result).toBe(DeletionResult.DELETED);
+
+        const { role } = await adminClient.query<GetRole.Query, GetRole.Variables>(GET_ROLE, {
+            id: createdRole.id,
+        });
+        expect(role).toBeNull();
+    });
+
     describe('multi-channel', () => {
         let secondChannel: CreateChannel.CreateChannel;
         let multiChannelRole: CreateRole.CreateRole;
@@ -337,3 +383,12 @@ export const UPDATE_ROLE = gql`
     }
     ${ROLE_FRAGMENT}
 `;
+
+export const DELETE_ROLE = gql`
+    mutation DeleteRole($id: ID!) {
+        deleteRole(id: $id) {
+            result
+            message
+        }
+    }
+`;

+ 9 - 1
packages/core/src/api/resolvers/admin/role.resolver.ts

@@ -1,6 +1,8 @@
 import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
 import {
+    DeletionResponse,
     MutationCreateRoleArgs,
+    MutationDeleteRoleArgs,
     MutationUpdateRoleArgs,
     Permission,
     QueryRoleArgs,
@@ -36,11 +38,17 @@ export class RoleResolver {
         const { input } = args;
         return this.roleService.create(ctx, input);
     }
-
     @Mutation()
     @Allow(Permission.UpdateAdministrator)
     updateRole(@Ctx() ctx: RequestContext, @Args() args: MutationUpdateRoleArgs): Promise<Role> {
         const { input } = args;
         return this.roleService.update(ctx, input);
     }
+
+    @Mutation()
+    @Allow(Permission.DeleteAdministrator)
+    deleteRole(@Ctx() ctx: RequestContext, @Args() args: MutationDeleteRoleArgs): Promise<DeletionResponse> {
+        const { id } = args;
+        return this.roleService.delete(ctx, id);
+    }
 }

+ 2 - 0
packages/core/src/api/schema/admin-api/role.api.graphql

@@ -8,6 +8,8 @@ type Mutation {
   createRole(input: CreateRoleInput!): Role!
   "Update an existing Role"
   updateRole(input: UpdateRoleInput!): Role!
+  "Delete an existing Role"
+  deleteRole(id: ID!): DeletionResponse!
 }
 
 # generated by generateListOptions function

+ 1 - 0
packages/core/src/i18n/messages/en.json

@@ -3,6 +3,7 @@
     "cancel-order-lines-invalid-order-state": "Cannot cancel OrderLines from an Order in the \"{ state }\" state",
     "cancel-order-lines-nothing-to-cancel": "Nothing to cancel",
     "cancel-order-lines-quantity-too-high": "Quantity to cancel is greater than existing OrderLine quantity",
+    "cannot-delete-role": "The role '{ roleCode }' cannot be deleted",
     "cannot-modify-role": "The role '{ roleCode }' cannot be modified",
     "cannot-create-sales-for-active-order": "Cannot create a Sale for an Order which is still active",
     "cannot-move-collection-into-self": "Cannot move a Collection into itself",

+ 1 - 0
packages/core/src/service/services/channel.service.ts

@@ -169,6 +169,7 @@ export class ChannelService {
     }
 
     async delete(id: ID): Promise<DeletionResponse> {
+        await getEntityOrThrow(this.connection, Channel, id);
         await this.connection.getRepository(Channel).delete(id);
         await this.connection.getRepository(ProductVariantPrice).delete({
             channelId: id,

+ 21 - 1
packages/core/src/service/services/role.service.ts

@@ -1,6 +1,12 @@
 import { Injectable } from '@nestjs/common';
 import { InjectConnection } from '@nestjs/typeorm';
-import { CreateRoleInput, Permission, UpdateRoleInput } from '@vendure/common/lib/generated-types';
+import {
+    CreateRoleInput,
+    DeletionResponse,
+    DeletionResult,
+    Permission,
+    UpdateRoleInput,
+} from '@vendure/common/lib/generated-types';
 import {
     CUSTOMER_ROLE_CODE,
     CUSTOMER_ROLE_DESCRIPTION,
@@ -148,6 +154,20 @@ export class RoleService {
         return assertFound(this.findOne(role.id));
     }
 
+    async delete(ctx: RequestContext, id: ID): Promise<DeletionResponse> {
+        const role = await this.findOne(id);
+        if (!role) {
+            throw new EntityNotFoundError('Role', id);
+        }
+        if (role.code === SUPER_ADMIN_ROLE_CODE || role.code === CUSTOMER_ROLE_CODE) {
+            throw new InternalServerError(`error.cannot-delete-role`, { roleCode: role.code });
+        }
+        await this.connection.getRepository(Role).remove(role);
+        return {
+            result: DeletionResult.DELETED,
+        };
+    }
+
     async assignRoleToChannel(roleId: ID, channelId: ID) {
         await this.channelService.assignToChannels(Role, roleId, [channelId]);
     }

+ 6 - 0
packages/elasticsearch-plugin/e2e/graphql/generated-e2e-elasticsearch-plugin-types.ts

@@ -1780,6 +1780,8 @@ export type Mutation = {
     createRole: Role;
     /** Update an existing Role */
     updateRole: Role;
+    /** Delete an existing Role */
+    deleteRole: DeletionResponse;
     /** Create a new ShippingMethod */
     createShippingMethod: ShippingMethod;
     /** Update an existing ShippingMethod */
@@ -2053,6 +2055,10 @@ export type MutationUpdateRoleArgs = {
     input: UpdateRoleInput;
 };
 
+export type MutationDeleteRoleArgs = {
+    id: Scalars['ID'];
+};
+
 export type MutationCreateShippingMethodArgs = {
     input: CreateShippingMethodInput;
 };

File diff ditekan karena terlalu besar
+ 0 - 0
schema-admin.json


Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini