Skip to content

Commit

Permalink
Merge branch 'feat#75/gerenciar-jornada' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
DaviMatheus authored Aug 18, 2024
2 parents a553265 + a6774c7 commit 144654b
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 43 deletions.
19 changes: 19 additions & 0 deletions src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,25 @@ export class AuthController {
this.authService.redirectFederated(req.user as any, res);
}

@Get('validate-token')
async validateToken(@Req() req: Request) {
const token = this.extractTokenFromHeader(req);

if (!token) {
throw new UnauthorizedException('Token not found');
}

const payload = await this.authService.validateToken(token);

return {
accessToken: token,
userPayload: payload,
};
}

private extractTokenFromHeader(request: Request): string | undefined {
return request.headers.authorization?.split(' ')[1];
}
@Post('refresh')
async refreshTokens(@Body() refreshTokenDto: RefreshTokenDto) {
return this.authService.refreshTokens(refreshTokenDto.refreshToken);
Expand Down
13 changes: 13 additions & 0 deletions src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,19 @@ export class AuthService {
refreshToken,
};
}
async validateToken(
token: string,
): Promise<{ userId: string; [key: string]: any }> {
try {
const payload = this.jwtService.verify(token);
return {
userId: payload.userId,
...payload,
};
} catch (err) {
throw new UnauthorizedException('Invalid token');
}
}

async storeRefreshToken(token: string, userId: string) {
const expiryDate = new Date();
Expand Down
3 changes: 2 additions & 1 deletion src/users/interface/user.interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Document } from 'mongoose';
import mongoose, { Document } from 'mongoose';
import { UserRole } from '../dtos/user-role.enum';

export interface User extends Document {
Expand All @@ -9,4 +9,5 @@ export interface User extends Document {
verificationToken?: string;
isVerified?: boolean;
role?: UserRole;
journeys?: mongoose.Types.ObjectId[];
}
1 change: 1 addition & 0 deletions src/users/interface/user.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const UserSchema = new mongoose.Schema(
enum: Object.values(UserRole),
default: UserRole.ALUNO,
},
journeys: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Journey' }],
},
{ timestamps: true, collection: 'users' },
);
Expand Down
15 changes: 11 additions & 4 deletions src/users/users.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,22 @@ export class UsersController {
};
}

@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(UserRole.ADMIN)
@Get()
async getUsers() {
return await this.usersService.getUsers();
}
@Patch(':id/add-journey')
async addJourneyToUser(
@Param('id') id: string,
@Body() body: { journeyId: string },
) {
try {
return await this.usersService.addJourneyToUser(id, body.journeyId);
} catch (error) {
throw error;
}
}

@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(UserRole.ADMIN)
@Get('/:id')
async getUserById(@Param('id') id: string) {
try {
Expand Down
20 changes: 19 additions & 1 deletion src/users/users.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Model } from 'mongoose';
import { Model, Types } from 'mongoose';
import { EmailService } from './email.service';
import { CreateUserDto } from './dtos/create-user.dto';
import { CreateUserDtoFederated } from './dtos/create-user-federated.dto';
Expand Down Expand Up @@ -80,6 +80,24 @@ export class UsersService {
return user;
}

async addJourneyToUser(userId: string, journeyId: string): Promise<User> {
const user = await this.userModel.findById(userId).exec();
if (!user) {
throw new NotFoundException(`User with ID ${userId} not found`);
}

const objectId = new Types.ObjectId(journeyId);

if (!user.journeys) {
user.journeys = [];
}

if (!user.journeys.includes(objectId)) {
user.journeys.push(objectId);
}

return user.save();
}
async deleteUserById(_id: string): Promise<void> {
const result = await this.userModel.deleteOne({ _id }).exec();
if (result.deletedCount === 0) {
Expand Down
1 change: 1 addition & 0 deletions test/auth.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ describe('AuthController', () => {
expect(await authController.forgotPassword(forgotPasswordDto)).toEqual({
message: 'Password reset link sent',
});

});
});

Expand Down
116 changes: 79 additions & 37 deletions test/email.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ConfigService } from '@nestjs/config';
import * as nodemailer from 'nodemailer';
import { EmailService } from 'src/users/email.service';

jest.mock('nodemailer');
jest.mock('nodemailer-sendgrid-transport', () =>
jest.fn(() => ({
sendMail: jest.fn(),
Expand All @@ -22,24 +20,7 @@ describe('EmailService', () => {
jest.spyOn(nodemailer, 'createTransport').mockReturnValue(mockTransporter);

const module: TestingModule = await Test.createTestingModule({
providers: [
EmailService,
{
provide: ConfigService,
useValue: {
get: jest.fn((key: string) => {
switch (key) {
case 'FRONTEND_URL':
return 'http://frontend-url.com';
case 'SENDGRID_API_KEY':
return 'fake-api-key';
default:
return null;
}
}),
},
},
],
providers: [EmailService],
}).compile();

emailService = module.get<EmailService>(EmailService);
Expand All @@ -51,6 +32,8 @@ describe('EmailService', () => {

describe('sendVerificationEmail', () => {
it('should send an email', async () => {
const loginLink = process.env.EMAIL_LINK;

const email = '[email protected]';

await emailService.sendVerificationEmail(email);
Expand All @@ -59,24 +42,83 @@ describe('EmailService', () => {
from: process.env.EMAIL_USER,
to: email,
subject: 'Bem-vindo!',
html: expect.any(String),
});
});
});

describe('sendForgotPassword', () => {
it('should send a password reset email', async () => {
const token = 'test-token';
const email = '[email protected]';

await emailService.sendPasswordResetEmail(email, token);

expect(mockTransporter.sendMail).toHaveBeenCalledWith({
from: process.env.EMAIL_USER,
to: email,
subject: 'Solicitação de Redefinição de Senha',
html: expect.any(String),
html: `
<html>
<head>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
color: #333;
margin: 0;
padding: 20px;
}
.container {
max-width: 600px;
margin: 0 auto;
background: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
h1 {
color: #333;
font-size: 24px;
margin-top: 0;
}
p {
line-height: 1.6;
margin: 0 0 10px;
}
.button {
display: inline-block;
padding: 10px 20px;
font-size: 16px;
color: #fff !important; /* Ensures text color is white */
background-color: #f97316 !important; /* Tailwind's orange-500 color */
text-decoration: none !important;
border-radius: 9999px !important; /* Tailwind's rounded-full */
margin-top: 20px;
text-align: center;
font-weight: bold !important;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important; /* Tailwind's shadow-md */
transition: box-shadow 0.3s ease !important; /* Tailwind's transition duration */
}
.button:hover {
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.2) !important; /* Tailwind's shadow-lg */
}
.footer {
margin-top: 20px;
font-size: 12px;
color: #888;
text-align: center;
}
.footer a {
color: #007bff;
text-decoration: none;
}
</style>
</head>
<body>
<div class="container">
<h1>Bem-vindo ao Nosso Serviço!</h1>
<p>Olá,</p>
<p>Seu cadastro foi realizado com sucesso. Para acessar sua conta, clique no botão abaixo:</p>
<div style="text-align: center;">
<a href="${loginLink}" class="button">Acessar Conta</a>
</div>
<p>Se você não se cadastrou em nosso serviço, por favor ignore este e-mail.</p>
<div class="footer">
<p>Obrigado por se cadastrar!</p>
<p>Equipe de Suporte</p>
<p><a href="${loginLink}">${loginLink}</a></p>
</div>
</div>
</body>
</html>
`,
});
});
});
});

0 comments on commit 144654b

Please sign in to comment.