diff --git a/1731785254977-migration.ts b/1731785254977-migration.ts new file mode 100644 index 0000000..c3bd147 --- /dev/null +++ b/1731785254977-migration.ts @@ -0,0 +1,24 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Migration1731785254977 implements MigrationInterface { + name = 'Migration1731785254977' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "comment" ("id" SERIAL NOT NULL, "body" character varying NOT NULL, "user_id" integer, "article_id" integer, CONSTRAINT "PK_0b0e4bbc8415ec426f87f3a88e2" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE TABLE "Articals" ("id" SERIAL NOT NULL, "title" character varying NOT NULL, "body" character varying NOT NULL, "user_id" integer, CONSTRAINT "PK_2c83ee8415072028f1a07e00d48" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE TABLE "users" ("id" SERIAL NOT NULL, "userName" character varying NOT NULL, "firstName" character varying NOT NULL, "lastName" character varying NOT NULL, "email" character varying NOT NULL, "password" character varying NOT NULL, CONSTRAINT "PK_a3ffb1c0c8416b9fc6f907b7433" PRIMARY KEY ("id"))`); + await queryRunner.query(`ALTER TABLE "comment" ADD CONSTRAINT "FK_bbfe153fa60aa06483ed35ff4a7" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "comment" ADD CONSTRAINT "FK_03a590c26b0910b0bb49682b1e3" FOREIGN KEY ("article_id") REFERENCES "Articals"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "Articals" ADD CONSTRAINT "FK_81607d9b135a801e10681c73217" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "Articals" DROP CONSTRAINT "FK_81607d9b135a801e10681c73217"`); + await queryRunner.query(`ALTER TABLE "comment" DROP CONSTRAINT "FK_03a590c26b0910b0bb49682b1e3"`); + await queryRunner.query(`ALTER TABLE "comment" DROP CONSTRAINT "FK_bbfe153fa60aa06483ed35ff4a7"`); + await queryRunner.query(`DROP TABLE "users"`); + await queryRunner.query(`DROP TABLE "Articals"`); + await queryRunner.query(`DROP TABLE "comment"`); + } + +} diff --git a/migration/1731437432808-migration.ts b/migration/1731437432808-migration.ts deleted file mode 100644 index 42745d6..0000000 --- a/migration/1731437432808-migration.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class Migration1731437432808 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise {} - - public async down(queryRunner: QueryRunner): Promise {} -} diff --git a/migration/t.txt b/migration/t.txt new file mode 100644 index 0000000..e69de29 diff --git a/package.json b/package.json index 446280f..d965958 100644 --- a/package.json +++ b/package.json @@ -16,10 +16,11 @@ "test:cov": "jest --coverage", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:e2e": "jest --config ./test/jest-e2e.json", - "typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli", - "migration:generate": "ts-node ./node_modules/typeorm/cli migration:generate -d ormconfig.ts -n", - "migration:run": "ts-node ./node_modules/typeorm/cli migration:run -d src/ormconfig.ts", - "migration:revert": "ts-node ./node_modules/typeorm/cli migration:revert -d src/ormconfig.ts", + "typeorm": "typeorm-ts-node-commonjs", + "migration:create": "npm run typeorm migration:create ./migration/initial", + "migration:generate": "npm run typeorm -- migration:generate -d src/ormconfig.ts migration/", + "migration:run": "npm run typeorm -- migration:run -d src/ormconfig.ts", + "migration:revert": "npm run typeorm -- migration:revert -d src/ormconfig.ts", "start:dev": "NODE_ENV=development nest start --watch", "start:prod": "NODE_ENV=production node dist/main" }, diff --git a/src/app.module.ts b/src/app.module.ts index b044980..8444a85 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -6,7 +6,7 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { DataSource } from 'typeorm'; import { UserModule } from './user/user.module'; import { AuthModule } from './auth/auth.module'; -import { env } from 'process'; +// import { env } from 'process'; import { CommentModule } from './comment/comment.module'; @Module({ @@ -14,14 +14,14 @@ import { CommentModule } from './comment/comment.module'; ArticalModule, TypeOrmModule.forRoot({ type: 'postgres', - host: env.HOST, - port: env.APP_PORT, - username: env.USERNAME, - password: env.PASSWORD, - database: env.DATABASE, + host: 'localhost', + port: 5432, + username: 'abdo', + password: 'abdo123', + database: 'test_db', autoLoadEntities: true, entities: [__dirname + '/**/*.entity{.ts,.js}'], - synchronize: true, + synchronize: false, logging: false, }), UserModule, diff --git a/src/articale/entities/artical.entity.ts b/src/articale/entities/artical.entity.ts index 942544b..0d69903 100644 --- a/src/articale/entities/artical.entity.ts +++ b/src/articale/entities/artical.entity.ts @@ -6,8 +6,9 @@ import { OneToMany, PrimaryGeneratedColumn, } from 'typeorm'; -import { User } from 'src/user/entities/user.entity'; -import { Comment } from 'src/comment/entities/comment.entity'; +import { User } from '../../user/entities/user.entity'; +import { Comment } from '../../comment/entities/comment.entity'; + @Entity('Articals') export class Artical { @PrimaryGeneratedColumn() diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index 9ef5cf3..d416dbd 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -1,14 +1,18 @@ -import { forwardRef, Module } from '@nestjs/common'; +import { Module } from '@nestjs/common'; import { AuthService } from './auth.service'; import { LocalStrategy } from './strategy/local.strategy'; import { JwtStrategy } from './strategy/jwt.strategy'; import { JwtModule } from '@nestjs/jwt'; import { ConfigModule, ConfigService } from '@nestjs/config'; -import { UserModule } from 'src/user/user.module'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { User } from 'src/user/entities/user.entity'; @Module({ imports: [ - forwardRef(() => UserModule), + ConfigModule.forRoot({ + isGlobal: true, + }), + TypeOrmModule.forFeature([User]), JwtModule.registerAsync({ imports: [ConfigModule], useFactory: async (configService: ConfigService) => ({ @@ -25,6 +29,6 @@ import { UserModule } from 'src/user/user.module'; }), ], providers: [AuthService, LocalStrategy, JwtStrategy], - exports: [AuthService, JwtModule, LocalStrategy, JwtStrategy, AuthModule], + exports: [AuthService], }) export class AuthModule {} diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 01c1ea0..7b2514a 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -2,24 +2,26 @@ import { BadRequestException, Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import * as bcrypt from 'bcrypt'; import { User } from 'src/user/entities/user.entity'; -import { UserService } from 'src/user/user.service'; -import { AccessToken } from './types/AccessToken.js'; -import { RegisterRequestDto } from './dto/Register-Request.dto copy.js'; +import { AccessToken } from './types/AccessToken'; +import { RegisterRequestDto } from './dto/Register-Request.dto copy'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; @Injectable() export class AuthService { constructor( - private readonly userService: UserService, + @InjectRepository(User) + private userRepository: Repository, private jwtService: JwtService, ) {} //used for registred user when thier wnat to login in existing account in the database async validateUser(email: string, password: string): Promise { - const user: User = await this.userService.getUserByEmail(email); + const user = await this.userRepository.findOne({ where: { email } }); if (!user) { throw new BadRequestException('The password or email isn`t right'); } - const isMatch: boolean = bcrypt.compareSync(password, user.password); + const isMatch = await bcrypt.compare(password, user.password); if (!isMatch) { throw new BadRequestException('The password or email not right'); } @@ -34,13 +36,18 @@ export class AuthService { // used in sign in (new account in userService) but befor registration it hashing the account's password, to be saved then in the database async register(user: RegisterRequestDto): Promise { - const existingUser = await this.userService.getUserByEmail(user.email); + const existingUser = await this.userRepository.findOne({ + where: { email: user.email }, + }); if (existingUser) { throw new BadRequestException('the email is already used'); } const hashedPassword = await bcrypt.hash(user.password, 10); - const newUser = { ...user, password: hashedPassword }; - await this.userService.addNewAcc(newUser); + const newUser = this.userRepository.create({ + ...user, + password: hashedPassword, + }); + await this.userRepository.save(newUser); return this.login(newUser); } } diff --git a/src/comment/comment.module.ts b/src/comment/comment.module.ts index 569ce06..7e4ce8e 100644 --- a/src/comment/comment.module.ts +++ b/src/comment/comment.module.ts @@ -4,6 +4,7 @@ import { CommentController } from './comment.controller'; import { TypeOrmModule } from '@nestjs/typeorm'; import { UserModule } from 'src/user/user.module'; import { ArticalModule } from 'src/articale/artical.module'; +import { Comment } from './entities/comment.entity'; @Module({ imports: [TypeOrmModule.forFeature([Comment]), UserModule, ArticalModule], diff --git a/src/comment/comment.service.ts b/src/comment/comment.service.ts index 6087912..b20e81b 100644 --- a/src/comment/comment.service.ts +++ b/src/comment/comment.service.ts @@ -9,6 +9,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { User } from 'src/user/entities/user.entity'; import { Artical } from 'src/articale/entities/artical.entity'; +import { Comment } from './entities/comment.entity'; @Injectable() export class CommentService { @@ -50,7 +51,7 @@ export class CommentService { article: article, }); - return this.commentRepo.save(newComment); + return await this.commentRepo.save(newComment); } async findOne(id: number) { diff --git a/src/comment/entities/comment.entity.ts b/src/comment/entities/comment.entity.ts index eb6496f..5bfe8a1 100644 --- a/src/comment/entities/comment.entity.ts +++ b/src/comment/entities/comment.entity.ts @@ -1,7 +1,14 @@ -import { User } from 'src/user/entities/user.entity'; -import { Artical } from 'src/articale/entities/artical.entity'; -import { Column, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; +import { User } from '../../user/entities/user.entity'; +import { Artical } from '../../articale/entities/artical.entity'; +import { + Column, + JoinColumn, + ManyToOne, + PrimaryGeneratedColumn, + Entity, +} from 'typeorm'; +@Entity() export class Comment { @PrimaryGeneratedColumn() id: number; diff --git a/src/ormconfig.ts b/src/ormconfig.ts index c17349a..b44a1ea 100644 --- a/src/ormconfig.ts +++ b/src/ormconfig.ts @@ -1,21 +1,23 @@ import { DataSource, DataSourceOptions } from 'typeorm'; +import { User } from './user/entities/user.entity'; +import { Artical } from './articale/entities/artical.entity'; +import { Comment } from './comment/entities/comment.entity'; import * as dotenv from 'dotenv'; + dotenv.config(); export const dataSourceOptions: DataSourceOptions = { type: 'postgres', host: 'localhost', port: 5432, - username: 'postgres', - password: '', - database: 'Blog-db', - entities: [__dirname + 'src/**/*.entity{.ts,.js}'], - synchronize: false, // todo: not safe for production and we should use migrations instead - subscribers: [__dirname + '/domain/subscribers/*.subscriber{.ts,.js}'], - migrations: [__dirname + '/migrations/*{.ts,.js}'], + username: 'abdo', + password: 'abdo123', + database: 'test_db', + entities: [User, Artical, Comment], + migrations: ['./migration/*.ts'], + migrationsTableName: 'migrations', + synchronize: false, }; const dataSource = new DataSource(dataSourceOptions); -dataSource.initialize(); - export default dataSource; diff --git a/src/user/entities/user.entity.ts b/src/user/entities/user.entity.ts index 9306d5a..846555c 100644 --- a/src/user/entities/user.entity.ts +++ b/src/user/entities/user.entity.ts @@ -1,7 +1,7 @@ import { IsEmail, Max, Min } from 'class-validator'; -import { Artical } from 'src/articale/entities/artical.entity'; import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm'; -import { Comment } from 'src/comment/entities/comment.entity'; +import { Artical } from '../../articale/entities/artical.entity'; +import { Comment } from '../../comment/entities/comment.entity'; @Entity('users') export class User { @PrimaryGeneratedColumn()