2024-05-25 06:02:26 +00:00
|
|
|
import { inject, injectable } from 'tsyringe';
|
2024-06-25 02:45:00 +00:00
|
|
|
import type { RegisterEmailDto } from '../../../dtos/register-email.dto';
|
2024-05-25 06:02:26 +00:00
|
|
|
import { UsersRepository } from '../repositories/users.repository';
|
|
|
|
|
import { MailerService } from './mailer.service';
|
|
|
|
|
import { TokensService } from './tokens.service';
|
2024-06-25 02:45:00 +00:00
|
|
|
import type { SignInEmailDto } from '../../../dtos/signin-email.dto';
|
2024-05-25 06:02:26 +00:00
|
|
|
import { BadRequest } from '../common/errors';
|
|
|
|
|
import { LuciaProvider } from '../providers/lucia.provider';
|
2024-06-25 02:45:00 +00:00
|
|
|
import type { UpdateEmailDto } from '../../../dtos/update-email.dto';
|
2024-05-27 17:38:59 +00:00
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
|
/* Service */
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
|
/* ---------------------------------- About --------------------------------- */
|
|
|
|
|
/*
|
|
|
|
|
Services are responsible for handling business logic and data manipulation.
|
|
|
|
|
They genreally call on repositories or other services to complete a use-case.
|
|
|
|
|
*/
|
|
|
|
|
/* ---------------------------------- Notes --------------------------------- */
|
|
|
|
|
/*
|
|
|
|
|
Services should be kept as clean and simple as possible.
|
|
|
|
|
|
|
|
|
|
Create private functions to handle complex logic and keep the public methods as
|
|
|
|
|
simple as possible. This makes the service easier to read, test and understand.
|
|
|
|
|
*/
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
2024-05-25 06:02:26 +00:00
|
|
|
|
|
|
|
|
@injectable()
|
|
|
|
|
export class IamService {
|
|
|
|
|
constructor(
|
|
|
|
|
@inject(UsersRepository) private usersRepository: UsersRepository,
|
|
|
|
|
@inject(TokensService) private tokensService: TokensService,
|
|
|
|
|
@inject(MailerService) private mailerService: MailerService,
|
|
|
|
|
@inject(LuciaProvider) private lucia: LuciaProvider
|
2024-06-25 16:14:45 +00:00
|
|
|
) { }
|
2024-05-25 06:02:26 +00:00
|
|
|
|
|
|
|
|
async registerEmail(data: RegisterEmailDto) {
|
|
|
|
|
const existingUser = await this.usersRepository.findOneByEmail(data.email);
|
|
|
|
|
|
|
|
|
|
if (!existingUser) {
|
|
|
|
|
const newUser = await this.usersRepository.create({ email: data.email, verified: false });
|
|
|
|
|
return this.createValidationReuqest(newUser.id, newUser.email);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this.createValidationReuqest(existingUser.id, existingUser.email);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async signinEmail(data: SignInEmailDto) {
|
|
|
|
|
const user = await this.usersRepository.findOneByEmail(data.email);
|
2024-06-25 16:14:45 +00:00
|
|
|
if (!user) throw BadRequest('Bad credentials');
|
2024-05-25 06:02:26 +00:00
|
|
|
|
|
|
|
|
const isValidToken = await this.tokensService.validateToken(user.id, data.token);
|
2024-06-25 16:14:45 +00:00
|
|
|
if (!isValidToken) throw BadRequest('Bad credentials');
|
2024-05-25 06:02:26 +00:00
|
|
|
|
|
|
|
|
// if this is a new unverified user, send a welcome email and update the user
|
|
|
|
|
if (!user.verified) {
|
|
|
|
|
await this.usersRepository.update(user.id, { verified: true });
|
2024-05-27 17:38:59 +00:00
|
|
|
this.mailerService.sendWelcomeEmail({
|
2024-05-25 06:02:26 +00:00
|
|
|
to: user.email,
|
2024-05-27 17:38:59 +00:00
|
|
|
props: null
|
2024-05-25 06:02:26 +00:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this.lucia.createSession(user.id, {});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async verifyEmail(userId: string, token: string) {
|
|
|
|
|
const user = await this.usersRepository.findOneById(userId);
|
2024-06-25 16:14:45 +00:00
|
|
|
if (!user) throw BadRequest('User not found');
|
2024-05-25 06:02:26 +00:00
|
|
|
|
|
|
|
|
const validToken = await this.tokensService.validateToken(user.id, token);
|
2024-06-25 16:14:45 +00:00
|
|
|
if (!validToken) throw BadRequest('Invalid token');
|
|
|
|
|
|
2024-05-25 06:02:26 +00:00
|
|
|
await this.usersRepository.update(user.id, { email: validToken.email });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async updateEmail(userId: string, data: UpdateEmailDto) {
|
|
|
|
|
return this.createValidationReuqest(userId, data.email);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async logout(sessionId: string) {
|
|
|
|
|
return this.lucia.invalidateSession(sessionId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async createValidationReuqest(userId: string, email: string) {
|
|
|
|
|
const validationToken = await this.tokensService.create(userId, email);
|
2024-05-27 17:38:59 +00:00
|
|
|
this.mailerService.sendEmailVerification({
|
2024-05-25 06:02:26 +00:00
|
|
|
to: email,
|
|
|
|
|
props: { token: validationToken.token }
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|