Implement password change endpoint

* move email templates to server
This commit is contained in:
Philipinho
2024-05-04 15:46:11 +01:00
parent c1cd090252
commit fece460051
22 changed files with 323 additions and 425 deletions

View File

@ -14,6 +14,11 @@ import { CreateUserDto } from './dto/create-user.dto';
import { SetupGuard } from './guards/setup.guard';
import { EnvironmentService } from '../../integrations/environment/environment.service';
import { CreateAdminUserDto } from './dto/create-admin-user.dto';
import { ChangePasswordDto } from './dto/change-password.dto';
import { AuthUser } from '../../decorators/auth-user.decorator';
import { User, Workspace } from '@docmost/db/types/entity.types';
import { AuthWorkspace } from '../../decorators/auth-workspace.decorator';
import { JwtAuthGuard } from '../../guards/jwt-auth.guard';
@Controller('auth')
export class AuthController {
@ -44,4 +49,15 @@ export class AuthController {
if (this.environmentService.isCloud()) throw new NotFoundException();
return this.authService.setup(createAdminUserDto);
}
@UseGuards(JwtAuthGuard)
@HttpCode(HttpStatus.OK)
@Post('change-password')
async changePassword(
@Body() dto: ChangePasswordDto,
@AuthUser() user: User,
@AuthWorkspace() workspace: Workspace,
) {
return this.authService.changePassword(dto, user.id, workspace.id);
}
}

View File

@ -7,8 +7,6 @@ import { TokenService } from './services/token.service';
import { JwtStrategy } from './strategies/jwt.strategy';
import { WorkspaceModule } from '../workspace/workspace.module';
import { SignupService } from './services/signup.service';
import { UserModule } from '../user/user.module';
import { SpaceModule } from '../space/space.module';
import { GroupModule } from '../group/group.module';
@Module({
@ -23,10 +21,8 @@ import { GroupModule } from '../group/group.module';
};
},
inject: [EnvironmentService],
} as any),
UserModule,
}),
WorkspaceModule,
SpaceModule,
GroupModule,
],
controllers: [AuthController],

View File

@ -0,0 +1,13 @@
import { IsNotEmpty, IsString, MinLength } from 'class-validator';
export class ChangePasswordDto {
@IsNotEmpty()
@MinLength(8)
@IsString()
oldPassword: string;
@IsNotEmpty()
@MinLength(8)
@IsString()
newPassword: string;
}

View File

@ -1,4 +1,9 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import {
BadRequestException,
Injectable,
NotFoundException,
UnauthorizedException,
} from '@nestjs/common';
import { LoginDto } from '../dto/login.dto';
import { CreateUserDto } from '../dto/create-user.dto';
import { TokenService } from './token.service';
@ -6,7 +11,10 @@ import { TokensDto } from '../dto/tokens.dto';
import { SignupService } from './signup.service';
import { CreateAdminUserDto } from '../dto/create-admin-user.dto';
import { UserRepo } from '@docmost/db/repos/user/user.repo';
import { comparePasswordHash } from '../../../helpers/utils';
import { comparePasswordHash, hashPassword } from '../../../helpers';
import { ChangePasswordDto } from '../dto/change-password.dto';
import { MailService } from '../../../integrations/mail/mail.service';
import ChangePasswordEmail from '@docmost/transactional/emails/change-password-email';
@Injectable()
export class AuthService {
@ -14,6 +22,7 @@ export class AuthService {
private signupService: SignupService,
private tokenService: TokenService,
private userRepo: UserRepo,
private mailService: MailService,
) {}
async login(loginDto: LoginDto, workspaceId: string) {
@ -52,4 +61,43 @@ export class AuthService {
return { tokens };
}
async changePassword(
dto: ChangePasswordDto,
userId: string,
workspaceId: string,
): Promise<void> {
const user = await this.userRepo.findById(userId, workspaceId, {
includePassword: true,
});
if (!user) {
throw new NotFoundException('User not found');
}
const comparePasswords = await comparePasswordHash(
dto.oldPassword,
user.password,
);
if (!comparePasswords) {
throw new BadRequestException('Current password is incorrect');
}
const newPasswordHash = await hashPassword(dto.newPassword);
await this.userRepo.updateUser(
{
password: newPasswordHash,
},
userId,
workspaceId,
);
const emailTemplate = ChangePasswordEmail({ username: user.name });
await this.mailService.sendToQueue({
to: user.email,
subject: 'Your password has been changed',
template: emailTemplate,
});
}
}

View File

@ -100,12 +100,9 @@ export class GroupUserService {
this.db,
async (trx) => {
await this.groupService.findAndValidateGroup(groupId, workspaceId);
const user = await this.userRepo.findById(
userId,
workspaceId,
false,
trx,
);
const user = await this.userRepo.findById(userId, workspaceId, {
trx: trx,
});
if (!user) {
throw new NotFoundException('User not found');