From b9a8a88928242dafdea6774a02ba51bb0b2978b5 Mon Sep 17 00:00:00 2001 From: "amplication[bot]" Date: Fri, 16 Feb 2024 05:27:40 +0000 Subject: [PATCH] Amplication build # clso7jwkm0ihpj101rixcysgi Congratulations on your first commit with Amplication! We encourage you to continue exploring the many ways Amplication can supercharge your development. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If you find Amplication useful, please show your support and give our GitHub repo a star ⭐️ This simple action helps our open-source project grow and reach more developers like you. Thank you and happy coding! Build URL: [https://app.amplication.com/clsnjidwz0f8ji601w0k5vgwn/clsnjie790f8mi601vzymg25p/clso7jmz80k4lj401qbjtswe1/builds/clso7jwkm0ihpj101rixcysgi](https://app.amplication.com/clsnjidwz0f8ji601w0k5vgwn/clsnjie790f8mi601vzymg25p/clso7jmz80k4lj401qbjtswe1/builds/clso7jwkm0ihpj101rixcysgi) --- server/.env | 2 +- server/docker-compose.yml | 2 +- server/package.json | 2 +- server/src/address/address.controller.ts | 17 + .../base/address.controller.base.spec.ts | 210 ++++++++++ .../address/base/address.controller.base.ts | 317 +++++++++++++++ server/src/app.module.ts | 19 +- .../base/customer.controller.base.spec.ts | 206 ++++++++++ .../customer/base/customer.controller.base.ts | 365 ++++++++++++++++++ server/src/customer/customer.controller.ts | 17 + .../order/base/order.controller.base.spec.ts | 202 ++++++++++ .../src/order/base/order.controller.base.ts | 295 ++++++++++++++ server/src/order/order.controller.ts | 17 + .../base/product.controller.base.spec.ts | 202 ++++++++++ .../product/base/product.controller.base.ts | 314 +++++++++++++++ server/src/product/product.controller.ts | 17 + server/src/swagger.ts | 4 +- .../user/base/user.controller.base.spec.ts | 206 ++++++++++ server/src/user/base/user.controller.base.ts | 202 ++++++++++ server/src/user/user.controller.ts | 17 + 20 files changed, 2610 insertions(+), 23 deletions(-) create mode 100644 server/src/address/address.controller.ts create mode 100644 server/src/address/base/address.controller.base.spec.ts create mode 100644 server/src/address/base/address.controller.base.ts create mode 100644 server/src/customer/base/customer.controller.base.spec.ts create mode 100644 server/src/customer/base/customer.controller.base.ts create mode 100644 server/src/customer/customer.controller.ts create mode 100644 server/src/order/base/order.controller.base.spec.ts create mode 100644 server/src/order/base/order.controller.base.ts create mode 100644 server/src/order/order.controller.ts create mode 100644 server/src/product/base/product.controller.base.spec.ts create mode 100644 server/src/product/base/product.controller.base.ts create mode 100644 server/src/product/product.controller.ts create mode 100644 server/src/user/base/user.controller.base.spec.ts create mode 100644 server/src/user/base/user.controller.base.ts create mode 100644 server/src/user/user.controller.ts diff --git a/server/.env b/server/.env index 5ab3bf0..2662f36 100644 --- a/server/.env +++ b/server/.env @@ -1,5 +1,5 @@ BCRYPT_SALT=10 -COMPOSE_PROJECT_NAME=amp_clsnjtzkx0gyaj401m9rrwx78 +COMPOSE_PROJECT_NAME=amp_clso7jmz80k4lj401qbjtswe1 DB_NAME=my-db DB_PASSWORD=admin DB_PORT=5432 diff --git a/server/docker-compose.yml b/server/docker-compose.yml index 2a466f3..189f745 100644 --- a/server/docker-compose.yml +++ b/server/docker-compose.yml @@ -9,9 +9,9 @@ services: - ${PORT}:3000 environment: BCRYPT_SALT: ${BCRYPT_SALT} + DB_URL: postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME} JWT_SECRET_KEY: ${JWT_SECRET_KEY} JWT_EXPIRATION: ${JWT_EXPIRATION} - DB_URL: postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME} depends_on: - migrate restart: on-failure diff --git a/server/package.json b/server/package.json index 40c2263..a74c58e 100644 --- a/server/package.json +++ b/server/package.json @@ -1,5 +1,5 @@ { - "name": "@light-management/server", + "name": "@demo-service/server", "private": true, "scripts": { "start": "nest start", diff --git a/server/src/address/address.controller.ts b/server/src/address/address.controller.ts new file mode 100644 index 0000000..feb5ea1 --- /dev/null +++ b/server/src/address/address.controller.ts @@ -0,0 +1,17 @@ +import * as common from "@nestjs/common"; +import * as swagger from "@nestjs/swagger"; +import * as nestAccessControl from "nest-access-control"; +import { AddressService } from "./address.service"; +import { AddressControllerBase } from "./base/address.controller.base"; + +@swagger.ApiTags("addresses") +@common.Controller("addresses") +export class AddressController extends AddressControllerBase { + constructor( + protected readonly service: AddressService, + @nestAccessControl.InjectRolesBuilder() + protected readonly rolesBuilder: nestAccessControl.RolesBuilder + ) { + super(service, rolesBuilder); + } +} diff --git a/server/src/address/base/address.controller.base.spec.ts b/server/src/address/base/address.controller.base.spec.ts new file mode 100644 index 0000000..b4e55e1 --- /dev/null +++ b/server/src/address/base/address.controller.base.spec.ts @@ -0,0 +1,210 @@ +import { Test } from "@nestjs/testing"; +import { + INestApplication, + HttpStatus, + ExecutionContext, + CallHandler, +} from "@nestjs/common"; +import request from "supertest"; +import { ACGuard } from "nest-access-control"; +import { DefaultAuthGuard } from "../../auth/defaultAuth.guard"; +import { ACLModule } from "../../auth/acl.module"; +import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; +import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; +import { map } from "rxjs"; +import { AddressController } from "../address.controller"; +import { AddressService } from "../address.service"; + +const nonExistingId = "nonExistingId"; +const existingId = "existingId"; +const CREATE_INPUT = { + address_1: "exampleAddress_1", + address_2: "exampleAddress_2", + city: "exampleCity", + createdAt: new Date(), + id: "exampleId", + state: "exampleState", + updatedAt: new Date(), + zip: 42, +}; +const CREATE_RESULT = { + address_1: "exampleAddress_1", + address_2: "exampleAddress_2", + city: "exampleCity", + createdAt: new Date(), + id: "exampleId", + state: "exampleState", + updatedAt: new Date(), + zip: 42, +}; +const FIND_MANY_RESULT = [ + { + address_1: "exampleAddress_1", + address_2: "exampleAddress_2", + city: "exampleCity", + createdAt: new Date(), + id: "exampleId", + state: "exampleState", + updatedAt: new Date(), + zip: 42, + }, +]; +const FIND_ONE_RESULT = { + address_1: "exampleAddress_1", + address_2: "exampleAddress_2", + city: "exampleCity", + createdAt: new Date(), + id: "exampleId", + state: "exampleState", + updatedAt: new Date(), + zip: 42, +}; + +const service = { + createAddress() { + return CREATE_RESULT; + }, + addresses: () => FIND_MANY_RESULT, + address: ({ where }: { where: { id: string } }) => { + switch (where.id) { + case existingId: + return FIND_ONE_RESULT; + case nonExistingId: + return null; + } + }, +}; + +const basicAuthGuard = { + canActivate: (context: ExecutionContext) => { + const argumentHost = context.switchToHttp(); + const request = argumentHost.getRequest(); + request.user = { + roles: ["user"], + }; + return true; + }, +}; + +const acGuard = { + canActivate: () => { + return true; + }, +}; + +const aclFilterResponseInterceptor = { + intercept: (context: ExecutionContext, next: CallHandler) => { + return next.handle().pipe( + map((data) => { + return data; + }) + ); + }, +}; +const aclValidateRequestInterceptor = { + intercept: (context: ExecutionContext, next: CallHandler) => { + return next.handle(); + }, +}; + +describe("Address", () => { + let app: INestApplication; + + beforeAll(async () => { + const moduleRef = await Test.createTestingModule({ + providers: [ + { + provide: AddressService, + useValue: service, + }, + ], + controllers: [AddressController], + imports: [ACLModule], + }) + .overrideGuard(DefaultAuthGuard) + .useValue(basicAuthGuard) + .overrideGuard(ACGuard) + .useValue(acGuard) + .overrideInterceptor(AclFilterResponseInterceptor) + .useValue(aclFilterResponseInterceptor) + .overrideInterceptor(AclValidateRequestInterceptor) + .useValue(aclValidateRequestInterceptor) + .compile(); + + app = moduleRef.createNestApplication(); + await app.init(); + }); + + test("POST /addresses", async () => { + await request(app.getHttpServer()) + .post("/addresses") + .send(CREATE_INPUT) + .expect(HttpStatus.CREATED) + .expect({ + ...CREATE_RESULT, + createdAt: CREATE_RESULT.createdAt.toISOString(), + updatedAt: CREATE_RESULT.updatedAt.toISOString(), + }); + }); + + test("GET /addresses", async () => { + await request(app.getHttpServer()) + .get("/addresses") + .expect(HttpStatus.OK) + .expect([ + { + ...FIND_MANY_RESULT[0], + createdAt: FIND_MANY_RESULT[0].createdAt.toISOString(), + updatedAt: FIND_MANY_RESULT[0].updatedAt.toISOString(), + }, + ]); + }); + + test("GET /addresses/:id non existing", async () => { + await request(app.getHttpServer()) + .get(`${"/addresses"}/${nonExistingId}`) + .expect(HttpStatus.NOT_FOUND) + .expect({ + statusCode: HttpStatus.NOT_FOUND, + message: `No resource was found for {"${"id"}":"${nonExistingId}"}`, + error: "Not Found", + }); + }); + + test("GET /addresses/:id existing", async () => { + await request(app.getHttpServer()) + .get(`${"/addresses"}/${existingId}`) + .expect(HttpStatus.OK) + .expect({ + ...FIND_ONE_RESULT, + createdAt: FIND_ONE_RESULT.createdAt.toISOString(), + updatedAt: FIND_ONE_RESULT.updatedAt.toISOString(), + }); + }); + + test("POST /addresses existing resource", async () => { + const agent = request(app.getHttpServer()); + await agent + .post("/addresses") + .send(CREATE_INPUT) + .expect(HttpStatus.CREATED) + .expect({ + ...CREATE_RESULT, + createdAt: CREATE_RESULT.createdAt.toISOString(), + updatedAt: CREATE_RESULT.updatedAt.toISOString(), + }) + .then(function () { + agent + .post("/addresses") + .send(CREATE_INPUT) + .expect(HttpStatus.CONFLICT) + .expect({ + statusCode: HttpStatus.CONFLICT, + }); + }); + }); + + afterAll(async () => { + await app.close(); + }); +}); diff --git a/server/src/address/base/address.controller.base.ts b/server/src/address/base/address.controller.base.ts new file mode 100644 index 0000000..5f52700 --- /dev/null +++ b/server/src/address/base/address.controller.base.ts @@ -0,0 +1,317 @@ +/* +------------------------------------------------------------------------------ +This code was generated by Amplication. + +Changes to this file will be lost if the code is regenerated. + +There are other ways to to customize your code, see this doc to learn more +https://docs.amplication.com/how-to/custom-code + +------------------------------------------------------------------------------ + */ +import * as common from "@nestjs/common"; +import * as swagger from "@nestjs/swagger"; +import { isRecordNotFoundError } from "../../prisma.util"; +import * as errors from "../../errors"; +import { Request } from "express"; +import { plainToClass } from "class-transformer"; +import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator"; +import * as nestAccessControl from "nest-access-control"; +import * as defaultAuthGuard from "../../auth/defaultAuth.guard"; +import { AddressService } from "../address.service"; +import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; +import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; +import { AddressCreateInput } from "./AddressCreateInput"; +import { Address } from "./Address"; +import { AddressFindManyArgs } from "./AddressFindManyArgs"; +import { AddressWhereUniqueInput } from "./AddressWhereUniqueInput"; +import { AddressUpdateInput } from "./AddressUpdateInput"; +import { CustomerFindManyArgs } from "../../customer/base/CustomerFindManyArgs"; +import { Customer } from "../../customer/base/Customer"; +import { CustomerWhereUniqueInput } from "../../customer/base/CustomerWhereUniqueInput"; + +@swagger.ApiBearerAuth() +@common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard) +export class AddressControllerBase { + constructor( + protected readonly service: AddressService, + protected readonly rolesBuilder: nestAccessControl.RolesBuilder + ) {} + @common.UseInterceptors(AclValidateRequestInterceptor) + @common.Post() + @swagger.ApiCreatedResponse({ type: Address }) + @nestAccessControl.UseRoles({ + resource: "Address", + action: "create", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async createAddress( + @common.Body() data: AddressCreateInput + ): Promise
{ + return await this.service.createAddress({ + data: data, + select: { + address_1: true, + address_2: true, + city: true, + createdAt: true, + id: true, + state: true, + updatedAt: true, + zip: true, + }, + }); + } + + @common.UseInterceptors(AclFilterResponseInterceptor) + @common.Get() + @swagger.ApiOkResponse({ type: [Address] }) + @ApiNestedQuery(AddressFindManyArgs) + @nestAccessControl.UseRoles({ + resource: "Address", + action: "read", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async addresses(@common.Req() request: Request): Promise { + const args = plainToClass(AddressFindManyArgs, request.query); + return this.service.addresses({ + ...args, + select: { + address_1: true, + address_2: true, + city: true, + createdAt: true, + id: true, + state: true, + updatedAt: true, + zip: true, + }, + }); + } + + @common.UseInterceptors(AclFilterResponseInterceptor) + @common.Get("/:id") + @swagger.ApiOkResponse({ type: Address }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "Address", + action: "read", + possession: "own", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async address( + @common.Param() params: AddressWhereUniqueInput + ): Promise
{ + const result = await this.service.address({ + where: params, + select: { + address_1: true, + address_2: true, + city: true, + createdAt: true, + id: true, + state: true, + updatedAt: true, + zip: true, + }, + }); + if (result === null) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + return result; + } + + @common.UseInterceptors(AclValidateRequestInterceptor) + @common.Patch("/:id") + @swagger.ApiOkResponse({ type: Address }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "Address", + action: "update", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async updateAddress( + @common.Param() params: AddressWhereUniqueInput, + @common.Body() data: AddressUpdateInput + ): Promise
{ + try { + return await this.service.updateAddress({ + where: params, + data: data, + select: { + address_1: true, + address_2: true, + city: true, + createdAt: true, + id: true, + state: true, + updatedAt: true, + zip: true, + }, + }); + } catch (error) { + if (isRecordNotFoundError(error)) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + throw error; + } + } + + @common.Delete("/:id") + @swagger.ApiOkResponse({ type: Address }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "Address", + action: "delete", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async deleteAddress( + @common.Param() params: AddressWhereUniqueInput + ): Promise
{ + try { + return await this.service.deleteAddress({ + where: params, + select: { + address_1: true, + address_2: true, + city: true, + createdAt: true, + id: true, + state: true, + updatedAt: true, + zip: true, + }, + }); + } catch (error) { + if (isRecordNotFoundError(error)) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + throw error; + } + } + + @common.UseInterceptors(AclFilterResponseInterceptor) + @common.Get("/:id/customers") + @ApiNestedQuery(CustomerFindManyArgs) + @nestAccessControl.UseRoles({ + resource: "Customer", + action: "read", + possession: "any", + }) + async findCustomers( + @common.Req() request: Request, + @common.Param() params: AddressWhereUniqueInput + ): Promise { + const query = plainToClass(CustomerFindManyArgs, request.query); + const results = await this.service.findCustomers(params.id, { + ...query, + select: { + address: { + select: { + id: true, + }, + }, + + createdAt: true, + email: true, + firstName: true, + id: true, + lastName: true, + phone: true, + updatedAt: true, + }, + }); + if (results === null) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + return results; + } + + @common.Post("/:id/customers") + @nestAccessControl.UseRoles({ + resource: "Address", + action: "update", + possession: "any", + }) + async connectCustomers( + @common.Param() params: AddressWhereUniqueInput, + @common.Body() body: CustomerWhereUniqueInput[] + ): Promise { + const data = { + customers: { + connect: body, + }, + }; + await this.service.updateAddress({ + where: params, + data, + select: { id: true }, + }); + } + + @common.Patch("/:id/customers") + @nestAccessControl.UseRoles({ + resource: "Address", + action: "update", + possession: "any", + }) + async updateCustomers( + @common.Param() params: AddressWhereUniqueInput, + @common.Body() body: CustomerWhereUniqueInput[] + ): Promise { + const data = { + customers: { + set: body, + }, + }; + await this.service.updateAddress({ + where: params, + data, + select: { id: true }, + }); + } + + @common.Delete("/:id/customers") + @nestAccessControl.UseRoles({ + resource: "Address", + action: "update", + possession: "any", + }) + async disconnectCustomers( + @common.Param() params: AddressWhereUniqueInput, + @common.Body() body: CustomerWhereUniqueInput[] + ): Promise { + const data = { + customers: { + disconnect: body, + }, + }; + await this.service.updateAddress({ + where: params, + data, + select: { id: true }, + }); + } +} diff --git a/server/src/app.module.ts b/server/src/app.module.ts index db5ef0e..d78d6e2 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -9,9 +9,7 @@ import { PrismaModule } from "./prisma/prisma.module"; import { SecretsManagerModule } from "./providers/secrets/secretsManager.module"; import { ServeStaticModule } from "@nestjs/serve-static"; import { ServeStaticOptionsService } from "./serveStaticOptions.service"; -import { ConfigModule, ConfigService } from "@nestjs/config"; -import { GraphQLModule } from "@nestjs/graphql"; -import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo"; +import { ConfigModule } from "@nestjs/config"; import { ACLModule } from "./auth/acl.module"; import { AuthModule } from "./auth/auth.module"; @@ -33,21 +31,6 @@ import { AuthModule } from "./auth/auth.module"; ServeStaticModule.forRootAsync({ useClass: ServeStaticOptionsService, }), - GraphQLModule.forRootAsync({ - driver: ApolloDriver, - useFactory: (configService: ConfigService) => { - const playground = configService.get("GRAPHQL_PLAYGROUND"); - const introspection = configService.get("GRAPHQL_INTROSPECTION"); - return { - autoSchemaFile: "schema.graphql", - sortSchema: true, - playground, - introspection: playground || introspection, - }; - }, - inject: [ConfigService], - imports: [ConfigModule], - }), ], providers: [], }) diff --git a/server/src/customer/base/customer.controller.base.spec.ts b/server/src/customer/base/customer.controller.base.spec.ts new file mode 100644 index 0000000..e5bb2ad --- /dev/null +++ b/server/src/customer/base/customer.controller.base.spec.ts @@ -0,0 +1,206 @@ +import { Test } from "@nestjs/testing"; +import { + INestApplication, + HttpStatus, + ExecutionContext, + CallHandler, +} from "@nestjs/common"; +import request from "supertest"; +import { ACGuard } from "nest-access-control"; +import { DefaultAuthGuard } from "../../auth/defaultAuth.guard"; +import { ACLModule } from "../../auth/acl.module"; +import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; +import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; +import { map } from "rxjs"; +import { CustomerController } from "../customer.controller"; +import { CustomerService } from "../customer.service"; + +const nonExistingId = "nonExistingId"; +const existingId = "existingId"; +const CREATE_INPUT = { + createdAt: new Date(), + email: "exampleEmail", + firstName: "exampleFirstName", + id: "exampleId", + lastName: "exampleLastName", + phone: "examplePhone", + updatedAt: new Date(), +}; +const CREATE_RESULT = { + createdAt: new Date(), + email: "exampleEmail", + firstName: "exampleFirstName", + id: "exampleId", + lastName: "exampleLastName", + phone: "examplePhone", + updatedAt: new Date(), +}; +const FIND_MANY_RESULT = [ + { + createdAt: new Date(), + email: "exampleEmail", + firstName: "exampleFirstName", + id: "exampleId", + lastName: "exampleLastName", + phone: "examplePhone", + updatedAt: new Date(), + }, +]; +const FIND_ONE_RESULT = { + createdAt: new Date(), + email: "exampleEmail", + firstName: "exampleFirstName", + id: "exampleId", + lastName: "exampleLastName", + phone: "examplePhone", + updatedAt: new Date(), +}; + +const service = { + createCustomer() { + return CREATE_RESULT; + }, + customers: () => FIND_MANY_RESULT, + customer: ({ where }: { where: { id: string } }) => { + switch (where.id) { + case existingId: + return FIND_ONE_RESULT; + case nonExistingId: + return null; + } + }, +}; + +const basicAuthGuard = { + canActivate: (context: ExecutionContext) => { + const argumentHost = context.switchToHttp(); + const request = argumentHost.getRequest(); + request.user = { + roles: ["user"], + }; + return true; + }, +}; + +const acGuard = { + canActivate: () => { + return true; + }, +}; + +const aclFilterResponseInterceptor = { + intercept: (context: ExecutionContext, next: CallHandler) => { + return next.handle().pipe( + map((data) => { + return data; + }) + ); + }, +}; +const aclValidateRequestInterceptor = { + intercept: (context: ExecutionContext, next: CallHandler) => { + return next.handle(); + }, +}; + +describe("Customer", () => { + let app: INestApplication; + + beforeAll(async () => { + const moduleRef = await Test.createTestingModule({ + providers: [ + { + provide: CustomerService, + useValue: service, + }, + ], + controllers: [CustomerController], + imports: [ACLModule], + }) + .overrideGuard(DefaultAuthGuard) + .useValue(basicAuthGuard) + .overrideGuard(ACGuard) + .useValue(acGuard) + .overrideInterceptor(AclFilterResponseInterceptor) + .useValue(aclFilterResponseInterceptor) + .overrideInterceptor(AclValidateRequestInterceptor) + .useValue(aclValidateRequestInterceptor) + .compile(); + + app = moduleRef.createNestApplication(); + await app.init(); + }); + + test("POST /customers", async () => { + await request(app.getHttpServer()) + .post("/customers") + .send(CREATE_INPUT) + .expect(HttpStatus.CREATED) + .expect({ + ...CREATE_RESULT, + createdAt: CREATE_RESULT.createdAt.toISOString(), + updatedAt: CREATE_RESULT.updatedAt.toISOString(), + }); + }); + + test("GET /customers", async () => { + await request(app.getHttpServer()) + .get("/customers") + .expect(HttpStatus.OK) + .expect([ + { + ...FIND_MANY_RESULT[0], + createdAt: FIND_MANY_RESULT[0].createdAt.toISOString(), + updatedAt: FIND_MANY_RESULT[0].updatedAt.toISOString(), + }, + ]); + }); + + test("GET /customers/:id non existing", async () => { + await request(app.getHttpServer()) + .get(`${"/customers"}/${nonExistingId}`) + .expect(HttpStatus.NOT_FOUND) + .expect({ + statusCode: HttpStatus.NOT_FOUND, + message: `No resource was found for {"${"id"}":"${nonExistingId}"}`, + error: "Not Found", + }); + }); + + test("GET /customers/:id existing", async () => { + await request(app.getHttpServer()) + .get(`${"/customers"}/${existingId}`) + .expect(HttpStatus.OK) + .expect({ + ...FIND_ONE_RESULT, + createdAt: FIND_ONE_RESULT.createdAt.toISOString(), + updatedAt: FIND_ONE_RESULT.updatedAt.toISOString(), + }); + }); + + test("POST /customers existing resource", async () => { + const agent = request(app.getHttpServer()); + await agent + .post("/customers") + .send(CREATE_INPUT) + .expect(HttpStatus.CREATED) + .expect({ + ...CREATE_RESULT, + createdAt: CREATE_RESULT.createdAt.toISOString(), + updatedAt: CREATE_RESULT.updatedAt.toISOString(), + }) + .then(function () { + agent + .post("/customers") + .send(CREATE_INPUT) + .expect(HttpStatus.CONFLICT) + .expect({ + statusCode: HttpStatus.CONFLICT, + }); + }); + }); + + afterAll(async () => { + await app.close(); + }); +}); diff --git a/server/src/customer/base/customer.controller.base.ts b/server/src/customer/base/customer.controller.base.ts new file mode 100644 index 0000000..4342a4d --- /dev/null +++ b/server/src/customer/base/customer.controller.base.ts @@ -0,0 +1,365 @@ +/* +------------------------------------------------------------------------------ +This code was generated by Amplication. + +Changes to this file will be lost if the code is regenerated. + +There are other ways to to customize your code, see this doc to learn more +https://docs.amplication.com/how-to/custom-code + +------------------------------------------------------------------------------ + */ +import * as common from "@nestjs/common"; +import * as swagger from "@nestjs/swagger"; +import { isRecordNotFoundError } from "../../prisma.util"; +import * as errors from "../../errors"; +import { Request } from "express"; +import { plainToClass } from "class-transformer"; +import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator"; +import * as nestAccessControl from "nest-access-control"; +import * as defaultAuthGuard from "../../auth/defaultAuth.guard"; +import { CustomerService } from "../customer.service"; +import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; +import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; +import { CustomerCreateInput } from "./CustomerCreateInput"; +import { Customer } from "./Customer"; +import { CustomerFindManyArgs } from "./CustomerFindManyArgs"; +import { CustomerWhereUniqueInput } from "./CustomerWhereUniqueInput"; +import { CustomerUpdateInput } from "./CustomerUpdateInput"; +import { OrderFindManyArgs } from "../../order/base/OrderFindManyArgs"; +import { Order } from "../../order/base/Order"; +import { OrderWhereUniqueInput } from "../../order/base/OrderWhereUniqueInput"; + +@swagger.ApiBearerAuth() +@common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard) +export class CustomerControllerBase { + constructor( + protected readonly service: CustomerService, + protected readonly rolesBuilder: nestAccessControl.RolesBuilder + ) {} + @common.UseInterceptors(AclValidateRequestInterceptor) + @common.Post() + @swagger.ApiCreatedResponse({ type: Customer }) + @nestAccessControl.UseRoles({ + resource: "Customer", + action: "create", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async createCustomer( + @common.Body() data: CustomerCreateInput + ): Promise { + return await this.service.createCustomer({ + data: { + ...data, + + address: data.address + ? { + connect: data.address, + } + : undefined, + }, + select: { + address: { + select: { + id: true, + }, + }, + + createdAt: true, + email: true, + firstName: true, + id: true, + lastName: true, + phone: true, + updatedAt: true, + }, + }); + } + + @common.UseInterceptors(AclFilterResponseInterceptor) + @common.Get() + @swagger.ApiOkResponse({ type: [Customer] }) + @ApiNestedQuery(CustomerFindManyArgs) + @nestAccessControl.UseRoles({ + resource: "Customer", + action: "read", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async customers(@common.Req() request: Request): Promise { + const args = plainToClass(CustomerFindManyArgs, request.query); + return this.service.customers({ + ...args, + select: { + address: { + select: { + id: true, + }, + }, + + createdAt: true, + email: true, + firstName: true, + id: true, + lastName: true, + phone: true, + updatedAt: true, + }, + }); + } + + @common.UseInterceptors(AclFilterResponseInterceptor) + @common.Get("/:id") + @swagger.ApiOkResponse({ type: Customer }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "Customer", + action: "read", + possession: "own", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async customer( + @common.Param() params: CustomerWhereUniqueInput + ): Promise { + const result = await this.service.customer({ + where: params, + select: { + address: { + select: { + id: true, + }, + }, + + createdAt: true, + email: true, + firstName: true, + id: true, + lastName: true, + phone: true, + updatedAt: true, + }, + }); + if (result === null) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + return result; + } + + @common.UseInterceptors(AclValidateRequestInterceptor) + @common.Patch("/:id") + @swagger.ApiOkResponse({ type: Customer }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "Customer", + action: "update", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async updateCustomer( + @common.Param() params: CustomerWhereUniqueInput, + @common.Body() data: CustomerUpdateInput + ): Promise { + try { + return await this.service.updateCustomer({ + where: params, + data: { + ...data, + + address: data.address + ? { + connect: data.address, + } + : undefined, + }, + select: { + address: { + select: { + id: true, + }, + }, + + createdAt: true, + email: true, + firstName: true, + id: true, + lastName: true, + phone: true, + updatedAt: true, + }, + }); + } catch (error) { + if (isRecordNotFoundError(error)) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + throw error; + } + } + + @common.Delete("/:id") + @swagger.ApiOkResponse({ type: Customer }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "Customer", + action: "delete", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async deleteCustomer( + @common.Param() params: CustomerWhereUniqueInput + ): Promise { + try { + return await this.service.deleteCustomer({ + where: params, + select: { + address: { + select: { + id: true, + }, + }, + + createdAt: true, + email: true, + firstName: true, + id: true, + lastName: true, + phone: true, + updatedAt: true, + }, + }); + } catch (error) { + if (isRecordNotFoundError(error)) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + throw error; + } + } + + @common.UseInterceptors(AclFilterResponseInterceptor) + @common.Get("/:id/orders") + @ApiNestedQuery(OrderFindManyArgs) + @nestAccessControl.UseRoles({ + resource: "Order", + action: "read", + possession: "any", + }) + async findOrders( + @common.Req() request: Request, + @common.Param() params: CustomerWhereUniqueInput + ): Promise { + const query = plainToClass(OrderFindManyArgs, request.query); + const results = await this.service.findOrders(params.id, { + ...query, + select: { + createdAt: true, + + customer: { + select: { + id: true, + }, + }, + + discount: true, + id: true, + + product: { + select: { + id: true, + }, + }, + + quantity: true, + totalPrice: true, + updatedAt: true, + }, + }); + if (results === null) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + return results; + } + + @common.Post("/:id/orders") + @nestAccessControl.UseRoles({ + resource: "Customer", + action: "update", + possession: "any", + }) + async connectOrders( + @common.Param() params: CustomerWhereUniqueInput, + @common.Body() body: OrderWhereUniqueInput[] + ): Promise { + const data = { + orders: { + connect: body, + }, + }; + await this.service.updateCustomer({ + where: params, + data, + select: { id: true }, + }); + } + + @common.Patch("/:id/orders") + @nestAccessControl.UseRoles({ + resource: "Customer", + action: "update", + possession: "any", + }) + async updateOrders( + @common.Param() params: CustomerWhereUniqueInput, + @common.Body() body: OrderWhereUniqueInput[] + ): Promise { + const data = { + orders: { + set: body, + }, + }; + await this.service.updateCustomer({ + where: params, + data, + select: { id: true }, + }); + } + + @common.Delete("/:id/orders") + @nestAccessControl.UseRoles({ + resource: "Customer", + action: "update", + possession: "any", + }) + async disconnectOrders( + @common.Param() params: CustomerWhereUniqueInput, + @common.Body() body: OrderWhereUniqueInput[] + ): Promise { + const data = { + orders: { + disconnect: body, + }, + }; + await this.service.updateCustomer({ + where: params, + data, + select: { id: true }, + }); + } +} diff --git a/server/src/customer/customer.controller.ts b/server/src/customer/customer.controller.ts new file mode 100644 index 0000000..1da4964 --- /dev/null +++ b/server/src/customer/customer.controller.ts @@ -0,0 +1,17 @@ +import * as common from "@nestjs/common"; +import * as swagger from "@nestjs/swagger"; +import * as nestAccessControl from "nest-access-control"; +import { CustomerService } from "./customer.service"; +import { CustomerControllerBase } from "./base/customer.controller.base"; + +@swagger.ApiTags("customers") +@common.Controller("customers") +export class CustomerController extends CustomerControllerBase { + constructor( + protected readonly service: CustomerService, + @nestAccessControl.InjectRolesBuilder() + protected readonly rolesBuilder: nestAccessControl.RolesBuilder + ) { + super(service, rolesBuilder); + } +} diff --git a/server/src/order/base/order.controller.base.spec.ts b/server/src/order/base/order.controller.base.spec.ts new file mode 100644 index 0000000..f954e6b --- /dev/null +++ b/server/src/order/base/order.controller.base.spec.ts @@ -0,0 +1,202 @@ +import { Test } from "@nestjs/testing"; +import { + INestApplication, + HttpStatus, + ExecutionContext, + CallHandler, +} from "@nestjs/common"; +import request from "supertest"; +import { ACGuard } from "nest-access-control"; +import { DefaultAuthGuard } from "../../auth/defaultAuth.guard"; +import { ACLModule } from "../../auth/acl.module"; +import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; +import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; +import { map } from "rxjs"; +import { OrderController } from "../order.controller"; +import { OrderService } from "../order.service"; + +const nonExistingId = "nonExistingId"; +const existingId = "existingId"; +const CREATE_INPUT = { + createdAt: new Date(), + discount: 42.42, + id: "exampleId", + quantity: 42, + totalPrice: 42, + updatedAt: new Date(), +}; +const CREATE_RESULT = { + createdAt: new Date(), + discount: 42.42, + id: "exampleId", + quantity: 42, + totalPrice: 42, + updatedAt: new Date(), +}; +const FIND_MANY_RESULT = [ + { + createdAt: new Date(), + discount: 42.42, + id: "exampleId", + quantity: 42, + totalPrice: 42, + updatedAt: new Date(), + }, +]; +const FIND_ONE_RESULT = { + createdAt: new Date(), + discount: 42.42, + id: "exampleId", + quantity: 42, + totalPrice: 42, + updatedAt: new Date(), +}; + +const service = { + createOrder() { + return CREATE_RESULT; + }, + orders: () => FIND_MANY_RESULT, + order: ({ where }: { where: { id: string } }) => { + switch (where.id) { + case existingId: + return FIND_ONE_RESULT; + case nonExistingId: + return null; + } + }, +}; + +const basicAuthGuard = { + canActivate: (context: ExecutionContext) => { + const argumentHost = context.switchToHttp(); + const request = argumentHost.getRequest(); + request.user = { + roles: ["user"], + }; + return true; + }, +}; + +const acGuard = { + canActivate: () => { + return true; + }, +}; + +const aclFilterResponseInterceptor = { + intercept: (context: ExecutionContext, next: CallHandler) => { + return next.handle().pipe( + map((data) => { + return data; + }) + ); + }, +}; +const aclValidateRequestInterceptor = { + intercept: (context: ExecutionContext, next: CallHandler) => { + return next.handle(); + }, +}; + +describe("Order", () => { + let app: INestApplication; + + beforeAll(async () => { + const moduleRef = await Test.createTestingModule({ + providers: [ + { + provide: OrderService, + useValue: service, + }, + ], + controllers: [OrderController], + imports: [ACLModule], + }) + .overrideGuard(DefaultAuthGuard) + .useValue(basicAuthGuard) + .overrideGuard(ACGuard) + .useValue(acGuard) + .overrideInterceptor(AclFilterResponseInterceptor) + .useValue(aclFilterResponseInterceptor) + .overrideInterceptor(AclValidateRequestInterceptor) + .useValue(aclValidateRequestInterceptor) + .compile(); + + app = moduleRef.createNestApplication(); + await app.init(); + }); + + test("POST /orders", async () => { + await request(app.getHttpServer()) + .post("/orders") + .send(CREATE_INPUT) + .expect(HttpStatus.CREATED) + .expect({ + ...CREATE_RESULT, + createdAt: CREATE_RESULT.createdAt.toISOString(), + updatedAt: CREATE_RESULT.updatedAt.toISOString(), + }); + }); + + test("GET /orders", async () => { + await request(app.getHttpServer()) + .get("/orders") + .expect(HttpStatus.OK) + .expect([ + { + ...FIND_MANY_RESULT[0], + createdAt: FIND_MANY_RESULT[0].createdAt.toISOString(), + updatedAt: FIND_MANY_RESULT[0].updatedAt.toISOString(), + }, + ]); + }); + + test("GET /orders/:id non existing", async () => { + await request(app.getHttpServer()) + .get(`${"/orders"}/${nonExistingId}`) + .expect(HttpStatus.NOT_FOUND) + .expect({ + statusCode: HttpStatus.NOT_FOUND, + message: `No resource was found for {"${"id"}":"${nonExistingId}"}`, + error: "Not Found", + }); + }); + + test("GET /orders/:id existing", async () => { + await request(app.getHttpServer()) + .get(`${"/orders"}/${existingId}`) + .expect(HttpStatus.OK) + .expect({ + ...FIND_ONE_RESULT, + createdAt: FIND_ONE_RESULT.createdAt.toISOString(), + updatedAt: FIND_ONE_RESULT.updatedAt.toISOString(), + }); + }); + + test("POST /orders existing resource", async () => { + const agent = request(app.getHttpServer()); + await agent + .post("/orders") + .send(CREATE_INPUT) + .expect(HttpStatus.CREATED) + .expect({ + ...CREATE_RESULT, + createdAt: CREATE_RESULT.createdAt.toISOString(), + updatedAt: CREATE_RESULT.updatedAt.toISOString(), + }) + .then(function () { + agent + .post("/orders") + .send(CREATE_INPUT) + .expect(HttpStatus.CONFLICT) + .expect({ + statusCode: HttpStatus.CONFLICT, + }); + }); + }); + + afterAll(async () => { + await app.close(); + }); +}); diff --git a/server/src/order/base/order.controller.base.ts b/server/src/order/base/order.controller.base.ts new file mode 100644 index 0000000..a82cf7f --- /dev/null +++ b/server/src/order/base/order.controller.base.ts @@ -0,0 +1,295 @@ +/* +------------------------------------------------------------------------------ +This code was generated by Amplication. + +Changes to this file will be lost if the code is regenerated. + +There are other ways to to customize your code, see this doc to learn more +https://docs.amplication.com/how-to/custom-code + +------------------------------------------------------------------------------ + */ +import * as common from "@nestjs/common"; +import * as swagger from "@nestjs/swagger"; +import { isRecordNotFoundError } from "../../prisma.util"; +import * as errors from "../../errors"; +import { Request } from "express"; +import { plainToClass } from "class-transformer"; +import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator"; +import * as nestAccessControl from "nest-access-control"; +import * as defaultAuthGuard from "../../auth/defaultAuth.guard"; +import { OrderService } from "../order.service"; +import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; +import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; +import { OrderCreateInput } from "./OrderCreateInput"; +import { Order } from "./Order"; +import { OrderFindManyArgs } from "./OrderFindManyArgs"; +import { OrderWhereUniqueInput } from "./OrderWhereUniqueInput"; +import { OrderUpdateInput } from "./OrderUpdateInput"; + +@swagger.ApiBearerAuth() +@common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard) +export class OrderControllerBase { + constructor( + protected readonly service: OrderService, + protected readonly rolesBuilder: nestAccessControl.RolesBuilder + ) {} + @common.UseInterceptors(AclValidateRequestInterceptor) + @common.Post() + @swagger.ApiCreatedResponse({ type: Order }) + @nestAccessControl.UseRoles({ + resource: "Order", + action: "create", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async createOrder(@common.Body() data: OrderCreateInput): Promise { + return await this.service.createOrder({ + data: { + ...data, + + customer: data.customer + ? { + connect: data.customer, + } + : undefined, + + product: data.product + ? { + connect: data.product, + } + : undefined, + }, + select: { + createdAt: true, + + customer: { + select: { + id: true, + }, + }, + + discount: true, + id: true, + + product: { + select: { + id: true, + }, + }, + + quantity: true, + totalPrice: true, + updatedAt: true, + }, + }); + } + + @common.UseInterceptors(AclFilterResponseInterceptor) + @common.Get() + @swagger.ApiOkResponse({ type: [Order] }) + @ApiNestedQuery(OrderFindManyArgs) + @nestAccessControl.UseRoles({ + resource: "Order", + action: "read", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async orders(@common.Req() request: Request): Promise { + const args = plainToClass(OrderFindManyArgs, request.query); + return this.service.orders({ + ...args, + select: { + createdAt: true, + + customer: { + select: { + id: true, + }, + }, + + discount: true, + id: true, + + product: { + select: { + id: true, + }, + }, + + quantity: true, + totalPrice: true, + updatedAt: true, + }, + }); + } + + @common.UseInterceptors(AclFilterResponseInterceptor) + @common.Get("/:id") + @swagger.ApiOkResponse({ type: Order }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "Order", + action: "read", + possession: "own", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async order( + @common.Param() params: OrderWhereUniqueInput + ): Promise { + const result = await this.service.order({ + where: params, + select: { + createdAt: true, + + customer: { + select: { + id: true, + }, + }, + + discount: true, + id: true, + + product: { + select: { + id: true, + }, + }, + + quantity: true, + totalPrice: true, + updatedAt: true, + }, + }); + if (result === null) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + return result; + } + + @common.UseInterceptors(AclValidateRequestInterceptor) + @common.Patch("/:id") + @swagger.ApiOkResponse({ type: Order }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "Order", + action: "update", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async updateOrder( + @common.Param() params: OrderWhereUniqueInput, + @common.Body() data: OrderUpdateInput + ): Promise { + try { + return await this.service.updateOrder({ + where: params, + data: { + ...data, + + customer: data.customer + ? { + connect: data.customer, + } + : undefined, + + product: data.product + ? { + connect: data.product, + } + : undefined, + }, + select: { + createdAt: true, + + customer: { + select: { + id: true, + }, + }, + + discount: true, + id: true, + + product: { + select: { + id: true, + }, + }, + + quantity: true, + totalPrice: true, + updatedAt: true, + }, + }); + } catch (error) { + if (isRecordNotFoundError(error)) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + throw error; + } + } + + @common.Delete("/:id") + @swagger.ApiOkResponse({ type: Order }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "Order", + action: "delete", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async deleteOrder( + @common.Param() params: OrderWhereUniqueInput + ): Promise { + try { + return await this.service.deleteOrder({ + where: params, + select: { + createdAt: true, + + customer: { + select: { + id: true, + }, + }, + + discount: true, + id: true, + + product: { + select: { + id: true, + }, + }, + + quantity: true, + totalPrice: true, + updatedAt: true, + }, + }); + } catch (error) { + if (isRecordNotFoundError(error)) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + throw error; + } + } +} diff --git a/server/src/order/order.controller.ts b/server/src/order/order.controller.ts new file mode 100644 index 0000000..07002fd --- /dev/null +++ b/server/src/order/order.controller.ts @@ -0,0 +1,17 @@ +import * as common from "@nestjs/common"; +import * as swagger from "@nestjs/swagger"; +import * as nestAccessControl from "nest-access-control"; +import { OrderService } from "./order.service"; +import { OrderControllerBase } from "./base/order.controller.base"; + +@swagger.ApiTags("orders") +@common.Controller("orders") +export class OrderController extends OrderControllerBase { + constructor( + protected readonly service: OrderService, + @nestAccessControl.InjectRolesBuilder() + protected readonly rolesBuilder: nestAccessControl.RolesBuilder + ) { + super(service, rolesBuilder); + } +} diff --git a/server/src/product/base/product.controller.base.spec.ts b/server/src/product/base/product.controller.base.spec.ts new file mode 100644 index 0000000..cfb4a79 --- /dev/null +++ b/server/src/product/base/product.controller.base.spec.ts @@ -0,0 +1,202 @@ +import { Test } from "@nestjs/testing"; +import { + INestApplication, + HttpStatus, + ExecutionContext, + CallHandler, +} from "@nestjs/common"; +import request from "supertest"; +import { ACGuard } from "nest-access-control"; +import { DefaultAuthGuard } from "../../auth/defaultAuth.guard"; +import { ACLModule } from "../../auth/acl.module"; +import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; +import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; +import { map } from "rxjs"; +import { ProductController } from "../product.controller"; +import { ProductService } from "../product.service"; + +const nonExistingId = "nonExistingId"; +const existingId = "existingId"; +const CREATE_INPUT = { + createdAt: new Date(), + description: "exampleDescription", + id: "exampleId", + itemPrice: 42.42, + name: "exampleName", + updatedAt: new Date(), +}; +const CREATE_RESULT = { + createdAt: new Date(), + description: "exampleDescription", + id: "exampleId", + itemPrice: 42.42, + name: "exampleName", + updatedAt: new Date(), +}; +const FIND_MANY_RESULT = [ + { + createdAt: new Date(), + description: "exampleDescription", + id: "exampleId", + itemPrice: 42.42, + name: "exampleName", + updatedAt: new Date(), + }, +]; +const FIND_ONE_RESULT = { + createdAt: new Date(), + description: "exampleDescription", + id: "exampleId", + itemPrice: 42.42, + name: "exampleName", + updatedAt: new Date(), +}; + +const service = { + createProduct() { + return CREATE_RESULT; + }, + products: () => FIND_MANY_RESULT, + product: ({ where }: { where: { id: string } }) => { + switch (where.id) { + case existingId: + return FIND_ONE_RESULT; + case nonExistingId: + return null; + } + }, +}; + +const basicAuthGuard = { + canActivate: (context: ExecutionContext) => { + const argumentHost = context.switchToHttp(); + const request = argumentHost.getRequest(); + request.user = { + roles: ["user"], + }; + return true; + }, +}; + +const acGuard = { + canActivate: () => { + return true; + }, +}; + +const aclFilterResponseInterceptor = { + intercept: (context: ExecutionContext, next: CallHandler) => { + return next.handle().pipe( + map((data) => { + return data; + }) + ); + }, +}; +const aclValidateRequestInterceptor = { + intercept: (context: ExecutionContext, next: CallHandler) => { + return next.handle(); + }, +}; + +describe("Product", () => { + let app: INestApplication; + + beforeAll(async () => { + const moduleRef = await Test.createTestingModule({ + providers: [ + { + provide: ProductService, + useValue: service, + }, + ], + controllers: [ProductController], + imports: [ACLModule], + }) + .overrideGuard(DefaultAuthGuard) + .useValue(basicAuthGuard) + .overrideGuard(ACGuard) + .useValue(acGuard) + .overrideInterceptor(AclFilterResponseInterceptor) + .useValue(aclFilterResponseInterceptor) + .overrideInterceptor(AclValidateRequestInterceptor) + .useValue(aclValidateRequestInterceptor) + .compile(); + + app = moduleRef.createNestApplication(); + await app.init(); + }); + + test("POST /products", async () => { + await request(app.getHttpServer()) + .post("/products") + .send(CREATE_INPUT) + .expect(HttpStatus.CREATED) + .expect({ + ...CREATE_RESULT, + createdAt: CREATE_RESULT.createdAt.toISOString(), + updatedAt: CREATE_RESULT.updatedAt.toISOString(), + }); + }); + + test("GET /products", async () => { + await request(app.getHttpServer()) + .get("/products") + .expect(HttpStatus.OK) + .expect([ + { + ...FIND_MANY_RESULT[0], + createdAt: FIND_MANY_RESULT[0].createdAt.toISOString(), + updatedAt: FIND_MANY_RESULT[0].updatedAt.toISOString(), + }, + ]); + }); + + test("GET /products/:id non existing", async () => { + await request(app.getHttpServer()) + .get(`${"/products"}/${nonExistingId}`) + .expect(HttpStatus.NOT_FOUND) + .expect({ + statusCode: HttpStatus.NOT_FOUND, + message: `No resource was found for {"${"id"}":"${nonExistingId}"}`, + error: "Not Found", + }); + }); + + test("GET /products/:id existing", async () => { + await request(app.getHttpServer()) + .get(`${"/products"}/${existingId}`) + .expect(HttpStatus.OK) + .expect({ + ...FIND_ONE_RESULT, + createdAt: FIND_ONE_RESULT.createdAt.toISOString(), + updatedAt: FIND_ONE_RESULT.updatedAt.toISOString(), + }); + }); + + test("POST /products existing resource", async () => { + const agent = request(app.getHttpServer()); + await agent + .post("/products") + .send(CREATE_INPUT) + .expect(HttpStatus.CREATED) + .expect({ + ...CREATE_RESULT, + createdAt: CREATE_RESULT.createdAt.toISOString(), + updatedAt: CREATE_RESULT.updatedAt.toISOString(), + }) + .then(function () { + agent + .post("/products") + .send(CREATE_INPUT) + .expect(HttpStatus.CONFLICT) + .expect({ + statusCode: HttpStatus.CONFLICT, + }); + }); + }); + + afterAll(async () => { + await app.close(); + }); +}); diff --git a/server/src/product/base/product.controller.base.ts b/server/src/product/base/product.controller.base.ts new file mode 100644 index 0000000..2086dc8 --- /dev/null +++ b/server/src/product/base/product.controller.base.ts @@ -0,0 +1,314 @@ +/* +------------------------------------------------------------------------------ +This code was generated by Amplication. + +Changes to this file will be lost if the code is regenerated. + +There are other ways to to customize your code, see this doc to learn more +https://docs.amplication.com/how-to/custom-code + +------------------------------------------------------------------------------ + */ +import * as common from "@nestjs/common"; +import * as swagger from "@nestjs/swagger"; +import { isRecordNotFoundError } from "../../prisma.util"; +import * as errors from "../../errors"; +import { Request } from "express"; +import { plainToClass } from "class-transformer"; +import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator"; +import * as nestAccessControl from "nest-access-control"; +import * as defaultAuthGuard from "../../auth/defaultAuth.guard"; +import { ProductService } from "../product.service"; +import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; +import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; +import { ProductCreateInput } from "./ProductCreateInput"; +import { Product } from "./Product"; +import { ProductFindManyArgs } from "./ProductFindManyArgs"; +import { ProductWhereUniqueInput } from "./ProductWhereUniqueInput"; +import { ProductUpdateInput } from "./ProductUpdateInput"; +import { OrderFindManyArgs } from "../../order/base/OrderFindManyArgs"; +import { Order } from "../../order/base/Order"; +import { OrderWhereUniqueInput } from "../../order/base/OrderWhereUniqueInput"; + +@swagger.ApiBearerAuth() +@common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard) +export class ProductControllerBase { + constructor( + protected readonly service: ProductService, + protected readonly rolesBuilder: nestAccessControl.RolesBuilder + ) {} + @common.UseInterceptors(AclValidateRequestInterceptor) + @common.Post() + @swagger.ApiCreatedResponse({ type: Product }) + @nestAccessControl.UseRoles({ + resource: "Product", + action: "create", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async createProduct( + @common.Body() data: ProductCreateInput + ): Promise { + return await this.service.createProduct({ + data: data, + select: { + createdAt: true, + description: true, + id: true, + itemPrice: true, + name: true, + updatedAt: true, + }, + }); + } + + @common.UseInterceptors(AclFilterResponseInterceptor) + @common.Get() + @swagger.ApiOkResponse({ type: [Product] }) + @ApiNestedQuery(ProductFindManyArgs) + @nestAccessControl.UseRoles({ + resource: "Product", + action: "read", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async products(@common.Req() request: Request): Promise { + const args = plainToClass(ProductFindManyArgs, request.query); + return this.service.products({ + ...args, + select: { + createdAt: true, + description: true, + id: true, + itemPrice: true, + name: true, + updatedAt: true, + }, + }); + } + + @common.UseInterceptors(AclFilterResponseInterceptor) + @common.Get("/:id") + @swagger.ApiOkResponse({ type: Product }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "Product", + action: "read", + possession: "own", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async product( + @common.Param() params: ProductWhereUniqueInput + ): Promise { + const result = await this.service.product({ + where: params, + select: { + createdAt: true, + description: true, + id: true, + itemPrice: true, + name: true, + updatedAt: true, + }, + }); + if (result === null) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + return result; + } + + @common.UseInterceptors(AclValidateRequestInterceptor) + @common.Patch("/:id") + @swagger.ApiOkResponse({ type: Product }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "Product", + action: "update", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async updateProduct( + @common.Param() params: ProductWhereUniqueInput, + @common.Body() data: ProductUpdateInput + ): Promise { + try { + return await this.service.updateProduct({ + where: params, + data: data, + select: { + createdAt: true, + description: true, + id: true, + itemPrice: true, + name: true, + updatedAt: true, + }, + }); + } catch (error) { + if (isRecordNotFoundError(error)) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + throw error; + } + } + + @common.Delete("/:id") + @swagger.ApiOkResponse({ type: Product }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "Product", + action: "delete", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async deleteProduct( + @common.Param() params: ProductWhereUniqueInput + ): Promise { + try { + return await this.service.deleteProduct({ + where: params, + select: { + createdAt: true, + description: true, + id: true, + itemPrice: true, + name: true, + updatedAt: true, + }, + }); + } catch (error) { + if (isRecordNotFoundError(error)) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + throw error; + } + } + + @common.UseInterceptors(AclFilterResponseInterceptor) + @common.Get("/:id/orders") + @ApiNestedQuery(OrderFindManyArgs) + @nestAccessControl.UseRoles({ + resource: "Order", + action: "read", + possession: "any", + }) + async findOrders( + @common.Req() request: Request, + @common.Param() params: ProductWhereUniqueInput + ): Promise { + const query = plainToClass(OrderFindManyArgs, request.query); + const results = await this.service.findOrders(params.id, { + ...query, + select: { + createdAt: true, + + customer: { + select: { + id: true, + }, + }, + + discount: true, + id: true, + + product: { + select: { + id: true, + }, + }, + + quantity: true, + totalPrice: true, + updatedAt: true, + }, + }); + if (results === null) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + return results; + } + + @common.Post("/:id/orders") + @nestAccessControl.UseRoles({ + resource: "Product", + action: "update", + possession: "any", + }) + async connectOrders( + @common.Param() params: ProductWhereUniqueInput, + @common.Body() body: OrderWhereUniqueInput[] + ): Promise { + const data = { + orders: { + connect: body, + }, + }; + await this.service.updateProduct({ + where: params, + data, + select: { id: true }, + }); + } + + @common.Patch("/:id/orders") + @nestAccessControl.UseRoles({ + resource: "Product", + action: "update", + possession: "any", + }) + async updateOrders( + @common.Param() params: ProductWhereUniqueInput, + @common.Body() body: OrderWhereUniqueInput[] + ): Promise { + const data = { + orders: { + set: body, + }, + }; + await this.service.updateProduct({ + where: params, + data, + select: { id: true }, + }); + } + + @common.Delete("/:id/orders") + @nestAccessControl.UseRoles({ + resource: "Product", + action: "update", + possession: "any", + }) + async disconnectOrders( + @common.Param() params: ProductWhereUniqueInput, + @common.Body() body: OrderWhereUniqueInput[] + ): Promise { + const data = { + orders: { + disconnect: body, + }, + }; + await this.service.updateProduct({ + where: params, + data, + select: { id: true }, + }); + } +} diff --git a/server/src/product/product.controller.ts b/server/src/product/product.controller.ts new file mode 100644 index 0000000..b7c034f --- /dev/null +++ b/server/src/product/product.controller.ts @@ -0,0 +1,17 @@ +import * as common from "@nestjs/common"; +import * as swagger from "@nestjs/swagger"; +import * as nestAccessControl from "nest-access-control"; +import { ProductService } from "./product.service"; +import { ProductControllerBase } from "./base/product.controller.base"; + +@swagger.ApiTags("products") +@common.Controller("products") +export class ProductController extends ProductControllerBase { + constructor( + protected readonly service: ProductService, + @nestAccessControl.InjectRolesBuilder() + protected readonly rolesBuilder: nestAccessControl.RolesBuilder + ) { + super(service, rolesBuilder); + } +} diff --git a/server/src/swagger.ts b/server/src/swagger.ts index bb81f81..2c646d3 100644 --- a/server/src/swagger.ts +++ b/server/src/swagger.ts @@ -3,7 +3,7 @@ import { DocumentBuilder, SwaggerCustomOptions } from "@nestjs/swagger"; export const swaggerPath = "api"; export const swaggerDocumentOptions = new DocumentBuilder() - .setTitle("Light management") + .setTitle("Demo service") .setDescription( 'Sample service for e-commerce\n\n## Congratulations! Your service resource is ready.\n \nPlease note that all endpoints are secured with JWT Bearer authentication.\nBy default, your service resource comes with one user with the username "admin" and password "admin".\nLearn more in [our docs](https://docs.amplication.com)' ) @@ -16,5 +16,5 @@ export const swaggerSetupOptions: SwaggerCustomOptions = { }, customCssUrl: "../swagger/swagger.css", customfavIcon: "../swagger/favicon.png", - customSiteTitle: "Light management", + customSiteTitle: "Demo service", }; diff --git a/server/src/user/base/user.controller.base.spec.ts b/server/src/user/base/user.controller.base.spec.ts new file mode 100644 index 0000000..fb15280 --- /dev/null +++ b/server/src/user/base/user.controller.base.spec.ts @@ -0,0 +1,206 @@ +import { Test } from "@nestjs/testing"; +import { + INestApplication, + HttpStatus, + ExecutionContext, + CallHandler, +} from "@nestjs/common"; +import request from "supertest"; +import { ACGuard } from "nest-access-control"; +import { DefaultAuthGuard } from "../../auth/defaultAuth.guard"; +import { ACLModule } from "../../auth/acl.module"; +import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; +import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; +import { map } from "rxjs"; +import { UserController } from "../user.controller"; +import { UserService } from "../user.service"; + +const nonExistingId = "nonExistingId"; +const existingId = "existingId"; +const CREATE_INPUT = { + createdAt: new Date(), + firstName: "exampleFirstName", + id: "exampleId", + lastName: "exampleLastName", + password: "examplePassword", + updatedAt: new Date(), + username: "exampleUsername", +}; +const CREATE_RESULT = { + createdAt: new Date(), + firstName: "exampleFirstName", + id: "exampleId", + lastName: "exampleLastName", + password: "examplePassword", + updatedAt: new Date(), + username: "exampleUsername", +}; +const FIND_MANY_RESULT = [ + { + createdAt: new Date(), + firstName: "exampleFirstName", + id: "exampleId", + lastName: "exampleLastName", + password: "examplePassword", + updatedAt: new Date(), + username: "exampleUsername", + }, +]; +const FIND_ONE_RESULT = { + createdAt: new Date(), + firstName: "exampleFirstName", + id: "exampleId", + lastName: "exampleLastName", + password: "examplePassword", + updatedAt: new Date(), + username: "exampleUsername", +}; + +const service = { + createUser() { + return CREATE_RESULT; + }, + users: () => FIND_MANY_RESULT, + user: ({ where }: { where: { id: string } }) => { + switch (where.id) { + case existingId: + return FIND_ONE_RESULT; + case nonExistingId: + return null; + } + }, +}; + +const basicAuthGuard = { + canActivate: (context: ExecutionContext) => { + const argumentHost = context.switchToHttp(); + const request = argumentHost.getRequest(); + request.user = { + roles: ["user"], + }; + return true; + }, +}; + +const acGuard = { + canActivate: () => { + return true; + }, +}; + +const aclFilterResponseInterceptor = { + intercept: (context: ExecutionContext, next: CallHandler) => { + return next.handle().pipe( + map((data) => { + return data; + }) + ); + }, +}; +const aclValidateRequestInterceptor = { + intercept: (context: ExecutionContext, next: CallHandler) => { + return next.handle(); + }, +}; + +describe("User", () => { + let app: INestApplication; + + beforeAll(async () => { + const moduleRef = await Test.createTestingModule({ + providers: [ + { + provide: UserService, + useValue: service, + }, + ], + controllers: [UserController], + imports: [ACLModule], + }) + .overrideGuard(DefaultAuthGuard) + .useValue(basicAuthGuard) + .overrideGuard(ACGuard) + .useValue(acGuard) + .overrideInterceptor(AclFilterResponseInterceptor) + .useValue(aclFilterResponseInterceptor) + .overrideInterceptor(AclValidateRequestInterceptor) + .useValue(aclValidateRequestInterceptor) + .compile(); + + app = moduleRef.createNestApplication(); + await app.init(); + }); + + test("POST /users", async () => { + await request(app.getHttpServer()) + .post("/users") + .send(CREATE_INPUT) + .expect(HttpStatus.CREATED) + .expect({ + ...CREATE_RESULT, + createdAt: CREATE_RESULT.createdAt.toISOString(), + updatedAt: CREATE_RESULT.updatedAt.toISOString(), + }); + }); + + test("GET /users", async () => { + await request(app.getHttpServer()) + .get("/users") + .expect(HttpStatus.OK) + .expect([ + { + ...FIND_MANY_RESULT[0], + createdAt: FIND_MANY_RESULT[0].createdAt.toISOString(), + updatedAt: FIND_MANY_RESULT[0].updatedAt.toISOString(), + }, + ]); + }); + + test("GET /users/:id non existing", async () => { + await request(app.getHttpServer()) + .get(`${"/users"}/${nonExistingId}`) + .expect(HttpStatus.NOT_FOUND) + .expect({ + statusCode: HttpStatus.NOT_FOUND, + message: `No resource was found for {"${"id"}":"${nonExistingId}"}`, + error: "Not Found", + }); + }); + + test("GET /users/:id existing", async () => { + await request(app.getHttpServer()) + .get(`${"/users"}/${existingId}`) + .expect(HttpStatus.OK) + .expect({ + ...FIND_ONE_RESULT, + createdAt: FIND_ONE_RESULT.createdAt.toISOString(), + updatedAt: FIND_ONE_RESULT.updatedAt.toISOString(), + }); + }); + + test("POST /users existing resource", async () => { + const agent = request(app.getHttpServer()); + await agent + .post("/users") + .send(CREATE_INPUT) + .expect(HttpStatus.CREATED) + .expect({ + ...CREATE_RESULT, + createdAt: CREATE_RESULT.createdAt.toISOString(), + updatedAt: CREATE_RESULT.updatedAt.toISOString(), + }) + .then(function () { + agent + .post("/users") + .send(CREATE_INPUT) + .expect(HttpStatus.CONFLICT) + .expect({ + statusCode: HttpStatus.CONFLICT, + }); + }); + }); + + afterAll(async () => { + await app.close(); + }); +}); diff --git a/server/src/user/base/user.controller.base.ts b/server/src/user/base/user.controller.base.ts new file mode 100644 index 0000000..57e9815 --- /dev/null +++ b/server/src/user/base/user.controller.base.ts @@ -0,0 +1,202 @@ +/* +------------------------------------------------------------------------------ +This code was generated by Amplication. + +Changes to this file will be lost if the code is regenerated. + +There are other ways to to customize your code, see this doc to learn more +https://docs.amplication.com/how-to/custom-code + +------------------------------------------------------------------------------ + */ +import * as common from "@nestjs/common"; +import * as swagger from "@nestjs/swagger"; +import { isRecordNotFoundError } from "../../prisma.util"; +import * as errors from "../../errors"; +import { Request } from "express"; +import { plainToClass } from "class-transformer"; +import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator"; +import * as nestAccessControl from "nest-access-control"; +import * as defaultAuthGuard from "../../auth/defaultAuth.guard"; +import { UserService } from "../user.service"; +import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; +import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; +import { UserCreateInput } from "./UserCreateInput"; +import { User } from "./User"; +import { UserFindManyArgs } from "./UserFindManyArgs"; +import { UserWhereUniqueInput } from "./UserWhereUniqueInput"; +import { UserUpdateInput } from "./UserUpdateInput"; + +@swagger.ApiBearerAuth() +@common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard) +export class UserControllerBase { + constructor( + protected readonly service: UserService, + protected readonly rolesBuilder: nestAccessControl.RolesBuilder + ) {} + @common.UseInterceptors(AclValidateRequestInterceptor) + @common.Post() + @swagger.ApiCreatedResponse({ type: User }) + @nestAccessControl.UseRoles({ + resource: "User", + action: "create", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async createUser(@common.Body() data: UserCreateInput): Promise { + return await this.service.createUser({ + data: data, + select: { + createdAt: true, + firstName: true, + id: true, + lastName: true, + roles: true, + updatedAt: true, + username: true, + }, + }); + } + + @common.UseInterceptors(AclFilterResponseInterceptor) + @common.Get() + @swagger.ApiOkResponse({ type: [User] }) + @ApiNestedQuery(UserFindManyArgs) + @nestAccessControl.UseRoles({ + resource: "User", + action: "read", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async users(@common.Req() request: Request): Promise { + const args = plainToClass(UserFindManyArgs, request.query); + return this.service.users({ + ...args, + select: { + createdAt: true, + firstName: true, + id: true, + lastName: true, + roles: true, + updatedAt: true, + username: true, + }, + }); + } + + @common.UseInterceptors(AclFilterResponseInterceptor) + @common.Get("/:id") + @swagger.ApiOkResponse({ type: User }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "User", + action: "read", + possession: "own", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async user( + @common.Param() params: UserWhereUniqueInput + ): Promise { + const result = await this.service.user({ + where: params, + select: { + createdAt: true, + firstName: true, + id: true, + lastName: true, + roles: true, + updatedAt: true, + username: true, + }, + }); + if (result === null) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + return result; + } + + @common.UseInterceptors(AclValidateRequestInterceptor) + @common.Patch("/:id") + @swagger.ApiOkResponse({ type: User }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "User", + action: "update", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async updateUser( + @common.Param() params: UserWhereUniqueInput, + @common.Body() data: UserUpdateInput + ): Promise { + try { + return await this.service.updateUser({ + where: params, + data: data, + select: { + createdAt: true, + firstName: true, + id: true, + lastName: true, + roles: true, + updatedAt: true, + username: true, + }, + }); + } catch (error) { + if (isRecordNotFoundError(error)) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + throw error; + } + } + + @common.Delete("/:id") + @swagger.ApiOkResponse({ type: User }) + @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) + @nestAccessControl.UseRoles({ + resource: "User", + action: "delete", + possession: "any", + }) + @swagger.ApiForbiddenResponse({ + type: errors.ForbiddenException, + }) + async deleteUser( + @common.Param() params: UserWhereUniqueInput + ): Promise { + try { + return await this.service.deleteUser({ + where: params, + select: { + createdAt: true, + firstName: true, + id: true, + lastName: true, + roles: true, + updatedAt: true, + username: true, + }, + }); + } catch (error) { + if (isRecordNotFoundError(error)) { + throw new errors.NotFoundException( + `No resource was found for ${JSON.stringify(params)}` + ); + } + throw error; + } + } +} diff --git a/server/src/user/user.controller.ts b/server/src/user/user.controller.ts new file mode 100644 index 0000000..21d9583 --- /dev/null +++ b/server/src/user/user.controller.ts @@ -0,0 +1,17 @@ +import * as common from "@nestjs/common"; +import * as swagger from "@nestjs/swagger"; +import * as nestAccessControl from "nest-access-control"; +import { UserService } from "./user.service"; +import { UserControllerBase } from "./base/user.controller.base"; + +@swagger.ApiTags("users") +@common.Controller("users") +export class UserController extends UserControllerBase { + constructor( + protected readonly service: UserService, + @nestAccessControl.InjectRolesBuilder() + protected readonly rolesBuilder: nestAccessControl.RolesBuilder + ) { + super(service, rolesBuilder); + } +}