2022-07-15 21:30:56 +02:00
|
|
|
import { UserEntity } from '@app/database/entities/user.entity';
|
|
|
|
|
import { BadRequestException } from '@nestjs/common';
|
|
|
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
|
|
|
import { Not, Repository } from 'typeorm';
|
|
|
|
|
import { CreateUserDto } from './dto/create-user.dto';
|
|
|
|
|
import * as bcrypt from 'bcrypt';
|
2022-10-23 16:54:54 -05:00
|
|
|
import { UpdateUserDto } from './dto/update-user.dto';
|
2022-07-15 21:30:56 +02:00
|
|
|
|
|
|
|
|
export interface IUserRepository {
|
2022-11-07 16:53:47 -05:00
|
|
|
get(userId: string, withDeleted?: boolean): Promise<UserEntity | null>;
|
2022-07-15 21:30:56 +02:00
|
|
|
getByEmail(email: string): Promise<UserEntity | null>;
|
|
|
|
|
getList(filter?: { excludeId?: string }): Promise<UserEntity[]>;
|
|
|
|
|
create(createUserDto: CreateUserDto): Promise<UserEntity>;
|
|
|
|
|
update(user: UserEntity, updateUserDto: UpdateUserDto): Promise<UserEntity>;
|
|
|
|
|
createProfileImage(user: UserEntity, fileInfo: Express.Multer.File): Promise<UserEntity>;
|
2022-11-07 16:53:47 -05:00
|
|
|
delete(user: UserEntity): Promise<UserEntity>;
|
|
|
|
|
restore(user: UserEntity): Promise<UserEntity>;
|
2022-07-15 21:30:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const USER_REPOSITORY = 'USER_REPOSITORY';
|
|
|
|
|
|
|
|
|
|
export class UserRepository implements IUserRepository {
|
|
|
|
|
constructor(
|
|
|
|
|
@InjectRepository(UserEntity)
|
|
|
|
|
private userRepository: Repository<UserEntity>,
|
|
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
private async hashPassword(password: string, salt: string): Promise<string> {
|
|
|
|
|
return bcrypt.hash(password, salt);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-07 16:53:47 -05:00
|
|
|
async get(userId: string, withDeleted?: boolean): Promise<UserEntity | null> {
|
|
|
|
|
return this.userRepository.findOne({ where: { id: userId }, withDeleted: withDeleted });
|
2022-07-15 21:30:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getByEmail(email: string): Promise<UserEntity | null> {
|
|
|
|
|
return this.userRepository.findOne({ where: { email } });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO add DTO for filtering
|
|
|
|
|
async getList({ excludeId }: { excludeId?: string } = {}): Promise<UserEntity[]> {
|
|
|
|
|
if (!excludeId) {
|
|
|
|
|
return this.userRepository.find(); // TODO: this should also be ordered the same as below
|
|
|
|
|
}
|
2022-11-07 16:53:47 -05:00
|
|
|
return this.userRepository
|
|
|
|
|
.find({
|
2022-07-15 21:30:56 +02:00
|
|
|
where: { id: Not(excludeId) },
|
2022-11-07 16:53:47 -05:00
|
|
|
withDeleted: true,
|
2022-07-15 21:30:56 +02:00
|
|
|
order: {
|
|
|
|
|
createdAt: 'DESC',
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async create(createUserDto: CreateUserDto): Promise<UserEntity> {
|
|
|
|
|
const newUser = new UserEntity();
|
|
|
|
|
newUser.email = createUserDto.email;
|
|
|
|
|
newUser.salt = await bcrypt.genSalt();
|
|
|
|
|
newUser.password = await this.hashPassword(createUserDto.password, newUser.salt);
|
|
|
|
|
newUser.firstName = createUserDto.firstName;
|
|
|
|
|
newUser.lastName = createUserDto.lastName;
|
|
|
|
|
newUser.isAdmin = false;
|
|
|
|
|
|
|
|
|
|
return this.userRepository.save(newUser);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async update(user: UserEntity, updateUserDto: UpdateUserDto): Promise<UserEntity> {
|
|
|
|
|
user.lastName = updateUserDto.lastName || user.lastName;
|
|
|
|
|
user.firstName = updateUserDto.firstName || user.firstName;
|
|
|
|
|
user.profileImagePath = updateUserDto.profileImagePath || user.profileImagePath;
|
|
|
|
|
user.shouldChangePassword =
|
|
|
|
|
updateUserDto.shouldChangePassword != undefined ? updateUserDto.shouldChangePassword : user.shouldChangePassword;
|
|
|
|
|
|
|
|
|
|
// If payload includes password - Create new password for user
|
|
|
|
|
if (updateUserDto.password) {
|
|
|
|
|
user.salt = await bcrypt.genSalt();
|
|
|
|
|
user.password = await this.hashPassword(updateUserDto.password, user.salt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: can this happen? If so we can move it to the service, otherwise remove it (also from DTO)
|
|
|
|
|
if (updateUserDto.isAdmin) {
|
|
|
|
|
const adminUser = await this.userRepository.findOne({ where: { isAdmin: true } });
|
|
|
|
|
|
|
|
|
|
if (adminUser) {
|
|
|
|
|
throw new BadRequestException('Admin user exists');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
user.isAdmin = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this.userRepository.save(user);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-07 16:53:47 -05:00
|
|
|
async delete(user: UserEntity): Promise<UserEntity> {
|
|
|
|
|
if (user.isAdmin) {
|
|
|
|
|
throw new BadRequestException('Cannot delete admin user! stay sane!');
|
|
|
|
|
}
|
|
|
|
|
return this.userRepository.softRemove(user);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async restore(user: UserEntity): Promise<UserEntity> {
|
|
|
|
|
return this.userRepository.recover(user);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-15 21:30:56 +02:00
|
|
|
async createProfileImage(user: UserEntity, fileInfo: Express.Multer.File): Promise<UserEntity> {
|
|
|
|
|
user.profileImagePath = fileInfo.path;
|
|
|
|
|
return this.userRepository.save(user);
|
|
|
|
|
}
|
2022-10-23 16:54:54 -05:00
|
|
|
}
|