Skip to content

Commit

Permalink
refactor(auth): Updated authentication logic
Browse files Browse the repository at this point in the history
  • Loading branch information
rajdip-b committed Jun 18, 2024
1 parent 22d5a38 commit e6f3a0e
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 113 deletions.
29 changes: 3 additions & 26 deletions src/auth/auth.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,28 +41,7 @@ describe('Auth Controller Tests', () => {
it('should be able to sign up using email', async () => {
const response = await app.inject({
method: 'POST',
url: '/auth/sign-up',
payload: {
email: '[email protected]',
},
});

expect(response.statusCode).toEqual(201);
expect(response.json().email).toEqual('[email protected]');
});

it('should be able to sign in using email', async () => {
await prisma.user.create({
data: {
email: '[email protected]',
isEmailVerified: true,
authType: AuthType.EMAIL,
},
});

const response = await app.inject({
method: 'POST',
url: '/auth/sign-in',
url: '/auth/send-verification-email',
payload: {
email: '[email protected]',
},
Expand All @@ -75,10 +54,9 @@ describe('Auth Controller Tests', () => {
it('should send verification code to email on sign up', async () => {
await app.inject({
method: 'POST',
url: '/auth/sign-up',
url: '/auth/send-verification-email',
payload: {
email: '[email protected]',
password: 'Password123',
},
});

Expand Down Expand Up @@ -123,10 +101,9 @@ describe('Auth Controller Tests', () => {
// Sign up
await app.inject({
method: 'POST',
url: '/auth/sign-up',
url: '/auth/send-verification-email',
payload: {
email: '[email protected]',
password: 'Password123',
},
});

Expand Down
35 changes: 7 additions & 28 deletions src/auth/controller/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@ import { Public } from '../../decorators/public.decorator';
import { FacebookOAuthStrategyFactory } from '../../oauth/factory/facebook/facebook-strategy.factory';
import { LinkedInOAuthStrategyFactory } from '../../oauth/factory/linkedin/linkedin-strategy.factory';
import { AppleOAuthStrategyFactory } from '../../oauth/factory/apple/apple-strategy.factory';
import { SignupDto } from '../dto/signup.dto';
import { SigninDto } from '../dto/signin.dto';
import { UserDetailsDto } from '../dto/user-details.dto';
import { EmailVerificationDto } from '../dto/email-verification.dto';
import {
ApiBadRequestResponse,
ApiConflictResponse,
ApiCreatedResponse,
ApiNoContentResponse,
ApiNotFoundResponse,
Expand Down Expand Up @@ -313,29 +311,10 @@ export class AuthController {
}

@Public()
@Post('sign-up')
@Post('send-verification-email')
@ApiOperation({
summary: 'Sign up',
description: 'Sign up with email',
})
@ApiCreatedResponse({
description: 'User signed up successfully',
})
@ApiConflictResponse({
description: 'User with this email already exists',
})
async signUp(@Body() dto: SignupDto) {
return await this.authService.signUp(dto);
}

@Public()
@Post('sign-in')
@ApiOperation({
summary: 'Sign in',
description: 'Sign in with email',
})
@ApiNotFoundResponse({
description: 'User not found',
summary: 'Sign in or sign up with email',
description: 'Sign in or sign up with email',
})
@ApiCreatedResponse({
description: 'User signed in successfully',
Expand All @@ -347,8 +326,8 @@ export class AuthController {
},
},
})
async signIn(@Body() dto: SigninDto) {
return await this.authService.signIn(dto);
async sendVerificationCode(@Body() dto: UserDetailsDto) {
return await this.authService.sendVerificationCode(dto);
}

@Public()
Expand Down Expand Up @@ -396,7 +375,7 @@ export class AuthController {
},
})
async verifyEmail(@Body() dto: EmailVerificationDto) {
return await this.authService.verifyEmail(dto.email, dto.code);
return await this.authService.verifyEmail(dto);
}

@Get('/social-accounts')
Expand Down
16 changes: 0 additions & 16 deletions src/auth/dto/signup.dto.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ApiProperty } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
import { IsEmail } from 'class-validator';

export class SigninDto {
export class UserDetailsDto {
@IsEmail()
@Transform(({ value }) => value.toLowerCase())
@ApiProperty({
Expand Down
87 changes: 45 additions & 42 deletions src/auth/service/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import {
BadRequestException,
ConflictException,
ForbiddenException,
Injectable,
NotFoundException,
} from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import { JwtService } from '@nestjs/jwt';
import { AuthType, SocialAccountType, User } from '@prisma/client';
import { SignupDto } from '../dto/signup.dto';
import { UserDetailsDto } from '../dto/user-details.dto';
import { MailService } from '../../mail/mail.service';
import { SigninDto } from '../dto/signin.dto';
import { EmailVerificationDto } from '../dto/email-verification.dto';

@Injectable()
export class AuthService {
Expand All @@ -20,37 +19,17 @@ export class AuthService {
private mailService: MailService,
) {}

async signUp(dto: SignupDto) {
async sendVerificationCode(dto: UserDetailsDto) {
const user = await this.createUserIfNotExists(
dto.email,
AuthType.EMAIL,
null,
null,
true,
);

return user;
}

async signIn(dto: SigninDto) {
const user = await this.prisma.user.findUnique({
where: {
email: dto.email,
},
select: {
isEmailVerified: true,
email: true,
},
});

if (!user) {
throw new NotFoundException('User not found');
}

await this.sendEmailVerificationCode(dto.email);
return user;
}

async handleGoogleOAuthLogin(req: any) {
const { emails, displayName: name, photos } = req.user;
const email = emails[0].value;
Expand All @@ -61,7 +40,6 @@ export class AuthService {
AuthType.GOOGLE,
name,
profilePictureUrl,
false,
);

const token = await this.generateToken(user);
Expand Down Expand Up @@ -98,7 +76,6 @@ export class AuthService {
AuthType.FACEBOOK,
displayName,
profilePictureUrl,
false,
);
await this.connectSocialPlatform(
SocialAccountType.FACEBOOK,
Expand Down Expand Up @@ -137,7 +114,6 @@ export class AuthService {
AuthType.LINKEDIN,
displayName,
picture,
false,
);
await this.connectSocialPlatform(
SocialAccountType.LINKEDIN,
Expand All @@ -161,7 +137,6 @@ export class AuthService {
AuthType.APPLE,
displayName,
null,
false,
);

const token = await this.generateToken(user);
Expand Down Expand Up @@ -194,7 +169,6 @@ export class AuthService {
AuthType.GITHUB,
name,
avatar_url,
false,
);
await this.connectSocialPlatform(SocialAccountType.GITHUB, user.id, req);
}
Expand All @@ -216,7 +190,9 @@ export class AuthService {
await this.sendEmailVerificationCode(email);
}

async verifyEmail(email: string, code: string) {
async verifyEmail(dto: EmailVerificationDto) {
const { email, code } = dto;

const verificationCode = await this.prisma.verificationCode.findUnique({
where: {
email,
Expand All @@ -235,7 +211,17 @@ export class AuthService {
throw new BadRequestException('Code expired');
}

const user = await this.prisma.user.update({
const user = await this.prisma.user.findUnique({
where: {
email,
},
});

if (!user) {
throw new NotFoundException('User not found');
}

const updatedUser = await this.prisma.user.update({
where: {
email,
},
Expand All @@ -258,12 +244,14 @@ export class AuthService {
},
});

await this.mailService.sendEmailVerifiedEmail(email);
// We send the email verified email only if the user is was not verified before
if (!user.isEmailVerified)
await this.mailService.sendEmailVerifiedEmail(email);

const token = await this.generateToken(user);
const token = await this.generateToken(updatedUser);

return {
...user,
...updatedUser,
token,
};
}
Expand All @@ -273,14 +261,11 @@ export class AuthService {
authType: AuthType,
name?: string,
profilePictureUrl?: string,
throwErrorIfUserExists?: boolean,
) {
email = email.toLowerCase();

let user = await this.findUserByEmail(email);
if (user && throwErrorIfUserExists) {
throw new ConflictException('User already exists');
}

// We need to create the user if it doesn't exist yet
if (!user) {
user = await this.prisma.user.create({
Expand All @@ -289,7 +274,7 @@ export class AuthService {
name: name,
profilePictureUrl: profilePictureUrl,
authType,
isEmailVerified: authType !== AuthType.EMAIL,
isEmailVerified: authType !== AuthType.EMAIL, // If the user signs up with OAuth, we consider the email as verified
settings: {
create: {},
},
Expand All @@ -303,9 +288,28 @@ export class AuthService {
isEmailVerified: true,
},
});
} else {
// And if it exists, we need to update the user data
user = await this.prisma.user.update({
where: {
email,
},
data: {
name,
profilePictureUrl,
},
select: {
id: true,
email: true,
name: true,
profilePictureUrl: true,
authType: true,
isEmailVerified: true,
},
});
}

await this.sendEmailVerificationCode(email);
} else if (!user.isEmailVerified) {
if (!user.isEmailVerified) {
await this.sendEmailVerificationCode(email);
}

Expand Down Expand Up @@ -384,7 +388,6 @@ export class AuthService {
userId: string,
req: any,
) {

const socialAcc = await this.prisma.socialAccount.findMany({
where: { socialId: req.user.id, platform },
});
Expand Down

0 comments on commit e6f3a0e

Please sign in to comment.