hunk.code_window: export class ServerInfoDto {
     diskSize: String;
     diskUse: String;
     diskAvailable: String;
     diskSizeRaw: number;
     diskUseRaw: number;
     diskAvailableRaw: number;
  
hunk.labels: keep replace replace replace keep keep keep
hunk.after_edit:   diskSize: string;
     diskUse: string;
     diskAvailable: string;
  
hunk.file_path: server/apps/immich/src/api-v1/server-info/dto/server-info.dto.ts
hunk.type: replace
file: import { BadRequestException, Injectable, InternalServerErrorException, Logger } from '@nestjs/common';
  import { InjectRepository } from '@nestjs/typeorm';
  import { Repository } from 'typeorm';
  import { UserEntity } from '@app/database/entities/user.entity';
  import { LoginCredentialDto } from './dto/login-credential.dto';
  import { ImmichJwtService } from '../../modules/immich-jwt/immich-jwt.service';
  import { JwtPayloadDto } from './dto/jwt-payload.dto';
  import { SignUpDto } from './dto/sign-up.dto';
  import * as bcrypt from 'bcrypt';
  import { mapUser, User } from '../user/response-dto/user';
  
  @Injectable()
  export class AuthService {
    constructor(
      @InjectRepository(UserEntity)
      private userRepository: Repository<UserEntity>,
      private immichJwtService: ImmichJwtService,
    ) {}
  
    private async validateUser(loginCredential: LoginCredentialDto): Promise<UserEntity> {
      const user = await this.userRepository.findOne(
        { email: loginCredential.email },
        {
          select: [
            'id',
            'email',
            'password',
            'salt',
            'firstName',
            'lastName',
            'isAdmin',
            'profileImagePath',
            'isFirstLoggedIn',
          ],
        },
      );
  
      const isAuthenticated = await this.validatePassword(user.password, loginCredential.password, user.salt);
  
      if (user && isAuthenticated) {
        return user;
      }
  
      return null;
    }
  
    public async login(loginCredential: LoginCredentialDto) {
      const validatedUser = await this.validateUser(loginCredential);
  
      if (!validatedUser) {
        throw new BadRequestException('Incorrect email or password');
      }
  
      const payload = new JwtPayloadDto(validatedUser.id, validatedUser.email);
  
      return {
        accessToken: await this.immichJwtService.generateToken(payload),
        userId: validatedUser.id,
        userEmail: validatedUser.email,
        firstName: validatedUser.firstName,
        lastName: validatedUser.lastName,
        isAdmin: validatedUser.isAdmin,
        profileImagePath: validatedUser.profileImagePath,
        isFirstLogin: validatedUser.isFirstLoggedIn,
      };
    }
  
    public async adminSignUp(signUpCredential: SignUpDto): Promise<User> {
      const adminUser = await this.userRepository.findOne({ where: { isAdmin: true } });
  
      if (adminUser) {
        throw new BadRequestException('The server already has an admin');
      }
  
      const newAdminUser = new UserEntity();
      newAdminUser.email = signUpCredential.email;
      newAdminUser.salt = await bcrypt.genSalt();
      newAdminUser.password = await this.hashPassword(signUpCredential.password, newAdminUser.salt);
      newAdminUser.firstName = signUpCredential.firstName;
      newAdminUser.lastName = signUpCredential.lastName;
      newAdminUser.isAdmin = true;
  
      try {
        const savedNewAdminUserUser = await this.userRepository.save(newAdminUser);
  
        return mapUser(savedNewAdminUserUser);
      } catch (e) {
        Logger.error('e', 'signUp');
        throw new InternalServerErrorException('Failed to register new admin user');
      }
    }
  
    private async hashPassword(password: string, salt: string): Promise<string> {
      return bcrypt.hash(password, salt);
    }
  
    private async validatePassword(hasedPassword: string, inputPassword: string, salt: string): Promise<boolean> {
      const hash = await bcrypt.hash(inputPassword, salt);
      return hash === hasedPassword;
    }
  }
  