feat(server): search by is favorite (#1400)

* feat(server): search by is favorite

* chore: regenerate api

* fix: boolean transform

* chore: remove console log

Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
Jason Rasmussen
2023-01-23 23:16:20 -05:00
committed by GitHub
parent eade36ee82
commit b7d34079d9
13 changed files with 123 additions and 63 deletions

View File

@@ -1,17 +1,11 @@
import { Transform } from 'class-transformer';
import { IsOptional, IsBoolean } from 'class-validator';
import { IsBoolean, IsOptional } from 'class-validator';
import { toBoolean } from '../../../utils/transform.util';
export class GetAlbumsDto {
@IsOptional()
@IsBoolean()
@Transform(({ value }) => {
if (value == 'true') {
return true;
} else if (value == 'false') {
return false;
}
return value;
})
@Transform(toBoolean)
/**
* true: only shared albums
* false: only non-shared own albums

View File

@@ -15,7 +15,8 @@ import { CheckExistingAssetsResponseDto } from './response-dto/check-existing-as
import { In } from 'typeorm/find-options/operator/In';
import { UpdateAssetDto } from './dto/update-asset.dto';
import { ITagRepository } from '../tag/tag.repository';
import { IsNull } from 'typeorm';
import { IsNull, Not } from 'typeorm';
import { AssetSearchDto } from './dto/asset-search.dto';
export interface IAssetRepository {
create(
@@ -28,7 +29,7 @@ export interface IAssetRepository {
livePhotoAssetEntity?: AssetEntity,
): Promise<AssetEntity>;
update(userId: string, asset: AssetEntity, dto: UpdateAssetDto): Promise<AssetEntity>;
getAllByUserId(userId: string, skip?: number): Promise<AssetEntity[]>;
getAllByUserId(userId: string, dto: AssetSearchDto): Promise<AssetEntity[]>;
getAllByDeviceId(userId: string, deviceId: string): Promise<string[]>;
getById(assetId: string): Promise<AssetEntity>;
getLocationsByUserId(userId: string): Promise<CuratedLocationsResponseDto[]>;
@@ -244,17 +245,23 @@ export class AssetRepository implements IAssetRepository {
* Get all assets belong to the user on the database
* @param userId
*/
async getAllByUserId(userId: string, skip?: number): Promise<AssetEntity[]> {
const query = this.assetRepository
.createQueryBuilder('asset')
.where('asset.userId = :userId', { userId: userId })
.andWhere('asset.resizePath is not NULL')
.andWhere('asset.isVisible = true')
.leftJoinAndSelect('asset.exifInfo', 'exifInfo')
.leftJoinAndSelect('asset.tags', 'tags')
.skip(skip || 0)
.orderBy('asset.createdAt', 'DESC');
return await query.getMany();
async getAllByUserId(userId: string, dto: AssetSearchDto): Promise<AssetEntity[]> {
return this.assetRepository.find({
where: {
userId,
resizePath: Not(IsNull()),
isVisible: true,
isFavorite: dto.isFavorite,
},
relations: {
exifInfo: true,
tags: true,
},
skip: dto.skip || 0,
order: {
createdAt: 'DESC',
},
});
}
/**

View File

@@ -54,6 +54,7 @@ import { DownloadFilesDto } from './dto/download-files.dto';
import { CreateAssetsShareLinkDto } from './dto/create-asset-shared-link.dto';
import { SharedLinkResponseDto } from '../share/response-dto/shared-link-response.dto';
import { UpdateAssetsToSharedLinkDto } from './dto/add-assets-to-shared-link.dto';
import { AssetSearchDto } from './dto/asset-search.dto';
@ApiBearerAuth()
@ApiTags('Asset')
@@ -219,9 +220,11 @@ export class AssetController {
required: false,
schema: { type: 'string' },
})
async getAllAssets(@GetAuthUser() authUser: AuthUserDto): Promise<AssetResponseDto[]> {
const assets = await this.assetService.getAllAssets(authUser);
return assets;
getAllAssets(
@GetAuthUser() authUser: AuthUserDto,
@Query(new ValidationPipe({ transform: true })) dto: AssetSearchDto,
): Promise<AssetResponseDto[]> {
return this.assetService.getAllAssets(authUser, dto);
}
@Authenticated()

View File

@@ -54,6 +54,7 @@ import { DownloadFilesDto } from './dto/download-files.dto';
import { CreateAssetsShareLinkDto } from './dto/create-asset-shared-link.dto';
import { mapSharedLink, SharedLinkResponseDto } from '../share/response-dto/shared-link-response.dto';
import { UpdateAssetsToSharedLinkDto } from './dto/add-assets-to-shared-link.dto';
import { AssetSearchDto } from './dto/asset-search.dto';
const fileInfo = promisify(stat);
@@ -200,8 +201,8 @@ export class AssetService {
return this._assetRepository.getAllByDeviceId(authUser.id, deviceId);
}
public async getAllAssets(authUser: AuthUserDto): Promise<AssetResponseDto[]> {
const assets = await this._assetRepository.getAllByUserId(authUser.id);
public async getAllAssets(authUser: AuthUserDto, dto: AssetSearchDto): Promise<AssetResponseDto[]> {
const assets = await this._assetRepository.getAllByUserId(authUser.id, dto);
return assets.map((asset) => mapAsset(asset));
}
@@ -238,7 +239,7 @@ export class AssetService {
}
public async downloadLibrary(user: AuthUserDto, dto: DownloadDto) {
const assets = await this._assetRepository.getAllByUserId(user.id, dto.skip);
const assets = await this._assetRepository.getAllByUserId(user.id, dto);
return this.downloadService.downloadArchive(dto.name || `library`, assets);
}

View File

@@ -0,0 +1,15 @@
import { Transform } from 'class-transformer';
import { IsBoolean, IsNotEmpty, IsNumber, IsOptional } from 'class-validator';
import { toBoolean } from '../../../utils/transform.util';
export class AssetSearchDto {
@IsOptional()
@IsNotEmpty()
@IsBoolean()
@Transform(toBoolean)
isFavorite?: boolean;
@IsOptional()
@IsNumber()
skip?: number;
}

View File

@@ -1,6 +0,0 @@
import { IsNotEmpty } from 'class-validator';
export class GetAssetDto {
@IsNotEmpty()
deviceId!: string;
}

View File

@@ -1,31 +1,18 @@
import { ApiProperty } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
import { IsBoolean, IsOptional } from 'class-validator';
import { toBoolean } from '../../../utils/transform.util';
export class ServeFileDto {
@IsOptional()
@IsBoolean()
@Transform(({ value }) => {
if (value == 'true') {
return true;
} else if (value == 'false') {
return false;
}
return value;
})
@Transform(toBoolean)
@ApiProperty({ type: Boolean, title: 'Is serve thumbnail (resize) file' })
isThumb?: boolean;
@IsOptional()
@IsBoolean()
@Transform(({ value }) => {
if (value == 'true') {
return true;
} else if (value == 'false') {
return false;
}
return value;
})
@Transform(toBoolean)
@ApiProperty({ type: Boolean, title: 'Is request made from web' })
isWeb?: boolean;
}

View File

@@ -0,0 +1,8 @@
export const toBoolean = ({ value }: { value: string }) => {
if (value == 'true') {
return true;
} else if (value == 'false') {
return false;
}
return value;
};

View File

@@ -1352,6 +1352,22 @@
"operationId": "getAllAssets",
"description": "Get all AssetEntity belong to the user",
"parameters": [
{
"name": "isFavorite",
"required": false,
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "skip",
"required": false,
"in": "query",
"schema": {
"type": "number"
}
},
{
"name": "if-none-match",
"in": "header",