diff --git a/.amplication/ignored/server/.env b/.amplication/ignored/server/.env index 59ebfd6..1775791 100644 --- a/.amplication/ignored/server/.env +++ b/.amplication/ignored/server/.env @@ -5,5 +5,4 @@ DB_URL=postgres://admin:admin@localhost:5432/my-db DB_USER=admin DB_PASSWORD=admin DB_PORT=5432 -JWT_SECRET_KEY=Change_ME!!! -JWT_EXPIRATION=2d \ No newline at end of file +DB_NAME=my-db \ No newline at end of file diff --git a/admin-ui/src/api/user/User.ts b/admin-ui/src/api/user/User.ts index 4e86caf..ab01be9 100644 --- a/admin-ui/src/api/user/User.ts +++ b/admin-ui/src/api/user/User.ts @@ -8,4 +8,6 @@ export type User = { lastName: string | null; username: string; roles: JsonValue; + age: string | null; + course: string | null; }; diff --git a/admin-ui/src/api/user/UserCreateInput.ts b/admin-ui/src/api/user/UserCreateInput.ts index cd7fa5a..0eae04c 100644 --- a/admin-ui/src/api/user/UserCreateInput.ts +++ b/admin-ui/src/api/user/UserCreateInput.ts @@ -6,4 +6,6 @@ export type UserCreateInput = { username: string; password: string; roles: InputJsonValue; + age?: string | null; + course?: string | null; }; diff --git a/admin-ui/src/api/user/UserOrderByInput.ts b/admin-ui/src/api/user/UserOrderByInput.ts index cde82ed..1e3bae5 100644 --- a/admin-ui/src/api/user/UserOrderByInput.ts +++ b/admin-ui/src/api/user/UserOrderByInput.ts @@ -9,4 +9,6 @@ export type UserOrderByInput = { username?: SortOrder; password?: SortOrder; roles?: SortOrder; + age?: SortOrder; + course?: SortOrder; }; diff --git a/admin-ui/src/api/user/UserUpdateInput.ts b/admin-ui/src/api/user/UserUpdateInput.ts index e4fc533..4039fce 100644 --- a/admin-ui/src/api/user/UserUpdateInput.ts +++ b/admin-ui/src/api/user/UserUpdateInput.ts @@ -6,4 +6,6 @@ export type UserUpdateInput = { username?: string; password?: string; roles?: InputJsonValue; + age?: string | null; + course?: string | null; }; diff --git a/admin-ui/src/api/user/UserWhereInput.ts b/admin-ui/src/api/user/UserWhereInput.ts index fcd81c7..3fa62a2 100644 --- a/admin-ui/src/api/user/UserWhereInput.ts +++ b/admin-ui/src/api/user/UserWhereInput.ts @@ -6,4 +6,6 @@ export type UserWhereInput = { firstName?: StringNullableFilter; lastName?: StringNullableFilter; username?: StringFilter; + age?: StringNullableFilter; + course?: StringNullableFilter; }; diff --git a/admin-ui/src/user/UserCreate.tsx b/admin-ui/src/user/UserCreate.tsx index dfda515..2cbc64a 100644 --- a/admin-ui/src/user/UserCreate.tsx +++ b/admin-ui/src/user/UserCreate.tsx @@ -25,6 +25,8 @@ export const UserCreate = (props: CreateProps): React.ReactElement => { optionText="label" optionValue="value" /> + + ); diff --git a/admin-ui/src/user/UserEdit.tsx b/admin-ui/src/user/UserEdit.tsx index 57aa95e..30877d5 100644 --- a/admin-ui/src/user/UserEdit.tsx +++ b/admin-ui/src/user/UserEdit.tsx @@ -23,6 +23,8 @@ export const UserEdit = (props: EditProps): React.ReactElement => { optionText="label" optionValue="value" /> + + ); diff --git a/admin-ui/src/user/UserList.tsx b/admin-ui/src/user/UserList.tsx index 87afc5e..d1a5ce0 100644 --- a/admin-ui/src/user/UserList.tsx +++ b/admin-ui/src/user/UserList.tsx @@ -19,6 +19,8 @@ export const UserList = (props: ListProps): React.ReactElement => { + + ); diff --git a/admin-ui/src/user/UserShow.tsx b/admin-ui/src/user/UserShow.tsx index 5e9d39d..b8ee0b6 100644 --- a/admin-ui/src/user/UserShow.tsx +++ b/admin-ui/src/user/UserShow.tsx @@ -18,6 +18,8 @@ export const UserShow = (props: ShowProps): React.ReactElement => { + + ); diff --git a/server/package.json b/server/package.json index ad7b671..c784c1f 100644 --- a/server/package.json +++ b/server/package.json @@ -39,12 +39,7 @@ "npm-run-all": "4.1.5", "reflect-metadata": "0.1.13", "swagger-ui-express": "4.3.0", - "ts-node": "9.1.1", - "@nestjs/jwt": "^10.0.2", - "@nestjs/passport": "^9.0.0", - "passport": "0.6.0", - "passport-http": "0.3.0", - "passport-jwt": "4.0.1" + "ts-node": "9.1.1" }, "devDependencies": { "@nestjs/cli": "8.2.5", @@ -61,9 +56,7 @@ "supertest": "4.0.2", "ts-jest": "27.0.3", "type-fest": "0.11.0", - "typescript": "4.2.3", - "@types/passport-http": "0.3.9", - "@types/passport-jwt": "3.0.8" + "typescript": "4.2.3" }, "jest": { "preset": "ts-jest", diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma index 81ef875..e64bf96 100644 --- a/server/prisma/schema.prisma +++ b/server/prisma/schema.prisma @@ -16,4 +16,6 @@ model User { username String @unique password String roles Json + age String? + course String? } diff --git a/server/scripts/seed.ts b/server/scripts/seed.ts index 272dddd..04cee65 100644 --- a/server/scripts/seed.ts +++ b/server/scripts/seed.ts @@ -1,8 +1,6 @@ import * as dotenv from "dotenv"; import { PrismaClient } from "@prisma/client"; import { customSeed } from "./customSeed"; -import { Salt, parseSalt } from "../src/auth/password.service"; -import { hash } from "bcrypt"; if (require.main === module) { dotenv.config(); @@ -12,34 +10,12 @@ if (require.main === module) { if (!BCRYPT_SALT) { throw new Error("BCRYPT_SALT environment variable must be defined"); } - const salt = parseSalt(BCRYPT_SALT); - - seed(salt).catch((error) => { - console.error(error); - process.exit(1); - }); } -async function seed(bcryptSalt: Salt) { +async function seed() { console.info("Seeding database..."); const client = new PrismaClient(); - - const data = { - username: "admin", - password: await hash("admin", bcryptSalt), - roles: ["user"], - }; - - await client.user.upsert({ - where: { - username: data.username, - }, - - update: {}, - create: data, - }); - void client.$disconnect(); console.info("Seeding database with custom seed..."); diff --git a/server/src/app.module.ts b/server/src/app.module.ts index d6433fb..297cc89 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -10,14 +10,9 @@ import { ServeStaticModule } from "@nestjs/serve-static"; import { ServeStaticOptionsService } from "./serveStaticOptions.service"; import { GraphQLModule } from "@nestjs/graphql"; -import { ACLModule } from "./auth/acl.module"; -import { AuthModule } from "./auth/auth.module"; - @Module({ controllers: [], imports: [ - ACLModule, - AuthModule, UserModule, HealthModule, PrismaModule, diff --git a/server/src/swagger.ts b/server/src/swagger.ts index eb21a8e..86ba502 100644 --- a/server/src/swagger.ts +++ b/server/src/swagger.ts @@ -7,7 +7,7 @@ export const swaggerDocumentOptions = new DocumentBuilder() .setDescription( '\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)' ) - .setVersion("1104a18s") + .setVersion("6uk4779j") .addBearerAuth() .build(); diff --git a/server/src/user/base/User.ts b/server/src/user/base/User.ts index e4f12cd..dd25cb5 100644 --- a/server/src/user/base/User.ts +++ b/server/src/user/base/User.ts @@ -78,6 +78,28 @@ class User { @IsJSON() @Field(() => GraphQLJSON) roles!: JsonValue; + + @ApiProperty({ + required: false, + type: String, + }) + @IsString() + @IsOptional() + @Field(() => String, { + nullable: true, + }) + age!: string | null; + + @ApiProperty({ + required: false, + type: String, + }) + @IsString() + @IsOptional() + @Field(() => String, { + nullable: true, + }) + course!: string | null; } export { User as User }; diff --git a/server/src/user/base/UserCreateInput.ts b/server/src/user/base/UserCreateInput.ts index 398f9b4..6964572 100644 --- a/server/src/user/base/UserCreateInput.ts +++ b/server/src/user/base/UserCreateInput.ts @@ -61,6 +61,28 @@ class UserCreateInput { @IsJSON() @Field(() => GraphQLJSON) roles!: InputJsonValue; + + @ApiProperty({ + required: false, + type: String, + }) + @IsString() + @IsOptional() + @Field(() => String, { + nullable: true, + }) + age?: string | null; + + @ApiProperty({ + required: false, + type: String, + }) + @IsString() + @IsOptional() + @Field(() => String, { + nullable: true, + }) + course?: string | null; } export { UserCreateInput as UserCreateInput }; diff --git a/server/src/user/base/UserOrderByInput.ts b/server/src/user/base/UserOrderByInput.ts index a76564c..b9068ec 100644 --- a/server/src/user/base/UserOrderByInput.ts +++ b/server/src/user/base/UserOrderByInput.ts @@ -89,6 +89,24 @@ class UserOrderByInput { nullable: true, }) roles?: SortOrder; + + @ApiProperty({ + required: false, + enum: ["asc", "desc"], + }) + @Field(() => SortOrder, { + nullable: true, + }) + age?: SortOrder; + + @ApiProperty({ + required: false, + enum: ["asc", "desc"], + }) + @Field(() => SortOrder, { + nullable: true, + }) + course?: SortOrder; } export { UserOrderByInput as UserOrderByInput }; diff --git a/server/src/user/base/UserUpdateInput.ts b/server/src/user/base/UserUpdateInput.ts index c0bd636..62291e3 100644 --- a/server/src/user/base/UserUpdateInput.ts +++ b/server/src/user/base/UserUpdateInput.ts @@ -70,6 +70,28 @@ class UserUpdateInput { nullable: true, }) roles?: InputJsonValue; + + @ApiProperty({ + required: false, + type: String, + }) + @IsString() + @IsOptional() + @Field(() => String, { + nullable: true, + }) + age?: string | null; + + @ApiProperty({ + required: false, + type: String, + }) + @IsString() + @IsOptional() + @Field(() => String, { + nullable: true, + }) + course?: string | null; } export { UserUpdateInput as UserUpdateInput }; diff --git a/server/src/user/base/UserWhereInput.ts b/server/src/user/base/UserWhereInput.ts index 00bc16b..3ed9ac8 100644 --- a/server/src/user/base/UserWhereInput.ts +++ b/server/src/user/base/UserWhereInput.ts @@ -61,6 +61,28 @@ class UserWhereInput { nullable: true, }) username?: StringFilter; + + @ApiProperty({ + required: false, + type: StringNullableFilter, + }) + @Type(() => StringNullableFilter) + @IsOptional() + @Field(() => StringNullableFilter, { + nullable: true, + }) + age?: StringNullableFilter; + + @ApiProperty({ + required: false, + type: StringNullableFilter, + }) + @Type(() => StringNullableFilter) + @IsOptional() + @Field(() => StringNullableFilter, { + nullable: true, + }) + course?: StringNullableFilter; } export { UserWhereInput as UserWhereInput }; diff --git a/server/src/user/base/user.controller.base.spec.ts b/server/src/user/base/user.controller.base.spec.ts index f3def16..49e801d 100644 --- a/server/src/user/base/user.controller.base.spec.ts +++ b/server/src/user/base/user.controller.base.spec.ts @@ -26,6 +26,8 @@ const CREATE_INPUT = { lastName: "exampleLastName", username: "exampleUsername", password: "examplePassword", + age: "exampleAge", + course: "exampleCourse", }; const CREATE_RESULT = { id: "exampleId", @@ -35,6 +37,8 @@ const CREATE_RESULT = { lastName: "exampleLastName", username: "exampleUsername", password: "examplePassword", + age: "exampleAge", + course: "exampleCourse", }; const FIND_MANY_RESULT = [ { @@ -45,6 +49,8 @@ const FIND_MANY_RESULT = [ lastName: "exampleLastName", username: "exampleUsername", password: "examplePassword", + age: "exampleAge", + course: "exampleCourse", }, ]; const FIND_ONE_RESULT = { @@ -55,6 +61,8 @@ const FIND_ONE_RESULT = { lastName: "exampleLastName", username: "exampleUsername", password: "examplePassword", + age: "exampleAge", + course: "exampleCourse", }; const service = { diff --git a/server/src/user/base/user.controller.base.ts b/server/src/user/base/user.controller.base.ts index 02d3c7f..0a823c5 100644 --- a/server/src/user/base/user.controller.base.ts +++ b/server/src/user/base/user.controller.base.ts @@ -16,11 +16,7 @@ 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 { UserWhereInput } from "./UserWhereInput"; import { UserWhereUniqueInput } from "./UserWhereUniqueInput"; @@ -28,24 +24,10 @@ import { UserFindManyArgs } from "./UserFindManyArgs"; import { UserUpdateInput } from "./UserUpdateInput"; import { User } from "./User"; -@swagger.ApiBearerAuth() -@common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard) export class UserControllerBase { - constructor( - protected readonly service: UserService, - protected readonly rolesBuilder: nestAccessControl.RolesBuilder - ) {} - @common.UseInterceptors(AclValidateRequestInterceptor) + constructor(protected readonly service: UserService) {} @common.Post() @swagger.ApiCreatedResponse({ type: User }) - @nestAccessControl.UseRoles({ - resource: "User", - action: "create", - possession: "any", - }) - @swagger.ApiForbiddenResponse({ - type: errors.ForbiddenException, - }) async create(@common.Body() data: UserCreateInput): Promise { return await this.service.create({ data: data, @@ -57,22 +39,15 @@ export class UserControllerBase { lastName: true, username: true, roles: true, + age: true, + course: 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 findMany(@common.Req() request: Request): Promise { const args = plainToClass(UserFindManyArgs, request.query); return this.service.findMany({ @@ -85,22 +60,15 @@ export class UserControllerBase { lastName: true, username: true, roles: true, + age: true, + course: 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 findOne( @common.Param() params: UserWhereUniqueInput ): Promise { @@ -114,6 +82,8 @@ export class UserControllerBase { lastName: true, username: true, roles: true, + age: true, + course: true, }, }); if (result === null) { @@ -124,18 +94,9 @@ export class UserControllerBase { 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 update( @common.Param() params: UserWhereUniqueInput, @common.Body() data: UserUpdateInput @@ -152,6 +113,8 @@ export class UserControllerBase { lastName: true, username: true, roles: true, + age: true, + course: true, }, }); } catch (error) { @@ -167,14 +130,6 @@ export class UserControllerBase { @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 delete( @common.Param() params: UserWhereUniqueInput ): Promise { @@ -189,6 +144,8 @@ export class UserControllerBase { lastName: true, username: true, roles: true, + age: true, + course: true, }, }); } catch (error) { diff --git a/server/src/user/base/user.module.base.ts b/server/src/user/base/user.module.base.ts index 76d29fe..2ec6897 100644 --- a/server/src/user/base/user.module.base.ts +++ b/server/src/user/base/user.module.base.ts @@ -9,12 +9,11 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ -import { Module, forwardRef } from "@nestjs/common"; +import { Module } from "@nestjs/common"; import { MorganModule } from "nest-morgan"; -import { ACLModule } from "../../auth/acl.module"; -import { AuthModule } from "../../auth/auth.module"; + @Module({ - imports: [ACLModule, forwardRef(() => AuthModule), MorganModule], - exports: [ACLModule, AuthModule, MorganModule], + imports: [MorganModule], + exports: [MorganModule], }) export class UserModuleBase {} diff --git a/server/src/user/base/user.resolver.base.ts b/server/src/user/base/user.resolver.base.ts index 614a584..c873d21 100644 --- a/server/src/user/base/user.resolver.base.ts +++ b/server/src/user/base/user.resolver.base.ts @@ -13,12 +13,6 @@ import * as graphql from "@nestjs/graphql"; import * as apollo from "apollo-server-express"; import { isRecordNotFoundError } from "../../prisma.util"; import { MetaQueryPayload } from "../../util/MetaQueryPayload"; -import * as nestAccessControl from "nest-access-control"; -import * as gqlACGuard from "../../auth/gqlAC.guard"; -import { GqlDefaultAuthGuard } from "../../auth/gqlDefaultAuth.guard"; -import * as common from "@nestjs/common"; -import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; -import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; import { CreateUserArgs } from "./CreateUserArgs"; import { UpdateUserArgs } from "./UpdateUserArgs"; import { DeleteUserArgs } from "./DeleteUserArgs"; @@ -26,20 +20,10 @@ import { UserFindManyArgs } from "./UserFindManyArgs"; import { UserFindUniqueArgs } from "./UserFindUniqueArgs"; import { User } from "./User"; import { UserService } from "../user.service"; -@common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard) @graphql.Resolver(() => User) export class UserResolverBase { - constructor( - protected readonly service: UserService, - protected readonly rolesBuilder: nestAccessControl.RolesBuilder - ) {} + constructor(protected readonly service: UserService) {} - @graphql.Query(() => MetaQueryPayload) - @nestAccessControl.UseRoles({ - resource: "User", - action: "read", - possession: "any", - }) async _usersMeta( @graphql.Args() args: UserFindManyArgs ): Promise { @@ -53,24 +37,12 @@ export class UserResolverBase { }; } - @common.UseInterceptors(AclFilterResponseInterceptor) @graphql.Query(() => [User]) - @nestAccessControl.UseRoles({ - resource: "User", - action: "read", - possession: "any", - }) async users(@graphql.Args() args: UserFindManyArgs): Promise { return this.service.findMany(args); } - @common.UseInterceptors(AclFilterResponseInterceptor) @graphql.Query(() => User, { nullable: true }) - @nestAccessControl.UseRoles({ - resource: "User", - action: "read", - possession: "own", - }) async user(@graphql.Args() args: UserFindUniqueArgs): Promise { const result = await this.service.findOne(args); if (result === null) { @@ -79,13 +51,7 @@ export class UserResolverBase { return result; } - @common.UseInterceptors(AclValidateRequestInterceptor) @graphql.Mutation(() => User) - @nestAccessControl.UseRoles({ - resource: "User", - action: "create", - possession: "any", - }) async createUser(@graphql.Args() args: CreateUserArgs): Promise { return await this.service.create({ ...args, @@ -93,13 +59,7 @@ export class UserResolverBase { }); } - @common.UseInterceptors(AclValidateRequestInterceptor) @graphql.Mutation(() => User) - @nestAccessControl.UseRoles({ - resource: "User", - action: "update", - possession: "any", - }) async updateUser(@graphql.Args() args: UpdateUserArgs): Promise { try { return await this.service.update({ @@ -117,11 +77,6 @@ export class UserResolverBase { } @graphql.Mutation(() => User) - @nestAccessControl.UseRoles({ - resource: "User", - action: "delete", - possession: "any", - }) async deleteUser(@graphql.Args() args: DeleteUserArgs): Promise { try { return await this.service.delete(args); diff --git a/server/src/user/base/user.service.base.ts b/server/src/user/base/user.service.base.ts index 89d81db..340d7b1 100644 --- a/server/src/user/base/user.service.base.ts +++ b/server/src/user/base/user.service.base.ts @@ -11,14 +11,9 @@ https://docs.amplication.com/how-to/custom-code */ import { PrismaService } from "../../prisma/prisma.service"; import { Prisma, User } from "@prisma/client"; -import { PasswordService } from "../../auth/password.service"; -import { transformStringFieldUpdateInput } from "../../prisma.util"; export class UserServiceBase { - constructor( - protected readonly prisma: PrismaService, - protected readonly passwordService: PasswordService - ) {} + constructor(protected readonly prisma: PrismaService) {} async count( args: Prisma.SelectSubset @@ -39,32 +34,12 @@ export class UserServiceBase { async create( args: Prisma.SelectSubset ): Promise { - return this.prisma.user.create({ - ...args, - - data: { - ...args.data, - password: await this.passwordService.hash(args.data.password), - }, - }); + return this.prisma.user.create(args); } async update( args: Prisma.SelectSubset ): Promise { - return this.prisma.user.update({ - ...args, - - data: { - ...args.data, - - password: - args.data.password && - (await transformStringFieldUpdateInput( - args.data.password, - (password) => this.passwordService.hash(password) - )), - }, - }); + return this.prisma.user.update(args); } async delete( args: Prisma.SelectSubset