From 9551ae0703e0f738f51d4659ba00f7bc7e46702d Mon Sep 17 00:00:00 2001 From: Igor Propisnov Date: Fri, 24 May 2024 20:42:46 +0200 Subject: [PATCH 1/4] added user data to db --- backend/src/entities/index.ts | 1 + backend/src/entities/user-data.entity.ts | 22 +++++++++++++++++++ .../src/modules/auth-module/auth.module.ts | 6 +++-- .../repositories/user-data.repository.ts | 21 ++++++++++++++++++ .../auth-module/services/auth.service.ts | 4 ++++ .../database-module/database-config.ts | 4 ++-- 6 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 backend/src/entities/user-data.entity.ts create mode 100644 backend/src/modules/auth-module/repositories/user-data.repository.ts diff --git a/backend/src/entities/index.ts b/backend/src/entities/index.ts index 2c05a4a..6bca565 100644 --- a/backend/src/entities/index.ts +++ b/backend/src/entities/index.ts @@ -1 +1,2 @@ export * from './user-credentials.entity'; +export * from './user-data.entity'; diff --git a/backend/src/entities/user-data.entity.ts b/backend/src/entities/user-data.entity.ts new file mode 100644 index 0000000..8511179 --- /dev/null +++ b/backend/src/entities/user-data.entity.ts @@ -0,0 +1,22 @@ +import { + Column, + Entity, + PrimaryGeneratedColumn, + OneToOne, + JoinColumn, +} from 'typeorm'; + +import { UserCredentials } from './user-credentials.entity'; + +@Entity() +export class UserData { + @PrimaryGeneratedColumn('uuid') + public id: number; + + @Column({ default: false }) + public isEmailConfirmed: boolean; + + @OneToOne(() => UserCredentials) + @JoinColumn() + public user: UserCredentials; +} diff --git a/backend/src/modules/auth-module/auth.module.ts b/backend/src/modules/auth-module/auth.module.ts index ed6168d..efc84be 100644 --- a/backend/src/modules/auth-module/auth.module.ts +++ b/backend/src/modules/auth-module/auth.module.ts @@ -1,9 +1,10 @@ import { Module } from '@nestjs/common'; import { JwtModule } from '@nestjs/jwt'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { UserCredentials } from 'src/entities/user-credentials.entity'; +import { UserData, UserCredentials } from 'src/entities'; import { AuthController } from './controller/auth.controller'; +import { UserDataRepository } from './repositories/user-data.repository'; import { UserRepository } from './repositories/user.repository'; import { AuthService } from './services/auth.service'; import { EncryptionService } from './services/encryption.service'; @@ -13,13 +14,14 @@ import { AccessTokenStrategy, RefreshTokenStrategy } from './strategies'; @Module({ imports: [ JwtModule.register({}), - TypeOrmModule.forFeature([UserCredentials]), + TypeOrmModule.forFeature([UserCredentials, UserData]), ], providers: [ AuthService, TokenManagementService, EncryptionService, UserRepository, + UserDataRepository, AccessTokenStrategy, RefreshTokenStrategy, ], diff --git a/backend/src/modules/auth-module/repositories/user-data.repository.ts b/backend/src/modules/auth-module/repositories/user-data.repository.ts new file mode 100644 index 0000000..85c593c --- /dev/null +++ b/backend/src/modules/auth-module/repositories/user-data.repository.ts @@ -0,0 +1,21 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { UserData } from 'src/entities'; +import { Repository } from 'typeorm'; + +@Injectable() +export class UserDataRepository { + public constructor( + @InjectRepository(UserData) + private readonly repository: Repository + ) {} + + public async createInitialUserData(userid: number): Promise { + const userData = new UserData(); + + userData.id = userid; + userData.isEmailConfirmed = false; + + return this.repository.save(userData); + } +} diff --git a/backend/src/modules/auth-module/services/auth.service.ts b/backend/src/modules/auth-module/services/auth.service.ts index 6d2d498..1859820 100644 --- a/backend/src/modules/auth-module/services/auth.service.ts +++ b/backend/src/modules/auth-module/services/auth.service.ts @@ -1,6 +1,7 @@ import { ForbiddenException, Injectable } from '@nestjs/common'; import { TokensDto, UserCredentialsDto } from '../models/dto'; +import { UserDataRepository } from '../repositories/user-data.repository'; import { UserRepository } from '../repositories/user.repository'; import { EncryptionService } from './encryption.service'; @@ -10,6 +11,7 @@ import { TokenManagementService } from './token-management.service'; export class AuthService { public constructor( private readonly userRepository: UserRepository, + private readonly UserDataRepository: UserDataRepository, private readonly tokenManagementService: TokenManagementService, private readonly encryptionService: EncryptionService ) {} @@ -23,6 +25,8 @@ export class AuthService { passwordHashed ); + await this.UserDataRepository.createInitialUserData(user.id); + return this.generateAndPersistTokens(user.id, user.email); } diff --git a/backend/src/modules/database-module/database-config.ts b/backend/src/modules/database-module/database-config.ts index b674b2f..e355798 100644 --- a/backend/src/modules/database-module/database-config.ts +++ b/backend/src/modules/database-module/database-config.ts @@ -1,6 +1,6 @@ import { ConfigService } from '@nestjs/config'; import { TypeOrmModuleOptions } from '@nestjs/typeorm'; -import { UserCredentials } from 'src/entities'; +import { UserCredentials, UserData } from 'src/entities'; export const databaseConfigFactory = ( configService: ConfigService @@ -13,5 +13,5 @@ export const databaseConfigFactory = ( database: configService.get('DB_NAME'), synchronize: true, logging: true, - entities: [UserCredentials], + entities: [UserCredentials, UserData], }); From 2359518ed540be281e6984eae9c15a85ce003511 Mon Sep 17 00:00:00 2001 From: Igor Propisnov Date: Fri, 24 May 2024 20:43:53 +0200 Subject: [PATCH 2/4] added properties to user data --- backend/src/entities/user-data.entity.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backend/src/entities/user-data.entity.ts b/backend/src/entities/user-data.entity.ts index 8511179..9bc93f4 100644 --- a/backend/src/entities/user-data.entity.ts +++ b/backend/src/entities/user-data.entity.ts @@ -4,6 +4,8 @@ import { PrimaryGeneratedColumn, OneToOne, JoinColumn, + CreateDateColumn, + UpdateDateColumn, } from 'typeorm'; import { UserCredentials } from './user-credentials.entity'; @@ -19,4 +21,10 @@ export class UserData { @OneToOne(() => UserCredentials) @JoinColumn() public user: UserCredentials; + + @CreateDateColumn() + public createdAt: Date; + + @UpdateDateColumn() + public updatedAt: Date; } From eaa057de4b759dd8adeba9112780e9992b1392ee Mon Sep 17 00:00:00 2001 From: Igor Propisnov Date: Fri, 24 May 2024 20:46:03 +0200 Subject: [PATCH 3/4] rename repo --- backend/src/modules/auth-module/auth.module.ts | 4 ++-- .../{user.repository.ts => user-credentials.repository.ts} | 2 +- backend/src/modules/auth-module/services/auth.service.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename backend/src/modules/auth-module/repositories/{user.repository.ts => user-credentials.repository.ts} (96%) diff --git a/backend/src/modules/auth-module/auth.module.ts b/backend/src/modules/auth-module/auth.module.ts index efc84be..4c0bbe8 100644 --- a/backend/src/modules/auth-module/auth.module.ts +++ b/backend/src/modules/auth-module/auth.module.ts @@ -4,8 +4,8 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { UserData, UserCredentials } from 'src/entities'; import { AuthController } from './controller/auth.controller'; +import { UserCredentialsRepository } from './repositories/user-credentials.repository'; import { UserDataRepository } from './repositories/user-data.repository'; -import { UserRepository } from './repositories/user.repository'; import { AuthService } from './services/auth.service'; import { EncryptionService } from './services/encryption.service'; import { TokenManagementService } from './services/token-management.service'; @@ -20,7 +20,7 @@ import { AccessTokenStrategy, RefreshTokenStrategy } from './strategies'; AuthService, TokenManagementService, EncryptionService, - UserRepository, + UserCredentialsRepository, UserDataRepository, AccessTokenStrategy, RefreshTokenStrategy, diff --git a/backend/src/modules/auth-module/repositories/user.repository.ts b/backend/src/modules/auth-module/repositories/user-credentials.repository.ts similarity index 96% rename from backend/src/modules/auth-module/repositories/user.repository.ts rename to backend/src/modules/auth-module/repositories/user-credentials.repository.ts index 9145b73..0ecab36 100644 --- a/backend/src/modules/auth-module/repositories/user.repository.ts +++ b/backend/src/modules/auth-module/repositories/user-credentials.repository.ts @@ -4,7 +4,7 @@ import { UserCredentials } from 'src/entities/user-credentials.entity'; import { Repository } from 'typeorm'; @Injectable() -export class UserRepository { +export class UserCredentialsRepository { public constructor( @InjectRepository(UserCredentials) private readonly repository: Repository diff --git a/backend/src/modules/auth-module/services/auth.service.ts b/backend/src/modules/auth-module/services/auth.service.ts index 1859820..f3b4f59 100644 --- a/backend/src/modules/auth-module/services/auth.service.ts +++ b/backend/src/modules/auth-module/services/auth.service.ts @@ -1,8 +1,8 @@ import { ForbiddenException, Injectable } from '@nestjs/common'; import { TokensDto, UserCredentialsDto } from '../models/dto'; +import { UserCredentialsRepository } from '../repositories/user-credentials.repository'; import { UserDataRepository } from '../repositories/user-data.repository'; -import { UserRepository } from '../repositories/user.repository'; import { EncryptionService } from './encryption.service'; import { TokenManagementService } from './token-management.service'; @@ -10,7 +10,7 @@ import { TokenManagementService } from './token-management.service'; @Injectable() export class AuthService { public constructor( - private readonly userRepository: UserRepository, + private readonly userRepository: UserCredentialsRepository, private readonly UserDataRepository: UserDataRepository, private readonly tokenManagementService: TokenManagementService, private readonly encryptionService: EncryptionService From bff7531b06b9ed4165796e814b8e812f10b8f68c Mon Sep 17 00:00:00 2001 From: Igor Propisnov Date: Fri, 24 May 2024 21:33:48 +0200 Subject: [PATCH 4/4] create a user module and move code from auth to user module --- backend/src/app.module.ts | 2 ++ backend/src/entities/user-data.entity.ts | 4 ++-- .../src/modules/auth-module/auth.module.ts | 9 ++++---- .../auth-module/services/auth.service.ts | 21 +++++++++++-------- .../modules/user-module/repositories/index.ts | 1 + .../repositories/user-data.repository.ts | 8 ++++--- .../src/modules/user-module/user.module.ts | 13 ++++++++++++ 7 files changed, 40 insertions(+), 18 deletions(-) create mode 100644 backend/src/modules/user-module/repositories/index.ts rename backend/src/modules/{auth-module => user-module}/repositories/user-data.repository.ts (68%) create mode 100644 backend/src/modules/user-module/user.module.ts diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts index dc1871d..3f5d90a 100644 --- a/backend/src/app.module.ts +++ b/backend/src/app.module.ts @@ -10,6 +10,7 @@ import { SecurityHeadersMiddleware } from './middleware/security-middleware/secu import { AuthModule } from './modules/auth-module/auth.module'; import { AccessTokenGuard } from './modules/auth-module/common/guards'; import { DatabaseModule } from './modules/database-module/database.module'; +import { UserModule } from './modules/user-module/user.module'; @Module({ imports: [ @@ -18,6 +19,7 @@ import { DatabaseModule } from './modules/database-module/database.module'; }), DatabaseModule, AuthModule, + UserModule, ], controllers: [AppController], providers: [AppService, { provide: 'APP_GUARD', useClass: AccessTokenGuard }], diff --git a/backend/src/entities/user-data.entity.ts b/backend/src/entities/user-data.entity.ts index 9bc93f4..b0ab112 100644 --- a/backend/src/entities/user-data.entity.ts +++ b/backend/src/entities/user-data.entity.ts @@ -13,13 +13,13 @@ import { UserCredentials } from './user-credentials.entity'; @Entity() export class UserData { @PrimaryGeneratedColumn('uuid') - public id: number; + public id: string; @Column({ default: false }) public isEmailConfirmed: boolean; @OneToOne(() => UserCredentials) - @JoinColumn() + @JoinColumn({ name: 'userCredentialsId' }) public user: UserCredentials; @CreateDateColumn() diff --git a/backend/src/modules/auth-module/auth.module.ts b/backend/src/modules/auth-module/auth.module.ts index 4c0bbe8..dab6e0f 100644 --- a/backend/src/modules/auth-module/auth.module.ts +++ b/backend/src/modules/auth-module/auth.module.ts @@ -1,11 +1,12 @@ import { Module } from '@nestjs/common'; import { JwtModule } from '@nestjs/jwt'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { UserData, UserCredentials } from 'src/entities'; +import { UserCredentials } from 'src/entities'; + +import { UserModule } from '../user-module/user.module'; import { AuthController } from './controller/auth.controller'; import { UserCredentialsRepository } from './repositories/user-credentials.repository'; -import { UserDataRepository } from './repositories/user-data.repository'; import { AuthService } from './services/auth.service'; import { EncryptionService } from './services/encryption.service'; import { TokenManagementService } from './services/token-management.service'; @@ -13,15 +14,15 @@ import { AccessTokenStrategy, RefreshTokenStrategy } from './strategies'; @Module({ imports: [ + UserModule, JwtModule.register({}), - TypeOrmModule.forFeature([UserCredentials, UserData]), + TypeOrmModule.forFeature([UserCredentials]), ], providers: [ AuthService, TokenManagementService, EncryptionService, UserCredentialsRepository, - UserDataRepository, AccessTokenStrategy, RefreshTokenStrategy, ], diff --git a/backend/src/modules/auth-module/services/auth.service.ts b/backend/src/modules/auth-module/services/auth.service.ts index f3b4f59..9416bba 100644 --- a/backend/src/modules/auth-module/services/auth.service.ts +++ b/backend/src/modules/auth-module/services/auth.service.ts @@ -1,8 +1,8 @@ import { ForbiddenException, Injectable } from '@nestjs/common'; +import { UserDataRepository } from '../../user-module/repositories/user-data.repository'; import { TokensDto, UserCredentialsDto } from '../models/dto'; import { UserCredentialsRepository } from '../repositories/user-credentials.repository'; -import { UserDataRepository } from '../repositories/user-data.repository'; import { EncryptionService } from './encryption.service'; import { TokenManagementService } from './token-management.service'; @@ -10,8 +10,8 @@ import { TokenManagementService } from './token-management.service'; @Injectable() export class AuthService { public constructor( - private readonly userRepository: UserCredentialsRepository, - private readonly UserDataRepository: UserDataRepository, + private readonly userCredentialsRepository: UserCredentialsRepository, + private readonly userDataRepository: UserDataRepository, private readonly tokenManagementService: TokenManagementService, private readonly encryptionService: EncryptionService ) {} @@ -20,18 +20,18 @@ export class AuthService { const passwordHashed = await this.encryptionService.hashData( userCredentials.password ); - const user = await this.userRepository.createUser( + const user = await this.userCredentialsRepository.createUser( userCredentials.email, passwordHashed ); - await this.UserDataRepository.createInitialUserData(user.id); + await this.userDataRepository.createInitialUserData(user); return this.generateAndPersistTokens(user.id, user.email); } public async signin(userCredentials: UserCredentialsDto): Promise { - const user = await this.userRepository.findUserByEmail( + const user = await this.userCredentialsRepository.findUserByEmail( userCredentials.email ); @@ -55,7 +55,7 @@ export class AuthService { userId: number, refreshToken: string ): Promise { - const user = await this.userRepository.findUserById(userId); + const user = await this.userCredentialsRepository.findUserById(userId); if (!user || !user.hashedRt) { throw new ForbiddenException('Access Denied'); @@ -74,7 +74,7 @@ export class AuthService { } public async logout(userId: number): Promise { - const affected = await this.userRepository.updateUserTokenHash( + const affected = await this.userCredentialsRepository.updateUserTokenHash( userId, null ); @@ -94,7 +94,10 @@ export class AuthService { tokens.refresh_token ); - await this.userRepository.updateUserTokenHash(userId, hashedRefreshToken); + await this.userCredentialsRepository.updateUserTokenHash( + userId, + hashedRefreshToken + ); return tokens; } } diff --git a/backend/src/modules/user-module/repositories/index.ts b/backend/src/modules/user-module/repositories/index.ts new file mode 100644 index 0000000..2248b76 --- /dev/null +++ b/backend/src/modules/user-module/repositories/index.ts @@ -0,0 +1 @@ +export * from './user-data.repository'; diff --git a/backend/src/modules/auth-module/repositories/user-data.repository.ts b/backend/src/modules/user-module/repositories/user-data.repository.ts similarity index 68% rename from backend/src/modules/auth-module/repositories/user-data.repository.ts rename to backend/src/modules/user-module/repositories/user-data.repository.ts index 85c593c..d8a57b1 100644 --- a/backend/src/modules/auth-module/repositories/user-data.repository.ts +++ b/backend/src/modules/user-module/repositories/user-data.repository.ts @@ -1,6 +1,6 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { UserData } from 'src/entities'; +import { UserCredentials, UserData } from 'src/entities'; import { Repository } from 'typeorm'; @Injectable() @@ -10,10 +10,12 @@ export class UserDataRepository { private readonly repository: Repository ) {} - public async createInitialUserData(userid: number): Promise { + public async createInitialUserData( + userCredentials: UserCredentials + ): Promise { const userData = new UserData(); - userData.id = userid; + userData.user = userCredentials; userData.isEmailConfirmed = false; return this.repository.save(userData); diff --git a/backend/src/modules/user-module/user.module.ts b/backend/src/modules/user-module/user.module.ts new file mode 100644 index 0000000..1786b75 --- /dev/null +++ b/backend/src/modules/user-module/user.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { UserData } from 'src/entities'; + +import { UserDataRepository } from './repositories'; + +@Module({ + imports: [TypeOrmModule.forFeature([UserData])], + providers: [UserDataRepository], + controllers: [], + exports: [UserDataRepository], +}) +export class UserModule {}