generate and save token to db + send via sendgrid api

This commit is contained in:
Igor Hrenowitsch Propisnov 2024-05-28 23:34:08 +02:00
parent 4278196096
commit 2f418ab14e
11 changed files with 120 additions and 9 deletions

View File

@ -0,0 +1,33 @@
import {
Column,
CreateDateColumn,
Entity,
JoinColumn,
OneToOne,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
import { UserCredentials } from './user-credentials.entity';
@Entity()
export class EmailVerification {
@PrimaryGeneratedColumn('uuid')
public id: string;
@Column()
public token: string;
@Column()
public expiresAt: Date;
@OneToOne(() => UserCredentials)
@JoinColumn({ name: 'userCredentialsId' })
public user: UserCredentials;
@CreateDateColumn()
public createdAt: Date;
@UpdateDateColumn()
public updatedAt: Date;
}

View File

@ -1,2 +1,3 @@
export * from './user-credentials.entity'; export * from './user-credentials.entity';
export * from './user-data.entity'; export * from './user-data.entity';
export * from './email-verification.entity';

View File

@ -5,6 +5,7 @@ import { UserCredentials } from 'src/entities';
import { SendgridModule } from '../sendgrid-module/sendgrid.module'; import { SendgridModule } from '../sendgrid-module/sendgrid.module';
import { UserModule } from '../user-module/user.module'; import { UserModule } from '../user-module/user.module';
import { VerifyModule } from '../verify-module/verify.module';
import { AuthController } from './controller/auth.controller'; import { AuthController } from './controller/auth.controller';
import { UserCredentialsRepository } from './repositories/user-credentials.repository'; import { UserCredentialsRepository } from './repositories/user-credentials.repository';
@ -17,6 +18,7 @@ import { AccessTokenStrategy, RefreshTokenStrategy } from './strategies';
imports: [ imports: [
UserModule, UserModule,
SendgridModule, SendgridModule,
VerifyModule,
JwtModule.register({}), JwtModule.register({}),
TypeOrmModule.forFeature([UserCredentials]), TypeOrmModule.forFeature([UserCredentials]),
], ],

View File

@ -31,12 +31,15 @@ export class AuthService {
await this.userDataRepository.createInitialUserData(user); await this.userDataRepository.createInitialUserData(user);
// TODO Send email confirmation const token =
// await this.passwordConfirmationMailService.sendPasswordConfirmationMail( await this.emailVerificationService.generateEmailVerificationToken(
// user.email user.id
// ); );
// await this.emailVerificationService.generateEmailVerificationToken(user.id); await this.passwordConfirmationMailService.sendPasswordConfirmationMail(
user.email,
token
);
return this.generateAndPersistTokens(user.id, user.email); return this.generateAndPersistTokens(user.id, user.email);
} }

View File

@ -1,6 +1,6 @@
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { TypeOrmModuleOptions } from '@nestjs/typeorm'; import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import { UserCredentials, UserData } from 'src/entities'; import { EmailVerification, UserCredentials, UserData } from 'src/entities';
export const databaseConfigFactory = ( export const databaseConfigFactory = (
configService: ConfigService configService: ConfigService
@ -13,5 +13,5 @@ export const databaseConfigFactory = (
database: configService.get('DB_NAME'), database: configService.get('DB_NAME'),
synchronize: true, synchronize: true,
logging: true, logging: true,
entities: [UserCredentials, UserData], entities: [UserCredentials, UserData, EmailVerification],
}); });

View File

@ -16,18 +16,23 @@ export class PasswordConfirmationMailService extends BaseMailService {
super(sendGridApiKey); super(sendGridApiKey);
} }
public async sendPasswordConfirmationMail(to: string): Promise<void> { public async sendPasswordConfirmationMail(
to: string,
token: string
): Promise<void> {
const templateId: string = this.templateConfigService.getTemplateId( const templateId: string = this.templateConfigService.getTemplateId(
this.PASSWORD_CONFIRMATION_EMAIL this.PASSWORD_CONFIRMATION_EMAIL
); );
const encodedToken = encodeURIComponent(token);
const mailoptions: SendGridMailApi.MailDataRequired = { const mailoptions: SendGridMailApi.MailDataRequired = {
to, to,
from: { email: 'info@igor-propisnov.com', name: 'Ticket App' }, from: { email: 'info@igor-propisnov.com', name: 'Ticket App' },
templateId: templateId, templateId: templateId,
dynamicTemplateData: { dynamicTemplateData: {
name: 'Mara', name: 'Mara',
buttonUrl: 'https://igor-propisnov.com', buttonUrl: `http://localhost:4200/?token=${encodedToken}`,
}, },
}; };

View File

@ -0,0 +1,24 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { EmailVerification } from 'src/entities';
import { Repository } from 'typeorm';
@Injectable()
export class EmailVerifyRepository {
public constructor(
@InjectRepository(EmailVerification)
private readonly repository: Repository<EmailVerification>
) {}
public async createEmailVerification(
token: string,
expiresAt: Date,
userId: string
): Promise<void> {
await this.repository.save({
token,
expiresAt,
user: { id: userId },
});
}
}

View File

@ -0,0 +1 @@
export * from './email-verify.repository';

View File

@ -0,0 +1,27 @@
import { randomBytes } from 'crypto';
import { Injectable } from '@nestjs/common';
import { EmailVerifyRepository } from '../repositories';
@Injectable()
export class EmailVerificationService {
public constructor(
private readonly emailVerifyRepository: EmailVerifyRepository
) {}
public async generateEmailVerificationToken(userId: string): Promise<string> {
const token = randomBytes(32).toString('hex');
// TODO Check users local time zone and set expiration time accordingly
const expiration = new Date(Date.now() + 24 * 60 * 60 * 1000);
this.emailVerifyRepository.createEmailVerification(
token,
expiration,
userId
);
return token;
}
}

View File

@ -0,0 +1,15 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { EmailVerification } from 'src/entities';
import { EmailVerifyRepository } from './repositories';
import { EmailVerificationService } from './services/email-verification.service';
@Module({
imports: [ConfigModule, TypeOrmModule.forFeature([EmailVerification])],
providers: [EmailVerifyRepository, EmailVerificationService],
controllers: [],
exports: [EmailVerificationService],
})
export class VerifyModule {}