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);
+ }
+}