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/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..b0ab112 --- /dev/null +++ b/backend/src/entities/user-data.entity.ts @@ -0,0 +1,30 @@ +import { + Column, + Entity, + PrimaryGeneratedColumn, + OneToOne, + JoinColumn, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +import { UserCredentials } from './user-credentials.entity'; + +@Entity() +export class UserData { + @PrimaryGeneratedColumn('uuid') + public id: string; + + @Column({ default: false }) + public isEmailConfirmed: boolean; + + @OneToOne(() => UserCredentials) + @JoinColumn({ name: 'userCredentialsId' }) + public user: UserCredentials; + + @CreateDateColumn() + public createdAt: Date; + + @UpdateDateColumn() + public updatedAt: Date; +} diff --git a/backend/src/modules/auth-module/auth.module.ts b/backend/src/modules/auth-module/auth.module.ts index ed6168d..dab6e0f 100644 --- a/backend/src/modules/auth-module/auth.module.ts +++ b/backend/src/modules/auth-module/auth.module.ts @@ -1,10 +1,12 @@ import { Module } from '@nestjs/common'; import { JwtModule } from '@nestjs/jwt'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { UserCredentials } from 'src/entities/user-credentials.entity'; +import { UserCredentials } from 'src/entities'; + +import { UserModule } from '../user-module/user.module'; import { AuthController } from './controller/auth.controller'; -import { UserRepository } from './repositories/user.repository'; +import { UserCredentialsRepository } from './repositories/user-credentials.repository'; import { AuthService } from './services/auth.service'; import { EncryptionService } from './services/encryption.service'; import { TokenManagementService } from './services/token-management.service'; @@ -12,6 +14,7 @@ import { AccessTokenStrategy, RefreshTokenStrategy } from './strategies'; @Module({ imports: [ + UserModule, JwtModule.register({}), TypeOrmModule.forFeature([UserCredentials]), ], @@ -19,7 +22,7 @@ import { AccessTokenStrategy, RefreshTokenStrategy } from './strategies'; AuthService, TokenManagementService, EncryptionService, - UserRepository, + UserCredentialsRepository, 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 6d2d498..9416bba 100644 --- a/backend/src/modules/auth-module/services/auth.service.ts +++ b/backend/src/modules/auth-module/services/auth.service.ts @@ -1,7 +1,8 @@ import { ForbiddenException, Injectable } from '@nestjs/common'; +import { UserDataRepository } from '../../user-module/repositories/user-data.repository'; import { TokensDto, UserCredentialsDto } from '../models/dto'; -import { UserRepository } from '../repositories/user.repository'; +import { UserCredentialsRepository } from '../repositories/user-credentials.repository'; import { EncryptionService } from './encryption.service'; import { TokenManagementService } from './token-management.service'; @@ -9,7 +10,8 @@ import { TokenManagementService } from './token-management.service'; @Injectable() export class AuthService { public constructor( - private readonly userRepository: UserRepository, + private readonly userCredentialsRepository: UserCredentialsRepository, + private readonly userDataRepository: UserDataRepository, private readonly tokenManagementService: TokenManagementService, private readonly encryptionService: EncryptionService ) {} @@ -18,16 +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); + 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 ); @@ -51,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'); @@ -70,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 ); @@ -90,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/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], }); 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/user-module/repositories/user-data.repository.ts b/backend/src/modules/user-module/repositories/user-data.repository.ts new file mode 100644 index 0000000..d8a57b1 --- /dev/null +++ b/backend/src/modules/user-module/repositories/user-data.repository.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { UserCredentials, UserData } from 'src/entities'; +import { Repository } from 'typeorm'; + +@Injectable() +export class UserDataRepository { + public constructor( + @InjectRepository(UserData) + private readonly repository: Repository + ) {} + + public async createInitialUserData( + userCredentials: UserCredentials + ): Promise { + const userData = new UserData(); + + 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 {}