Skip to content

Commit e129eaf

Browse files
committed
merged with fix-migration
2 parents 23c023c + 1bdf0a9 commit e129eaf

24 files changed

+195
-146
lines changed

src/analytics/analytics.controller.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ import {
1010
} from '@nestjs/common';
1111
import { FilterAnalyticsRequestData } from './dto/filter-analytics-request-data';
1212
import { AnalyticsService } from './analytics.service';
13-
import { AuthGuard } from 'src/auth/auth.guard';
1413
import type { RequestWithUser } from 'src/types/RequestWithUser';
14+
import { GuardService } from 'src/guard/guard.service';
1515

1616
@Controller('analytics')
1717
export class AnalyticsController {
1818
constructor(private readonly analyticsService: AnalyticsService) {}
1919

20-
@UseGuards(AuthGuard)
20+
@UseGuards(GuardService)
2121
@HttpCode(HttpStatus.OK)
2222
@Get()
2323
async filterUrlAnalytics(

src/app.module.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import dataSource from './data-source';
99
import { ScheduleModule } from '@nestjs/schedule';
1010
import { CronModule } from './cron/cron.module';
1111
import { AnalyticsModule } from './analytics/analytics.module';
12+
import { GuardService } from './guard/guard.service';
13+
import { GuardModule } from './guard/guard.module';
1214
import { EventEmitterModule } from '@nestjs/event-emitter';
1315

1416
@Module({
@@ -22,8 +24,9 @@ import { EventEmitterModule } from '@nestjs/event-emitter';
2224
UrlModule,
2325
CronModule,
2426
AnalyticsModule,
27+
GuardModule,
2528
],
2629
controllers: [AppController],
27-
providers: [],
30+
providers: [GuardService],
2831
})
2932
export class AppModule {}

src/auth/auth.controller.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ import {
1010
import { AuthService } from './auth.service';
1111
import { SignupRequestData } from './dto/signup-user-dto';
1212

13+
import { ResendEmailVerificationRequestData } from './dto/resend-verification-dto';
14+
1315
import { LoginRequestData } from './dto/login-user-dto';
14-
import { ResendVerificationRequestData } from './dto/resend-verification-request-data';
1516
import { VerifyTokenRequestData } from './dto/verify-token-request-data';
1617

1718
@Controller('auth')
@@ -31,8 +32,13 @@ export class AuthController {
3132
}
3233

3334
@Post('resend-verification')
34-
async reSendVerification(@Body() requestData: ResendVerificationRequestData) {
35-
return await this.authService.sendVerificationLink(requestData);
35+
async reSendVerification(
36+
@Body()
37+
resendEmailVerificationRequestData: ResendEmailVerificationRequestData,
38+
) {
39+
return await this.authService.sendVerificationLink(
40+
resendEmailVerificationRequestData,
41+
);
3642
}
3743

3844
@Get('verify-email')

src/auth/auth.module.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ import { AuthController } from './auth.controller';
44
import { JwtModule } from '@nestjs/jwt';
55
import { CryptoService } from './crypto.service';
66
import { EmailModule } from 'src/email/email.module';
7-
import { AuthGuard } from './auth.guard';
87
import { EmailVerification } from './email-verification.entity';
9-
import { User } from 'src/user/user.entity';
108
import { TypeOrmModule } from '@nestjs/typeorm';
119
import { UserModule } from 'src/user/user.module';
1210

1311
@Module({
1412
imports: [
15-
TypeOrmModule.forFeature([User, EmailVerification]),
13+
TypeOrmModule.forFeature([EmailVerification]),
1614
EmailModule,
1715
UserModule,
1816
JwtModule.register({
@@ -21,8 +19,8 @@ import { UserModule } from 'src/user/user.module';
2119
signOptions: { expiresIn: '7d' },
2220
}),
2321
],
24-
providers: [AuthService, CryptoService, AuthGuard],
22+
providers: [AuthService, CryptoService],
2523
controllers: [AuthController],
26-
exports: [AuthService, AuthGuard],
24+
exports: [AuthService],
2725
})
2826
export class AuthModule {}

src/auth/auth.service.ts

Lines changed: 30 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
BadRequestException,
3+
ConflictException,
34
Injectable,
45
NotFoundException,
56
} from '@nestjs/common';
@@ -9,84 +10,62 @@ import { EmailService } from 'src/email/email.service';
910
import { CryptoService } from './crypto.service';
1011
import { LoginRequestData } from './dto/login-user-dto';
1112
import * as bcrypt from 'bcrypt';
12-
import { MoreThan, Repository } from 'typeorm';
13+
import { LessThan, Repository } from 'typeorm';
1314
import { InjectRepository } from '@nestjs/typeorm';
1415
import { EmailVerification } from './email-verification.entity';
1516
import { EmailVerificationPayload } from './interface';
16-
import { EmailMessages } from './messages';
1717
import { JwtPayload } from 'src/types/JwtPayload';
18-
import { ResendVerificationRequestData } from './dto/resend-verification-request-data';
19-
import { VerifyTokenRequestData } from './dto/verify-token-request-data';
18+
import { EmailMessages } from '../config/messages';
19+
import { ResendEmailVerificationRequestData } from './dto/resend-verification-dto';
2020
import { SendMailRequestData } from '../email/dto/send-mail-request-data';
21-
import { EventEmitter2, OnEvent } from '@nestjs/event-emitter';
22-
import { SendVerificationMailEvent } from 'src/event/send-verification-mail.event';
2321
import { UserService } from '../user/user.service';
22+
import { VerifyTokenRequestData } from './dto/verify-token-request-data';
2423

2524
@Injectable()
2625
export class AuthService {
2726
constructor(
28-
private readonly userService: UserService,
2927
private readonly jwtService: JwtService,
3028
private readonly emailService: EmailService,
29+
private readonly userService: UserService,
3130
@InjectRepository(EmailVerification)
3231
private readonly emailVerificationRepo: Repository<EmailVerification>,
3332
private readonly cryptoService: CryptoService,
34-
private readonly eventEmitter: EventEmitter2,
3533
) {}
3634

3735
async signUp(signUpUserDto: SignupRequestData): Promise<{ message: string }> {
38-
const existingUser = await this.userService.findByUserNameAndEmail(
39-
signUpUserDto.username,
40-
signUpUserDto.email,
41-
);
42-
43-
if (existingUser) {
44-
if (existingUser.username === signUpUserDto.username) {
45-
throw new BadRequestException(EmailMessages.usernameTaken);
46-
}
47-
48-
if (existingUser.email === signUpUserDto.email) {
49-
throw new BadRequestException(EmailMessages.emailTaken);
50-
}
51-
}
52-
5336
const hashedPassword = await this.cryptoService.hashPassword(
5437
signUpUserDto.password,
5538
);
5639

57-
const { email, fullName, username } = signUpUserDto;
58-
59-
await this.userService.create({
40+
const createUserRequestData: SignupRequestData = {
41+
...signUpUserDto,
6042
password: hashedPassword,
61-
email,
62-
fullName,
63-
username,
64-
});
65-
66-
const resendVerificationRequestData: ResendVerificationRequestData = {
67-
email: email,
6843
};
6944

70-
const event = new SendVerificationMailEvent(
71-
resendVerificationRequestData.email,
72-
);
73-
this.eventEmitter.emit('send.mail', event);
45+
const user = await this.userService.create(createUserRequestData);
7446

75-
return { message: 'Sign up succesfull. Verification mail has been sent.' };
47+
const requestData: ResendEmailVerificationRequestData = {
48+
email: user.email,
49+
};
50+
await this.sendVerificationLink(requestData);
51+
52+
return {
53+
message:
54+
'Sign Up successful. Verification mail has been sent. Please verify',
55+
};
7656
}
7757

78-
@OnEvent('send.mail')
7958
async sendVerificationLink(
80-
resendVerificationRequestData: ResendVerificationRequestData,
59+
resendEmailVerificationRequestData: ResendEmailVerificationRequestData,
8160
) {
82-
const email = resendVerificationRequestData.email;
61+
const email = resendEmailVerificationRequestData.email;
8362
const user = await this.userService.findOneByField('email', email);
8463
if (!user) {
85-
throw new BadRequestException('User not found');
64+
throw new NotFoundException('User not found');
8665
}
8766

88-
if (user.verifiedAt !== null) {
89-
throw new BadRequestException('User is already verified');
67+
if (user.verifiedAt) {
68+
throw new ConflictException('User is already verified');
9069
}
9170

9271
await this.emailVerificationRepo.softDelete({
@@ -128,22 +107,19 @@ export class AuthService {
128107
message: EmailMessages.emailSendSuccess,
129108
};
130109
}
110+
131111
async verify(verifyTokenRequestData: VerifyTokenRequestData) {
132112
const token = verifyTokenRequestData.token;
133-
134113
const payload = this.jwtService.verify<EmailVerificationPayload>(token, {
135114
secret: process.env.JWT_VERIFICATION_TOKEN_SECRET,
136115
});
137116

138117
const record = await this.emailVerificationRepo.findOne({
139-
where: {
140-
token,
141-
expiresAt: MoreThan(new Date()),
142-
},
118+
where: { token, expiresAt: LessThan(new Date()) },
143119
});
144120

145121
if (!record) {
146-
throw new BadRequestException('Token has expired');
122+
throw new NotFoundException('Token not found or has expired');
147123
}
148124

149125
await this.emailVerificationRepo.save(record);
@@ -172,7 +148,7 @@ export class AuthService {
172148
throw new NotFoundException('User not found');
173149
}
174150

175-
if (user.verifiedAt === null) {
151+
if (!user.verifiedAt) {
176152
throw new BadRequestException(
177153
'User not verified. Please verify before login',
178154
);
@@ -192,9 +168,9 @@ export class AuthService {
192168
return { accessToken: await this.jwtService.signAsync(payload) };
193169
}
194170

195-
async validateToken(
196-
verifyTokenRequestData: VerifyTokenRequestData,
197-
): Promise<JwtPayload> {
171+
async validateToken(verifyTokenRequestData: {
172+
token: string;
173+
}): Promise<JwtPayload> {
198174
const decoded = await this.jwtService.verifyAsync<JwtPayload>(
199175
verifyTokenRequestData.token,
200176
{
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { IsEmail, IsNotEmpty } from 'class-validator';
2+
export class ResendEmailVerificationRequestData {
3+
@IsEmail()
4+
@IsNotEmpty({ message: 'Email is required' })
5+
email: string;
6+
}

src/auth/email-verification.entity.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export class EmailVerification {
1515
@PrimaryGeneratedColumn('uuid')
1616
readonly id: string;
1717

18-
@Column({ name: 'user_id' })
18+
@Column({ name: 'user_id', type: 'uuid' })
1919
readonly userId: string;
2020

2121
@OneToOne(() => User, (user) => user.id, {
File renamed without changes.

src/cron/check-url-expiry.service.ts

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,35 @@
1-
import { Injectable, NotFoundException } from '@nestjs/common';
1+
import { Injectable } from '@nestjs/common';
22
import { Cron, CronExpression } from '@nestjs/schedule';
3-
import { InjectRepository } from '@nestjs/typeorm';
4-
import { Url } from 'src/url/url.entity';
5-
import { IsNull, LessThan, Repository } from 'typeorm';
63
import { EmailService } from '../email/email.service';
7-
import { User } from 'src/user/user.entity';
4+
import { UserService } from '../user/user.service';
5+
import { UrlService } from '../url/url.service';
86

97
@Injectable()
108
export class CheckUrlExpiry {
119
constructor(
12-
@InjectRepository(Url)
13-
private readonly urlRepository: Repository<Url>,
14-
@InjectRepository(User)
15-
private readonly userRepository: Repository<User>,
1610
private readonly emailService: EmailService,
11+
private readonly urlService: UrlService,
12+
private readonly userService: UserService,
1713
) {}
1814

1915
@Cron(CronExpression.EVERY_30_SECONDS)
2016
async checkUrls() {
21-
const expiredUrls = await this.urlRepository.find({
22-
where: { expiresAt: LessThan(new Date()), expiryAlertedAt: IsNull() },
23-
});
17+
const expiredUrls = await this.urlService.checkExpiredUrl();
2418
for (const url of expiredUrls) {
25-
const user = await this.userRepository.findOne({
26-
where: {
27-
id: url.userId,
28-
},
29-
});
19+
const user = await this.userService.findOneByField('id', url.userId);
3020
if (!user) {
31-
return new NotFoundException('User not found');
21+
continue; // skip if user not found
3222
}
23+
3324
await this.emailService.sendMail({
3425
to: user.email,
3526
subject: `Your ${url.title} URL has expired`,
36-
text: `Hi ${user.fullName} your ${url.title} url has expired!`,
27+
text: `Hi ${user.fullName}, your ${url.title} URL has expired!`,
3728
});
38-
await this.urlRepository.save({
29+
30+
await this.urlService.update(user.id, url.id, {
3931
...url,
40-
expiryAlertedAt: new Date(Date.now()),
32+
expiryAlertedAt: new Date(),
4133
});
4234
}
4335
}

src/cron/cron.module.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import { Module } from '@nestjs/common';
2-
import { TypeOrmModule } from '@nestjs/typeorm';
3-
import { Url } from 'src/url/url.entity';
4-
import { User } from 'src/user/user.entity';
52
import { EmailModule } from 'src/email/email.module';
63
import { CheckUrlExpiry } from './check-url-expiry.service';
4+
import { UserModule } from 'src/user/user.module';
5+
import { UrlModule } from 'src/url/url.module';
76

87
@Module({
9-
imports: [TypeOrmModule.forFeature([Url, User]), EmailModule],
8+
imports: [EmailModule, UserModule, UrlModule],
109
controllers: [],
1110
providers: [CheckUrlExpiry],
1211
exports: [],

0 commit comments

Comments
 (0)