import { IUserRepository, UserFindOptions, UserListFilter, UserStatsQueryResponse } from '@app/domain'; import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { IsNull, Not, Repository } from 'typeorm'; import { UserEntity } from '../entities'; @Injectable() export class UserRepository implements IUserRepository { constructor(@InjectRepository(UserEntity) private userRepository: Repository) {} async get(userId: string, options: UserFindOptions): Promise { options = options || {}; return this.userRepository.findOne({ where: { id: userId }, withDeleted: options.withDeleted, }); } async getAdmin(): Promise { return this.userRepository.findOne({ where: { isAdmin: true } }); } async hasAdmin(): Promise { return this.userRepository.exist({ where: { isAdmin: true } }); } async getByEmail(email: string, withPassword?: boolean): Promise { let builder = this.userRepository.createQueryBuilder('user').where({ email }); if (withPassword) { builder = builder.addSelect('user.password'); } return builder.getOne(); } async getByStorageLabel(storageLabel: string): Promise { return this.userRepository.findOne({ where: { storageLabel } }); } async getByOAuthId(oauthId: string): Promise { return this.userRepository.findOne({ where: { oauthId } }); } async getDeletedUsers(): Promise { return this.userRepository.find({ withDeleted: true, where: { deletedAt: Not(IsNull()) } }); } async getList({ withDeleted }: UserListFilter = {}): Promise { return this.userRepository.find({ withDeleted, order: { createdAt: 'DESC', }, }); } create(user: Partial): Promise { return this.save(user); } // TODO change to (user: Partial) update(id: string, user: Partial): Promise { return this.save({ ...user, id }); } async delete(user: UserEntity, hard?: boolean): Promise { if (hard) { return this.userRepository.remove(user); } else { return this.userRepository.softRemove(user); } } async restore(user: UserEntity): Promise { return this.userRepository.recover(user); } async getUserStats(): Promise { const stats = await this.userRepository .createQueryBuilder('users') .select('users.id', 'userId') .addSelect('users.name', 'userName') .addSelect(`COUNT(assets.id) FILTER (WHERE assets.type = 'IMAGE' AND assets.isVisible)`, 'photos') .addSelect(`COUNT(assets.id) FILTER (WHERE assets.type = 'VIDEO' AND assets.isVisible)`, 'videos') .addSelect('COALESCE(SUM(exif.fileSizeInByte), 0)', 'usage') .leftJoin('users.assets', 'assets') .leftJoin('assets.exifInfo', 'exif') .groupBy('users.id') .orderBy('users.createdAt', 'ASC') .getRawMany(); for (const stat of stats) { stat.photos = Number(stat.photos); stat.videos = Number(stat.videos); stat.usage = Number(stat.usage); } return stats; } private async save(user: Partial) { const { id } = await this.userRepository.save(user); return this.userRepository.findOneByOrFail({ id }); } }