mirror of https://github.com/immich-app/immich.git
parent
0c13c63bb6
commit
6d9e7694b1
@ -1,8 +0,0 @@
|
||||
import { ArrayNotEmpty } from 'class-validator';
|
||||
import { ValidateUUID } from 'src/validation';
|
||||
|
||||
export class AddUsersDto {
|
||||
@ValidateUUID({ each: true })
|
||||
@ArrayNotEmpty()
|
||||
sharedUserIds!: string[];
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString } from 'class-validator';
|
||||
import { Optional, ValidateUUID } from 'src/validation';
|
||||
|
||||
export class CreateAlbumDto {
|
||||
@IsString()
|
||||
@ApiProperty()
|
||||
albumName!: string;
|
||||
|
||||
@IsString()
|
||||
@Optional()
|
||||
description?: string;
|
||||
|
||||
@ValidateUUID({ optional: true, each: true })
|
||||
sharedWithUserIds?: string[];
|
||||
|
||||
@ValidateUUID({ optional: true, each: true })
|
||||
assetIds?: string[];
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEnum, IsString } from 'class-validator';
|
||||
import { AssetOrder } from 'src/entities/album.entity';
|
||||
import { Optional, ValidateBoolean, ValidateUUID } from 'src/validation';
|
||||
|
||||
export class UpdateAlbumDto {
|
||||
@Optional()
|
||||
@IsString()
|
||||
albumName?: string;
|
||||
|
||||
@Optional()
|
||||
@IsString()
|
||||
description?: string;
|
||||
|
||||
@ValidateUUID({ optional: true })
|
||||
albumThumbnailAssetId?: string;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
isActivityEnabled?: boolean;
|
||||
|
||||
@IsEnum(AssetOrder)
|
||||
@Optional()
|
||||
@ApiProperty({ enum: AssetOrder, enumName: 'AssetOrder' })
|
||||
order?: AssetOrder;
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
import { ValidateBoolean } from 'src/validation';
|
||||
|
||||
export class AlbumInfoDto {
|
||||
@ValidateBoolean({ optional: true })
|
||||
withoutAssets?: boolean;
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
import { ValidateBoolean, ValidateUUID } from 'src/validation';
|
||||
|
||||
export class GetAlbumsDto {
|
||||
@ValidateBoolean({ optional: true })
|
||||
/**
|
||||
* true: only shared albums
|
||||
* false: only non-shared own albums
|
||||
* undefined: shared and owned albums
|
||||
*/
|
||||
shared?: boolean;
|
||||
|
||||
/**
|
||||
* Only returns albums that contain the asset
|
||||
* Ignores the shared parameter
|
||||
* undefined: get all albums
|
||||
*/
|
||||
@ValidateUUID({ optional: true })
|
||||
assetId?: string;
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEnum } from 'class-validator';
|
||||
import { ValidateUUID } from 'src/validation';
|
||||
|
||||
export class AssetIdsDto {
|
||||
@ValidateUUID({ each: true })
|
||||
assetIds!: string[];
|
||||
}
|
||||
|
||||
export enum AssetJobName {
|
||||
REGENERATE_THUMBNAIL = 'regenerate-thumbnail',
|
||||
REFRESH_METADATA = 'refresh-metadata',
|
||||
TRANSCODE_VIDEO = 'transcode-video',
|
||||
}
|
||||
|
||||
export class AssetJobsDto extends AssetIdsDto {
|
||||
@ApiProperty({ enumName: 'AssetJobName', enum: AssetJobName })
|
||||
@IsEnum(AssetJobName)
|
||||
name!: AssetJobName;
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { AssetType } from 'src/entities/asset.entity';
|
||||
import { AssetStats } from 'src/interfaces/asset.repository';
|
||||
import { ValidateBoolean } from 'src/validation';
|
||||
|
||||
export class AssetStatsDto {
|
||||
@ValidateBoolean({ optional: true })
|
||||
isArchived?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
isFavorite?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
isTrashed?: boolean;
|
||||
}
|
||||
|
||||
export class AssetStatsResponseDto {
|
||||
@ApiProperty({ type: 'integer' })
|
||||
images!: number;
|
||||
|
||||
@ApiProperty({ type: 'integer' })
|
||||
videos!: number;
|
||||
|
||||
@ApiProperty({ type: 'integer' })
|
||||
total!: number;
|
||||
}
|
||||
|
||||
export const mapStats = (stats: AssetStats): AssetStatsResponseDto => {
|
||||
return {
|
||||
images: stats[AssetType.IMAGE],
|
||||
videos: stats[AssetType.VIDEO],
|
||||
total: Object.values(stats).reduce((total, value) => total + value, 0),
|
||||
};
|
||||
};
|
||||
@ -1,75 +0,0 @@
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsDateString,
|
||||
IsInt,
|
||||
IsLatitude,
|
||||
IsLongitude,
|
||||
IsNotEmpty,
|
||||
IsPositive,
|
||||
IsString,
|
||||
ValidateIf,
|
||||
} from 'class-validator';
|
||||
import { BulkIdsDto } from 'src/domain/asset/response-dto/asset-ids-response.dto';
|
||||
import { Optional, ValidateBoolean, ValidateUUID } from 'src/validation';
|
||||
|
||||
export class DeviceIdDto {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
deviceId!: string;
|
||||
}
|
||||
|
||||
const hasGPS = (o: { latitude: undefined; longitude: undefined }) =>
|
||||
o.latitude !== undefined || o.longitude !== undefined;
|
||||
const ValidateGPS = () => ValidateIf(hasGPS);
|
||||
|
||||
export class UpdateAssetBase {
|
||||
@ValidateBoolean({ optional: true })
|
||||
isFavorite?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
isArchived?: boolean;
|
||||
|
||||
@Optional()
|
||||
@IsDateString()
|
||||
dateTimeOriginal?: string;
|
||||
|
||||
@ValidateGPS()
|
||||
@IsLatitude()
|
||||
@IsNotEmpty()
|
||||
latitude?: number;
|
||||
|
||||
@ValidateGPS()
|
||||
@IsLongitude()
|
||||
@IsNotEmpty()
|
||||
longitude?: number;
|
||||
}
|
||||
|
||||
export class AssetBulkUpdateDto extends UpdateAssetBase {
|
||||
@ValidateUUID({ each: true })
|
||||
ids!: string[];
|
||||
|
||||
@ValidateUUID({ optional: true })
|
||||
stackParentId?: string;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
removeParent?: boolean;
|
||||
}
|
||||
|
||||
export class UpdateAssetDto extends UpdateAssetBase {
|
||||
@Optional()
|
||||
@IsString()
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export class RandomAssetsDto {
|
||||
@Optional()
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
@Type(() => Number)
|
||||
count?: number;
|
||||
}
|
||||
|
||||
export class AssetBulkDeleteDto extends BulkIdsDto {
|
||||
@ValidateBoolean({ optional: true })
|
||||
force?: boolean;
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
import { ValidateBoolean, ValidateDate } from 'src/validation';
|
||||
|
||||
export class MapMarkerDto {
|
||||
@ValidateBoolean({ optional: true })
|
||||
isArchived?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
isFavorite?: boolean;
|
||||
|
||||
@ValidateDate({ optional: true })
|
||||
fileCreatedAfter?: Date;
|
||||
|
||||
@ValidateDate({ optional: true })
|
||||
fileCreatedBefore?: Date;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
withPartners?: boolean;
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import { IsInt, Max, Min } from 'class-validator';
|
||||
|
||||
export class MemoryLaneDto {
|
||||
@IsInt()
|
||||
@Type(() => Number)
|
||||
@Max(31)
|
||||
@Min(1)
|
||||
@ApiProperty({ type: 'integer' })
|
||||
day!: number;
|
||||
|
||||
@IsInt()
|
||||
@Type(() => Number)
|
||||
@Max(12)
|
||||
@Min(1)
|
||||
@ApiProperty({ type: 'integer' })
|
||||
month!: number;
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class MapMarkerResponseDto {
|
||||
@ApiProperty()
|
||||
id!: string;
|
||||
|
||||
@ApiProperty({ format: 'double' })
|
||||
lat!: number;
|
||||
|
||||
@ApiProperty({ format: 'double' })
|
||||
lon!: number;
|
||||
|
||||
@ApiProperty()
|
||||
city!: string | null;
|
||||
|
||||
@ApiProperty()
|
||||
state!: string | null;
|
||||
|
||||
@ApiProperty()
|
||||
country!: string | null;
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
import { SmartInfoEntity } from 'src/entities/smart-info.entity';
|
||||
|
||||
export class SmartInfoResponseDto {
|
||||
tags?: string[] | null;
|
||||
objects?: string[] | null;
|
||||
}
|
||||
|
||||
export function mapSmartInfo(entity: SmartInfoEntity): SmartInfoResponseDto {
|
||||
return {
|
||||
tags: entity.tags,
|
||||
objects: entity.objects,
|
||||
};
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class TimeBucketResponseDto {
|
||||
@ApiProperty({ type: 'string' })
|
||||
timeBucket!: string;
|
||||
|
||||
@ApiProperty({ type: 'integer' })
|
||||
count!: number;
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
|
||||
import { Optional } from 'src/validation';
|
||||
|
||||
export enum SearchSuggestionType {
|
||||
COUNTRY = 'country',
|
||||
STATE = 'state',
|
||||
CITY = 'city',
|
||||
CAMERA_MAKE = 'camera-make',
|
||||
CAMERA_MODEL = 'camera-model',
|
||||
}
|
||||
|
||||
export class SearchSuggestionRequestDto {
|
||||
@IsEnum(SearchSuggestionType)
|
||||
@IsNotEmpty()
|
||||
@ApiProperty({ enumName: 'SearchSuggestionType', enum: SearchSuggestionType })
|
||||
type!: SearchSuggestionType;
|
||||
|
||||
@IsString()
|
||||
@Optional()
|
||||
country?: string;
|
||||
|
||||
@IsString()
|
||||
@Optional()
|
||||
state?: string;
|
||||
|
||||
@IsString()
|
||||
@Optional()
|
||||
make?: string;
|
||||
|
||||
@IsString()
|
||||
@Optional()
|
||||
model?: string;
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
import { AssetResponseDto } from 'src/domain/asset/response-dto/asset-response.dto';
|
||||
|
||||
class SearchExploreItem {
|
||||
value!: string;
|
||||
data!: AssetResponseDto;
|
||||
}
|
||||
|
||||
export class SearchExploreResponseDto {
|
||||
fieldName!: string;
|
||||
items!: SearchExploreItem[];
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { AlbumResponseDto } from 'src/domain/album/album-response.dto';
|
||||
import { AssetResponseDto } from 'src/domain/asset/response-dto/asset-response.dto';
|
||||
|
||||
class SearchFacetCountResponseDto {
|
||||
@ApiProperty({ type: 'integer' })
|
||||
count!: number;
|
||||
value!: string;
|
||||
}
|
||||
|
||||
class SearchFacetResponseDto {
|
||||
fieldName!: string;
|
||||
counts!: SearchFacetCountResponseDto[];
|
||||
}
|
||||
|
||||
class SearchAlbumResponseDto {
|
||||
@ApiProperty({ type: 'integer' })
|
||||
total!: number;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
count!: number;
|
||||
items!: AlbumResponseDto[];
|
||||
facets!: SearchFacetResponseDto[];
|
||||
}
|
||||
|
||||
class SearchAssetResponseDto {
|
||||
@ApiProperty({ type: 'integer' })
|
||||
total!: number;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
count!: number;
|
||||
items!: AssetResponseDto[];
|
||||
facets!: SearchFacetResponseDto[];
|
||||
nextPage!: string | null;
|
||||
}
|
||||
|
||||
export class SearchResponseDto {
|
||||
albums!: SearchAlbumResponseDto;
|
||||
assets!: SearchAssetResponseDto;
|
||||
}
|
||||
@ -1,75 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEnum, IsString } from 'class-validator';
|
||||
import { SharedLinkType } from 'src/entities/shared-link.entity';
|
||||
import { Optional, ValidateBoolean, ValidateDate, ValidateUUID } from 'src/validation';
|
||||
|
||||
export class SharedLinkCreateDto {
|
||||
@IsEnum(SharedLinkType)
|
||||
@ApiProperty({ enum: SharedLinkType, enumName: 'SharedLinkType' })
|
||||
type!: SharedLinkType;
|
||||
|
||||
@ValidateUUID({ each: true, optional: true })
|
||||
assetIds?: string[];
|
||||
|
||||
@ValidateUUID({ optional: true })
|
||||
albumId?: string;
|
||||
|
||||
@IsString()
|
||||
@Optional()
|
||||
description?: string;
|
||||
|
||||
@IsString()
|
||||
@Optional()
|
||||
password?: string;
|
||||
|
||||
@ValidateDate({ optional: true, nullable: true })
|
||||
expiresAt?: Date | null = null;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
allowUpload?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
allowDownload?: boolean = true;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
showMetadata?: boolean = true;
|
||||
}
|
||||
|
||||
export class SharedLinkEditDto {
|
||||
@Optional()
|
||||
description?: string;
|
||||
|
||||
@Optional()
|
||||
password?: string;
|
||||
|
||||
@Optional({ nullable: true })
|
||||
expiresAt?: Date | null;
|
||||
|
||||
@Optional()
|
||||
allowUpload?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
allowDownload?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
showMetadata?: boolean;
|
||||
|
||||
/**
|
||||
* Few clients cannot send null to set the expiryTime to never.
|
||||
* Setting this flag and not sending expiryAt is considered as null instead.
|
||||
* Clients that can send null values can ignore this.
|
||||
*/
|
||||
@ValidateBoolean({ optional: true })
|
||||
changeExpiryTime?: boolean;
|
||||
}
|
||||
|
||||
export class SharedLinkPasswordDto {
|
||||
@IsString()
|
||||
@Optional()
|
||||
@ApiProperty({ example: 'password' })
|
||||
password?: string;
|
||||
|
||||
@IsString()
|
||||
@Optional()
|
||||
token?: string;
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
export class SystemConfigTemplateStorageOptionDto {
|
||||
yearOptions!: string[];
|
||||
monthOptions!: string[];
|
||||
weekOptions!: string[];
|
||||
dayOptions!: string[];
|
||||
hourOptions!: string[];
|
||||
minuteOptions!: string[];
|
||||
secondOptions!: string[];
|
||||
presetOptions!: string[];
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
|
||||
import { TagType } from 'src/entities/tag.entity';
|
||||
import { Optional } from 'src/validation';
|
||||
|
||||
export class CreateTagDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
name!: string;
|
||||
|
||||
@IsEnum(TagType)
|
||||
@IsNotEmpty()
|
||||
@ApiProperty({ enumName: 'TagTypeEnum', enum: TagType })
|
||||
type!: TagType;
|
||||
}
|
||||
|
||||
export class UpdateTagDto {
|
||||
@IsString()
|
||||
@Optional()
|
||||
name?: string;
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { UploadFieldName } from 'src/domain/asset/asset.service';
|
||||
|
||||
export class CreateProfileImageDto {
|
||||
@ApiProperty({ type: 'string', format: 'binary' })
|
||||
[UploadFieldName.PROFILE_DATA]!: Express.Multer.File;
|
||||
}
|
||||
@ -1,61 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
import { IsEmail, IsNotEmpty, IsNumber, IsPositive, IsString } from 'class-validator';
|
||||
import { Optional, ValidateBoolean, toEmail, toSanitized } from 'src/validation';
|
||||
|
||||
export class CreateUserDto {
|
||||
@IsEmail({ require_tld: false })
|
||||
@Transform(toEmail)
|
||||
email!: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
password!: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
name!: string;
|
||||
|
||||
@Optional({ nullable: true })
|
||||
@IsString()
|
||||
@Transform(toSanitized)
|
||||
storageLabel?: string | null;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
memoriesEnabled?: boolean;
|
||||
|
||||
@Optional({ nullable: true })
|
||||
@IsNumber()
|
||||
@IsPositive()
|
||||
@ApiProperty({ type: 'integer', format: 'int64' })
|
||||
quotaSizeInBytes?: number | null;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
shouldChangePassword?: boolean;
|
||||
}
|
||||
|
||||
export class CreateAdminDto {
|
||||
@IsNotEmpty()
|
||||
isAdmin!: true;
|
||||
|
||||
@IsEmail({ require_tld: false })
|
||||
@Transform(({ value }) => value?.toLowerCase())
|
||||
email!: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
password!: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
name!: string;
|
||||
}
|
||||
|
||||
export class CreateUserOAuthDto {
|
||||
@IsEmail({ require_tld: false })
|
||||
@Transform(({ value }) => value?.toLowerCase())
|
||||
email!: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
oauthId!: string;
|
||||
|
||||
name?: string;
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
import { ValidateBoolean } from 'src/validation';
|
||||
|
||||
export class DeleteUserDto {
|
||||
@ValidateBoolean({ optional: true })
|
||||
force?: boolean;
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import { UpdateUserDto } from 'src/domain/user/dto/update-user.dto';
|
||||
|
||||
describe('update user DTO', () => {
|
||||
it('should allow emails without a tld', async () => {
|
||||
const someEmail = 'test@test';
|
||||
|
||||
const dto = plainToInstance(UpdateUserDto, {
|
||||
email: someEmail,
|
||||
id: '3fe388e4-2078-44d7-b36c-39d9dee3a657',
|
||||
});
|
||||
const errors = await validate(dto);
|
||||
expect(errors).toHaveLength(0);
|
||||
expect(dto.email).toEqual(someEmail);
|
||||
});
|
||||
});
|
||||
@ -1,52 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
import { IsEmail, IsEnum, IsNotEmpty, IsNumber, IsPositive, IsString, IsUUID } from 'class-validator';
|
||||
import { UserAvatarColor } from 'src/entities/user.entity';
|
||||
import { Optional, ValidateBoolean, toEmail, toSanitized } from 'src/validation';
|
||||
|
||||
export class UpdateUserDto {
|
||||
@Optional()
|
||||
@IsEmail({ require_tld: false })
|
||||
@Transform(toEmail)
|
||||
email?: string;
|
||||
|
||||
@Optional()
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
password?: string;
|
||||
|
||||
@Optional()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
name?: string;
|
||||
|
||||
@Optional()
|
||||
@IsString()
|
||||
@Transform(toSanitized)
|
||||
storageLabel?: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsUUID('4')
|
||||
@ApiProperty({ format: 'uuid' })
|
||||
id!: string;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
isAdmin?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
shouldChangePassword?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
memoriesEnabled?: boolean;
|
||||
|
||||
@Optional()
|
||||
@IsEnum(UserAvatarColor)
|
||||
@ApiProperty({ enumName: 'UserAvatarColor', enum: UserAvatarColor })
|
||||
avatarColor?: UserAvatarColor;
|
||||
|
||||
@Optional({ nullable: true })
|
||||
@IsNumber()
|
||||
@IsPositive()
|
||||
@ApiProperty({ type: 'integer', format: 'int64' })
|
||||
quotaSizeInBytes?: number | null;
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
export class CreateProfileImageResponseDto {
|
||||
userId!: string;
|
||||
profileImagePath!: string;
|
||||
}
|
||||
|
||||
export function mapCreateProfileImageResponse(userId: string, profileImagePath: string): CreateProfileImageResponseDto {
|
||||
return {
|
||||
userId: userId,
|
||||
profileImagePath: profileImagePath,
|
||||
};
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEnum } from 'class-validator';
|
||||
import { UserAvatarColor, UserEntity, UserStatus } from 'src/entities/user.entity';
|
||||
|
||||
export const getRandomAvatarColor = (user: UserEntity): UserAvatarColor => {
|
||||
const values = Object.values(UserAvatarColor);
|
||||
const randomIndex = Math.floor(
|
||||
[...user.email].map((letter) => letter.codePointAt(0) ?? 0).reduce((a, b) => a + b, 0) % values.length,
|
||||
);
|
||||
return values[randomIndex] as UserAvatarColor;
|
||||
};
|
||||
|
||||
export class UserDto {
|
||||
id!: string;
|
||||
name!: string;
|
||||
email!: string;
|
||||
profileImagePath!: string;
|
||||
@IsEnum(UserAvatarColor)
|
||||
@ApiProperty({ enumName: 'UserAvatarColor', enum: UserAvatarColor })
|
||||
avatarColor!: UserAvatarColor;
|
||||
}
|
||||
|
||||
export class UserResponseDto extends UserDto {
|
||||
storageLabel!: string | null;
|
||||
shouldChangePassword!: boolean;
|
||||
isAdmin!: boolean;
|
||||
createdAt!: Date;
|
||||
deletedAt!: Date | null;
|
||||
updatedAt!: Date;
|
||||
oauthId!: string;
|
||||
memoriesEnabled?: boolean;
|
||||
@ApiProperty({ type: 'integer', format: 'int64' })
|
||||
quotaSizeInBytes!: number | null;
|
||||
@ApiProperty({ type: 'integer', format: 'int64' })
|
||||
quotaUsageInBytes!: number | null;
|
||||
@ApiProperty({ enumName: 'UserStatus', enum: UserStatus })
|
||||
status!: string;
|
||||
}
|
||||
|
||||
export const mapSimpleUser = (entity: UserEntity): UserDto => {
|
||||
return {
|
||||
id: entity.id,
|
||||
email: entity.email,
|
||||
name: entity.name,
|
||||
profileImagePath: entity.profileImagePath,
|
||||
avatarColor: entity.avatarColor ?? getRandomAvatarColor(entity),
|
||||
};
|
||||
};
|
||||
|
||||
export function mapUser(entity: UserEntity): UserResponseDto {
|
||||
return {
|
||||
...mapSimpleUser(entity),
|
||||
storageLabel: entity.storageLabel,
|
||||
shouldChangePassword: entity.shouldChangePassword,
|
||||
isAdmin: entity.isAdmin,
|
||||
createdAt: entity.createdAt,
|
||||
deletedAt: entity.deletedAt,
|
||||
updatedAt: entity.updatedAt,
|
||||
oauthId: entity.oauthId,
|
||||
memoriesEnabled: entity.memoriesEnabled,
|
||||
quotaSizeInBytes: entity.quotaSizeInBytes,
|
||||
quotaUsageInBytes: entity.quotaUsageInBytes,
|
||||
status: entity.status,
|
||||
};
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEnum, IsNotEmpty, IsString, ValidateIf } from 'class-validator';
|
||||
import { UserDto, mapSimpleUser } from 'src/domain/user/response-dto/user-response.dto';
|
||||
import { UserDto, mapSimpleUser } from 'src/dtos/user.dto';
|
||||
import { ActivityEntity } from 'src/entities/activity.entity';
|
||||
import { Optional, ValidateUUID } from 'src/validation';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { mapAlbum } from 'src/domain/album/album-response.dto';
|
||||
import { mapAlbum } from 'src/dtos/album.dto';
|
||||
import { albumStub } from 'test/fixtures/album.stub';
|
||||
|
||||
describe('mapAlbum', () => {
|
||||
@ -0,0 +1,132 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsDateString,
|
||||
IsEnum,
|
||||
IsInt,
|
||||
IsLatitude,
|
||||
IsLongitude,
|
||||
IsNotEmpty,
|
||||
IsPositive,
|
||||
IsString,
|
||||
ValidateIf,
|
||||
} from 'class-validator';
|
||||
import { BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
|
||||
import { AssetType } from 'src/entities/asset.entity';
|
||||
import { AssetStats } from 'src/interfaces/asset.repository';
|
||||
import { Optional, ValidateBoolean, ValidateUUID } from 'src/validation';
|
||||
|
||||
export class DeviceIdDto {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
deviceId!: string;
|
||||
}
|
||||
|
||||
const hasGPS = (o: { latitude: undefined; longitude: undefined }) =>
|
||||
o.latitude !== undefined || o.longitude !== undefined;
|
||||
const ValidateGPS = () => ValidateIf(hasGPS);
|
||||
|
||||
export class UpdateAssetBase {
|
||||
@ValidateBoolean({ optional: true })
|
||||
isFavorite?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
isArchived?: boolean;
|
||||
|
||||
@Optional()
|
||||
@IsDateString()
|
||||
dateTimeOriginal?: string;
|
||||
|
||||
@ValidateGPS()
|
||||
@IsLatitude()
|
||||
@IsNotEmpty()
|
||||
latitude?: number;
|
||||
|
||||
@ValidateGPS()
|
||||
@IsLongitude()
|
||||
@IsNotEmpty()
|
||||
longitude?: number;
|
||||
}
|
||||
|
||||
export class AssetBulkUpdateDto extends UpdateAssetBase {
|
||||
@ValidateUUID({ each: true })
|
||||
ids!: string[];
|
||||
|
||||
@ValidateUUID({ optional: true })
|
||||
stackParentId?: string;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
removeParent?: boolean;
|
||||
}
|
||||
|
||||
export class UpdateAssetDto extends UpdateAssetBase {
|
||||
@Optional()
|
||||
@IsString()
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export class RandomAssetsDto {
|
||||
@Optional()
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
@Type(() => Number)
|
||||
count?: number;
|
||||
}
|
||||
|
||||
export class AssetBulkDeleteDto extends BulkIdsDto {
|
||||
@ValidateBoolean({ optional: true })
|
||||
force?: boolean;
|
||||
}
|
||||
|
||||
export class AssetIdsDto {
|
||||
@ValidateUUID({ each: true })
|
||||
assetIds!: string[];
|
||||
}
|
||||
|
||||
export enum AssetJobName {
|
||||
REGENERATE_THUMBNAIL = 'regenerate-thumbnail',
|
||||
REFRESH_METADATA = 'refresh-metadata',
|
||||
TRANSCODE_VIDEO = 'transcode-video',
|
||||
}
|
||||
|
||||
export class AssetJobsDto extends AssetIdsDto {
|
||||
@ApiProperty({ enumName: 'AssetJobName', enum: AssetJobName })
|
||||
@IsEnum(AssetJobName)
|
||||
name!: AssetJobName;
|
||||
}
|
||||
|
||||
export class AssetStatsDto {
|
||||
@ValidateBoolean({ optional: true })
|
||||
isArchived?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
isFavorite?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
isTrashed?: boolean;
|
||||
}
|
||||
|
||||
export class AssetStatsResponseDto {
|
||||
@ApiProperty({ type: 'integer' })
|
||||
images!: number;
|
||||
|
||||
@ApiProperty({ type: 'integer' })
|
||||
videos!: number;
|
||||
|
||||
@ApiProperty({ type: 'integer' })
|
||||
total!: number;
|
||||
}
|
||||
|
||||
export const mapStats = (stats: AssetStats): AssetStatsResponseDto => {
|
||||
return {
|
||||
images: stats[AssetType.IMAGE],
|
||||
videos: stats[AssetType.VIDEO],
|
||||
total: Object.values(stats).reduce((total, value) => total + value, 0),
|
||||
};
|
||||
};
|
||||
export enum UploadFieldName {
|
||||
ASSET_DATA = 'assetData',
|
||||
LIVE_PHOTO_DATA = 'livePhotoData',
|
||||
SIDECAR_DATA = 'sidecarData',
|
||||
PROFILE_DATA = 'file',
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue