mirror of
https://github.com/immich-app/immich.git
synced 2024-12-28 06:31:58 +00:00
fix(server): keep full datetime precision from database
This commit is contained in:
parent
d7a33c8ec2
commit
94b9013da5
44 changed files with 120 additions and 99 deletions
|
@ -18,7 +18,8 @@ export type MaybeDuplicate<T> = { duplicate: boolean; value: T };
|
|||
|
||||
export class ActivityResponseDto {
|
||||
id!: string;
|
||||
createdAt!: Date;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
createdAt!: string;
|
||||
type!: ReactionType;
|
||||
user!: UserResponseDto;
|
||||
assetId!: string | null;
|
||||
|
|
|
@ -123,8 +123,10 @@ export class AlbumResponseDto {
|
|||
ownerId!: string;
|
||||
albumName!: string;
|
||||
description!: string;
|
||||
createdAt!: Date;
|
||||
updatedAt!: Date;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
createdAt!: string;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
updatedAt!: string;
|
||||
albumThumbnailAssetId!: string | null;
|
||||
shared!: boolean;
|
||||
albumUsers!: AlbumUserResponseDto[];
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
import { Optional } from 'src/validation';
|
||||
export class APIKeyCreateDto {
|
||||
|
@ -21,6 +22,8 @@ export class APIKeyCreateResponseDto {
|
|||
export class APIKeyResponseDto {
|
||||
id!: string;
|
||||
name!: string;
|
||||
createdAt!: Date;
|
||||
updatedAt!: Date;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
createdAt!: string;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
updatedAt!: string;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,8 @@ export class AssetResponseDto extends SanitizedAssetResponseDto {
|
|||
originalFileName!: string;
|
||||
fileCreatedAt!: Date;
|
||||
fileModifiedAt!: Date;
|
||||
updatedAt!: Date;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
updatedAt!: string;
|
||||
isFavorite!: boolean;
|
||||
isArchived!: boolean;
|
||||
isTrashed!: boolean;
|
||||
|
|
|
@ -3,13 +3,13 @@ import { Type } from 'class-transformer';
|
|||
import { IsArray, IsEnum, IsString, IsUUID, ValidateNested } from 'class-validator';
|
||||
import { EntityType } from 'src/entities/audit.entity';
|
||||
import { AssetPathType, PathType, PersonPathType, UserPathType } from 'src/entities/move.entity';
|
||||
import { Optional, ValidateDate, ValidateUUID } from 'src/validation';
|
||||
import { Optional, ValidateUUID } from 'src/validation';
|
||||
|
||||
const PathEnum = Object.values({ ...AssetPathType, ...PersonPathType, ...UserPathType });
|
||||
|
||||
export class AuditDeletesDto {
|
||||
@ValidateDate()
|
||||
after!: Date;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
after!: string;
|
||||
|
||||
@ApiProperty({ enum: EntityType, enumName: 'EntityType' })
|
||||
@IsEnum(EntityType)
|
||||
|
|
|
@ -105,8 +105,10 @@ export class LibraryResponseDto {
|
|||
|
||||
exclusionPatterns!: string[];
|
||||
|
||||
createdAt!: Date;
|
||||
updatedAt!: Date;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
createdAt!: string;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
updatedAt!: string;
|
||||
refreshedAt!: Date | null;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,9 +55,12 @@ export class MemoryCreateDto extends MemoryBaseDto {
|
|||
|
||||
export class MemoryResponseDto {
|
||||
id!: string;
|
||||
createdAt!: Date;
|
||||
updatedAt!: Date;
|
||||
deletedAt?: Date;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
createdAt!: string;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
updatedAt!: string;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
deletedAt?: string;
|
||||
memoryAt!: Date;
|
||||
seenAt?: Date;
|
||||
ownerId!: string;
|
||||
|
|
|
@ -11,8 +11,8 @@ export class SessionResponseDto {
|
|||
|
||||
export const mapSession = (entity: SessionEntity, currentId?: string): SessionResponseDto => ({
|
||||
id: entity.id,
|
||||
createdAt: entity.createdAt.toISOString(),
|
||||
updatedAt: entity.updatedAt.toISOString(),
|
||||
createdAt: entity.createdAt,
|
||||
updatedAt: entity.updatedAt,
|
||||
current: currentId === entity.id,
|
||||
deviceOS: entity.deviceOS,
|
||||
deviceType: entity.deviceType,
|
||||
|
|
|
@ -86,7 +86,8 @@ export class SharedLinkResponseDto {
|
|||
|
||||
@ApiProperty({ enumName: 'SharedLinkType', enum: SharedLinkType })
|
||||
type!: SharedLinkType;
|
||||
createdAt!: Date;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
createdAt!: string;
|
||||
expiresAt!: Date | null;
|
||||
assets!: AssetResponseDto[];
|
||||
album?: AlbumResponseDto;
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsInt, IsPositive } from 'class-validator';
|
||||
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
|
||||
import { ValidateDate, ValidateUUID } from 'src/validation';
|
||||
import { ValidateUUID } from 'src/validation';
|
||||
|
||||
export class AssetFullSyncDto {
|
||||
@ValidateUUID({ optional: true })
|
||||
lastId?: string;
|
||||
|
||||
@ValidateDate()
|
||||
updatedUntil!: Date;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
updatedUntil!: string;
|
||||
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
|
@ -20,8 +20,8 @@ export class AssetFullSyncDto {
|
|||
}
|
||||
|
||||
export class AssetDeltaSyncDto {
|
||||
@ValidateDate()
|
||||
updatedAfter!: Date;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
updatedAfter!: string;
|
||||
|
||||
@ValidateUUID({ each: true })
|
||||
userIds!: string[];
|
||||
|
|
|
@ -120,9 +120,12 @@ export class UserAdminResponseDto extends UserResponseDto {
|
|||
storageLabel!: string | null;
|
||||
shouldChangePassword!: boolean;
|
||||
isAdmin!: boolean;
|
||||
createdAt!: Date;
|
||||
deletedAt!: Date | null;
|
||||
updatedAt!: Date;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
createdAt!: string;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
deletedAt!: string | null;
|
||||
@ApiProperty({ type: 'string', format: 'date-time' })
|
||||
updatedAt!: string;
|
||||
oauthId!: string;
|
||||
@ApiProperty({ type: 'integer', format: 'int64' })
|
||||
quotaSizeInBytes!: number | null;
|
||||
|
|
|
@ -20,10 +20,10 @@ export class ActivityEntity {
|
|||
id!: string;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
createdAt!: string;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: Date;
|
||||
updatedAt!: string;
|
||||
|
||||
@Column()
|
||||
albumId!: string;
|
||||
|
|
|
@ -39,13 +39,13 @@ export class AlbumEntity {
|
|||
description!: string;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
createdAt!: string;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: Date;
|
||||
updatedAt!: string;
|
||||
|
||||
@DeleteDateColumn({ type: 'timestamptz' })
|
||||
deletedAt!: Date | null;
|
||||
deletedAt!: string | null;
|
||||
|
||||
@ManyToOne(() => AssetEntity, { nullable: true, onDelete: 'SET NULL', onUpdate: 'CASCADE' })
|
||||
albumThumbnailAsset!: AssetEntity | null;
|
||||
|
|
|
@ -19,8 +19,8 @@ export class APIKeyEntity {
|
|||
userId!: string;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
createdAt!: string;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: Date;
|
||||
updatedAt!: string;
|
||||
}
|
||||
|
|
|
@ -84,13 +84,13 @@ export class AssetEntity {
|
|||
encodedVideoPath!: string | null;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
createdAt!: string;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: Date;
|
||||
updatedAt!: string;
|
||||
|
||||
@DeleteDateColumn({ type: 'timestamptz', nullable: true })
|
||||
deletedAt!: Date | null;
|
||||
deletedAt!: string | null;
|
||||
|
||||
@Index('idx_asset_file_created_at')
|
||||
@Column({ type: 'timestamptz' })
|
||||
|
|
|
@ -30,5 +30,5 @@ export class AuditEntity {
|
|||
ownerId!: string;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
createdAt!: string;
|
||||
}
|
||||
|
|
|
@ -37,13 +37,13 @@ export class LibraryEntity {
|
|||
exclusionPatterns!: string[];
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
createdAt!: string;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: Date;
|
||||
updatedAt!: string;
|
||||
|
||||
@DeleteDateColumn({ type: 'timestamptz' })
|
||||
deletedAt?: Date;
|
||||
deletedAt?: string;
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true })
|
||||
refreshedAt!: Date | null;
|
||||
|
|
|
@ -29,13 +29,13 @@ export class MemoryEntity<T extends MemoryType = MemoryType> {
|
|||
id!: string;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
createdAt!: string;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: Date;
|
||||
updatedAt!: string;
|
||||
|
||||
@DeleteDateColumn({ type: 'timestamptz' })
|
||||
deletedAt?: Date;
|
||||
deletedAt?: string;
|
||||
|
||||
@ManyToOne(() => UserEntity, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: false })
|
||||
owner!: UserEntity;
|
||||
|
|
|
@ -18,10 +18,10 @@ export class PartnerEntity {
|
|||
sharedWith!: UserEntity;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
createdAt!: string;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: Date;
|
||||
updatedAt!: string;
|
||||
|
||||
@Column({ type: 'boolean', default: false })
|
||||
inTimeline!: boolean;
|
||||
|
|
|
@ -18,10 +18,10 @@ export class PersonEntity {
|
|||
id!: string;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
createdAt!: string;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: Date;
|
||||
updatedAt!: string;
|
||||
|
||||
@Column()
|
||||
ownerId!: string;
|
||||
|
|
|
@ -16,10 +16,10 @@ export class SessionEntity {
|
|||
user!: UserEntity;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
createdAt!: string;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: Date;
|
||||
updatedAt!: string;
|
||||
|
||||
@Column({ default: '' })
|
||||
deviceType!: string;
|
||||
|
|
|
@ -38,7 +38,7 @@ export class SharedLinkEntity {
|
|||
type!: SharedLinkType;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
createdAt!: string;
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true })
|
||||
expiresAt!: Date | null;
|
||||
|
|
|
@ -47,16 +47,16 @@ export class UserEntity {
|
|||
shouldChangePassword!: boolean;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
createdAt!: string;
|
||||
|
||||
@DeleteDateColumn({ type: 'timestamptz' })
|
||||
deletedAt!: Date | null;
|
||||
deletedAt!: string | null;
|
||||
|
||||
@Column({ type: 'varchar', default: UserStatus.ACTIVE })
|
||||
status!: UserStatus;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: Date;
|
||||
updatedAt!: string;
|
||||
|
||||
@OneToMany(() => TagEntity, (tag) => tag.user)
|
||||
tags!: TagEntity[];
|
||||
|
|
|
@ -123,13 +123,13 @@ export interface AssetExploreOptions extends AssetExploreFieldOptions {
|
|||
export interface AssetFullSyncOptions {
|
||||
ownerId: string;
|
||||
lastId?: string;
|
||||
updatedUntil: Date;
|
||||
updatedUntil: string;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
export interface AssetDeltaSyncOptions {
|
||||
userIds: string[];
|
||||
updatedAfter: Date;
|
||||
updatedAfter: string;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,6 @@ export interface AuditSearch {
|
|||
}
|
||||
|
||||
export interface IAuditRepository {
|
||||
getAfter(since: Date, options: AuditSearch): Promise<string[]>;
|
||||
getAfter(since: string, options: AuditSearch): Promise<string[]>;
|
||||
removeBefore(before: Date): Promise<void>;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import { In, LessThan, MoreThan, Repository } from 'typeorm';
|
|||
export class AuditRepository implements IAuditRepository {
|
||||
constructor(@InjectRepository(AuditEntity) private repository: Repository<AuditEntity>) {}
|
||||
|
||||
async getAfter(since: Date, options: AuditSearch): Promise<string[]> {
|
||||
async getAfter(since: string, options: AuditSearch): Promise<string[]> {
|
||||
const records = await this.repository
|
||||
.createQueryBuilder('audit')
|
||||
.where({
|
||||
|
@ -28,6 +28,6 @@ export class AuditRepository implements IAuditRepository {
|
|||
}
|
||||
|
||||
async removeBefore(before: Date): Promise<void> {
|
||||
await this.repository.delete({ createdAt: LessThan(before) });
|
||||
await this.repository.delete({ createdAt: LessThan(before.toISOString()) });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ export class SessionRepository implements ISessionRepository {
|
|||
|
||||
@GenerateSql({ params: [DummyValue.DATE] })
|
||||
search(options: SessionSearchOptions): Promise<SessionEntity[]> {
|
||||
return this.repository.find({ where: { updatedAt: LessThanOrEqual(options.updatedBefore) } });
|
||||
return this.repository.find({ where: { updatedAt: LessThanOrEqual(options.updatedBefore.toISOString()) } });
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.STRING] })
|
||||
|
|
|
@ -569,7 +569,7 @@ describe(AlbumService.name, () => {
|
|||
|
||||
expect(albumMock.update).toHaveBeenCalledWith({
|
||||
id: 'album-123',
|
||||
updatedAt: expect.any(Date),
|
||||
updatedAt: expect.any(String),
|
||||
albumThumbnailAssetId: 'asset-1',
|
||||
});
|
||||
expect(albumMock.addAssetIds).toHaveBeenCalledWith('album-123', ['asset-1', 'asset-2', 'asset-3']);
|
||||
|
@ -595,7 +595,7 @@ describe(AlbumService.name, () => {
|
|||
|
||||
expect(albumMock.update).toHaveBeenCalledWith({
|
||||
id: 'album-123',
|
||||
updatedAt: expect.any(Date),
|
||||
updatedAt: expect.any(String),
|
||||
albumThumbnailAssetId: 'asset-id',
|
||||
});
|
||||
expect(albumMock.addAssetIds).toHaveBeenCalled();
|
||||
|
@ -617,7 +617,7 @@ describe(AlbumService.name, () => {
|
|||
|
||||
expect(albumMock.update).toHaveBeenCalledWith({
|
||||
id: 'album-123',
|
||||
updatedAt: expect.any(Date),
|
||||
updatedAt: expect.any(String),
|
||||
albumThumbnailAssetId: 'asset-1',
|
||||
});
|
||||
expect(albumMock.addAssetIds).toHaveBeenCalledWith('album-123', ['asset-1', 'asset-2', 'asset-3']);
|
||||
|
@ -658,7 +658,7 @@ describe(AlbumService.name, () => {
|
|||
|
||||
expect(albumMock.update).toHaveBeenCalledWith({
|
||||
id: 'album-123',
|
||||
updatedAt: expect.any(Date),
|
||||
updatedAt: expect.any(String),
|
||||
albumThumbnailAssetId: 'asset-1',
|
||||
});
|
||||
expect(albumMock.addAssetIds).toHaveBeenCalledWith('album-123', ['asset-1', 'asset-2', 'asset-3']);
|
||||
|
@ -681,7 +681,7 @@ describe(AlbumService.name, () => {
|
|||
|
||||
expect(albumMock.update).toHaveBeenCalledWith({
|
||||
id: 'album-123',
|
||||
updatedAt: expect.any(Date),
|
||||
updatedAt: expect.any(String),
|
||||
albumThumbnailAssetId: 'asset-1',
|
||||
});
|
||||
expect(accessMock.asset.checkPartnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['asset-1']));
|
||||
|
@ -746,7 +746,7 @@ describe(AlbumService.name, () => {
|
|||
{ success: true, id: 'asset-id' },
|
||||
]);
|
||||
|
||||
expect(albumMock.update).toHaveBeenCalledWith({ id: 'album-123', updatedAt: expect.any(Date) });
|
||||
expect(albumMock.update).toHaveBeenCalledWith({ id: 'album-123', updatedAt: expect.any(String) });
|
||||
expect(albumMock.removeAssetIds).toHaveBeenCalledWith('album-123', ['asset-id']);
|
||||
});
|
||||
|
||||
|
@ -790,7 +790,7 @@ describe(AlbumService.name, () => {
|
|||
|
||||
expect(albumMock.update).toHaveBeenCalledWith({
|
||||
id: 'album-123',
|
||||
updatedAt: expect.any(Date),
|
||||
updatedAt: expect.any(String),
|
||||
});
|
||||
expect(albumMock.updateThumbnails).toHaveBeenCalled();
|
||||
});
|
||||
|
|
|
@ -185,7 +185,7 @@ export class AlbumService {
|
|||
if (firstNewAssetId) {
|
||||
await this.albumRepository.update({
|
||||
id,
|
||||
updatedAt: new Date(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
albumThumbnailAssetId: album.albumThumbnailAssetId ?? firstNewAssetId,
|
||||
});
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ export class AlbumService {
|
|||
|
||||
const removedIds = results.filter(({ success }) => success).map(({ id }) => id);
|
||||
if (removedIds.length > 0) {
|
||||
await this.albumRepository.update({ id, updatedAt: new Date() });
|
||||
await this.albumRepository.update({ id, updatedAt: new Date().toISOString() });
|
||||
if (album.albumThumbnailAssetId && removedIds.includes(album.albumThumbnailAssetId)) {
|
||||
await this.albumRepository.updateThumbnails();
|
||||
}
|
||||
|
|
|
@ -265,7 +265,7 @@ describe(AssetService.name, () => {
|
|||
ids: [],
|
||||
stackParentId: 'parent',
|
||||
}),
|
||||
expect(assetMock.updateAll).toHaveBeenCalledWith(['parent'], { updatedAt: expect.any(Date) });
|
||||
expect(assetMock.updateAll).toHaveBeenCalledWith(['parent'], { updatedAt: expect.any(String) });
|
||||
});
|
||||
|
||||
it('should update parent asset when children are removed', async () => {
|
||||
|
@ -285,7 +285,7 @@ describe(AssetService.name, () => {
|
|||
});
|
||||
expect(assetMock.updateAll).toHaveBeenCalledWith(expect.arrayContaining(['child-1']), { stack: null });
|
||||
expect(assetMock.updateAll).toHaveBeenCalledWith(expect.arrayContaining(['parent']), {
|
||||
updatedAt: expect.any(Date),
|
||||
updatedAt: expect.any(String),
|
||||
});
|
||||
expect(assetStackMock.delete).toHaveBeenCalledWith('stack-1');
|
||||
});
|
||||
|
@ -316,7 +316,7 @@ describe(AssetService.name, () => {
|
|||
]),
|
||||
primaryAsset: undefined,
|
||||
});
|
||||
expect(assetMock.updateAll).toBeCalledWith(['child-1', 'child-2', 'parent'], { updatedAt: expect.any(Date) });
|
||||
expect(assetMock.updateAll).toBeCalledWith(['child-1', 'child-2', 'parent'], { updatedAt: expect.any(String) });
|
||||
});
|
||||
|
||||
it('remove stack for removed children', async () => {
|
||||
|
@ -353,7 +353,7 @@ describe(AssetService.name, () => {
|
|||
primaryAssetId: 'parent',
|
||||
});
|
||||
expect(assetMock.updateAll).toBeCalledWith(['child-1', 'parent', 'child-1', 'child-2'], {
|
||||
updatedAt: expect.any(Date),
|
||||
updatedAt: expect.any(String),
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -532,7 +532,7 @@ describe(AssetService.name, () => {
|
|||
|
||||
expect(assetStackMock.update).toBeCalledWith({ id: 'stack-1', primaryAssetId: 'new' });
|
||||
expect(assetMock.updateAll).toBeCalledWith([assetStub.image.id, 'new', assetStub.image.id], {
|
||||
updatedAt: expect.any(Date),
|
||||
updatedAt: expect.any(String),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -191,7 +191,7 @@ export class AssetService {
|
|||
// All the unique parent's -> parent is set to null
|
||||
await this.assetRepository.updateAll(
|
||||
assets.filter((a) => !!a.stack?.primaryAssetId).map((a) => a.stack!.primaryAssetId!),
|
||||
{ updatedAt: new Date() },
|
||||
{ updatedAt: new Date().toISOString() },
|
||||
);
|
||||
} else if (options.stackParentId) {
|
||||
//Creating new stack if parent doesn't have one already. If it does, then we add to the existing stack
|
||||
|
@ -225,7 +225,7 @@ export class AssetService {
|
|||
|
||||
// Merge stacks
|
||||
options.stackParentId = undefined;
|
||||
(options as Partial<AssetEntity>).updatedAt = new Date();
|
||||
(options as Partial<AssetEntity>).updatedAt = new Date().toISOString();
|
||||
}
|
||||
|
||||
for (const id of ids) {
|
||||
|
@ -372,7 +372,9 @@ export class AssetService {
|
|||
newParentId,
|
||||
oldParentId,
|
||||
]);
|
||||
await this.assetRepository.updateAll([oldParentId, newParentId, ...childIds], { updatedAt: new Date() });
|
||||
await this.assetRepository.updateAll([oldParentId, newParentId, ...childIds], {
|
||||
updatedAt: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
async run(auth: AuthDto, dto: AssetJobsDto) {
|
||||
|
|
|
@ -58,7 +58,7 @@ describe(AuditService.name, () => {
|
|||
it('should require full sync if the request is older than 100 days', async () => {
|
||||
auditMock.getAfter.mockResolvedValue([]);
|
||||
|
||||
const date = new Date(2022, 0, 1);
|
||||
const date = new Date(2022, 0, 1).toISOString();
|
||||
await expect(sut.getDeletes(authStub.admin, { after: date, entityType: EntityType.ASSET })).resolves.toEqual({
|
||||
needsFullSync: true,
|
||||
ids: [],
|
||||
|
|
|
@ -59,7 +59,7 @@ export class AuditService {
|
|||
action: DatabaseAction.DELETE,
|
||||
});
|
||||
|
||||
const duration = DateTime.now().diff(DateTime.fromJSDate(dto.after));
|
||||
const duration = DateTime.now().diff(DateTime.fromISO(dto.after));
|
||||
|
||||
return {
|
||||
needsFullSync: duration > AUDIT_LOG_MAX_DURATION,
|
||||
|
|
|
@ -331,7 +331,7 @@ describe('AuthService', () => {
|
|||
sessionMock.update.mockResolvedValue(sessionStub.valid);
|
||||
const headers: IncomingHttpHeaders = { cookie: 'immich_access_token=auth_token' };
|
||||
await expect(sut.validate(headers, {})).resolves.toBeDefined();
|
||||
expect(sessionMock.update.mock.calls[0][0]).toMatchObject({ id: 'not_active', updatedAt: expect.any(Date) });
|
||||
expect(sessionMock.update.mock.calls[0][0]).toMatchObject({ id: 'not_active', updatedAt: expect.any(String) });
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -382,10 +382,10 @@ export class AuthService {
|
|||
|
||||
if (session?.user) {
|
||||
const now = DateTime.now();
|
||||
const updatedAt = DateTime.fromJSDate(session.updatedAt);
|
||||
const updatedAt = DateTime.fromISO(session.updatedAt);
|
||||
const diff = now.diff(updatedAt, ['hours']);
|
||||
if (diff.hours > 1) {
|
||||
await this.sessionRepository.update({ id: session.id, updatedAt: new Date() });
|
||||
await this.sessionRepository.update({ id: session.id, updatedAt: new Date().toISOString() });
|
||||
}
|
||||
|
||||
return { user: session.user, session: session };
|
||||
|
|
|
@ -74,7 +74,7 @@ export class MemoryService {
|
|||
|
||||
const hasSuccess = results.find(({ success }) => success);
|
||||
if (hasSuccess) {
|
||||
await this.repository.update({ id, updatedAt: new Date() });
|
||||
await this.repository.update({ id, updatedAt: new Date().toISOString() });
|
||||
}
|
||||
|
||||
return results;
|
||||
|
@ -89,7 +89,7 @@ export class MemoryService {
|
|||
|
||||
const hasSuccess = results.find(({ success }) => success);
|
||||
if (hasSuccess) {
|
||||
await this.repository.update({ id, updatedAt: new Date() });
|
||||
await this.repository.update({ id, updatedAt: new Date().toISOString() });
|
||||
}
|
||||
|
||||
return results;
|
||||
|
|
|
@ -38,8 +38,8 @@ describe('SessionService', () => {
|
|||
it('should delete sessions', async () => {
|
||||
sessionMock.search.mockResolvedValue([
|
||||
{
|
||||
createdAt: new Date('1970-01-01T00:00:00.00Z'),
|
||||
updatedAt: new Date('1970-01-02T00:00:00.00Z'),
|
||||
createdAt: new Date('1970-01-01T00:00:00.00Z').toISOString(),
|
||||
updatedAt: new Date('1970-01-02T00:00:00.00Z').toISOString(),
|
||||
deviceOS: '',
|
||||
deviceType: '',
|
||||
id: '123',
|
||||
|
|
|
@ -14,7 +14,7 @@ import { newAuditRepositoryMock } from 'test/repositories/audit.repository.mock'
|
|||
import { newPartnerRepositoryMock } from 'test/repositories/partner.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
const untilDate = new Date(2024);
|
||||
const untilDate = new Date(2024).toISOString();
|
||||
const mapAssetOpts = { auth: authStub.user1, stripMetadata: false, withStack: true };
|
||||
|
||||
describe(SyncService.name, () => {
|
||||
|
@ -55,7 +55,7 @@ describe(SyncService.name, () => {
|
|||
it('should return a response requiring a full sync when partners are out of sync', async () => {
|
||||
partnerMock.getAll.mockResolvedValue([partnerStub.adminToUser1]);
|
||||
await expect(
|
||||
sut.getDeltaSync(authStub.user1, { updatedAfter: new Date(), userIds: [authStub.user1.user.id] }),
|
||||
sut.getDeltaSync(authStub.user1, { updatedAfter: new Date().toISOString(), userIds: [authStub.user1.user.id] }),
|
||||
).resolves.toEqual({ needsFullSync: true, upserted: [], deleted: [] });
|
||||
expect(assetMock.getChangedDeltaSync).toHaveBeenCalledTimes(0);
|
||||
expect(auditMock.getAfter).toHaveBeenCalledTimes(0);
|
||||
|
@ -64,7 +64,10 @@ describe(SyncService.name, () => {
|
|||
it('should return a response requiring a full sync when last sync was too long ago', async () => {
|
||||
partnerMock.getAll.mockResolvedValue([]);
|
||||
await expect(
|
||||
sut.getDeltaSync(authStub.user1, { updatedAfter: new Date(2000), userIds: [authStub.user1.user.id] }),
|
||||
sut.getDeltaSync(authStub.user1, {
|
||||
updatedAfter: new Date(2000).toISOString(),
|
||||
userIds: [authStub.user1.user.id],
|
||||
}),
|
||||
).resolves.toEqual({ needsFullSync: true, upserted: [], deleted: [] });
|
||||
expect(assetMock.getChangedDeltaSync).toHaveBeenCalledTimes(0);
|
||||
expect(auditMock.getAfter).toHaveBeenCalledTimes(0);
|
||||
|
|
|
@ -42,7 +42,7 @@ export class SyncService {
|
|||
|
||||
async getDeltaSync(auth: AuthDto, dto: AssetDeltaSyncDto): Promise<AssetDeltaSyncResponseDto> {
|
||||
// app has not synced in the last 100 days
|
||||
const duration = DateTime.now().diff(DateTime.fromJSDate(dto.updatedAfter));
|
||||
const duration = DateTime.now().diff(DateTime.fromISO(dto.updatedAfter));
|
||||
if (duration > AUDIT_LOG_MAX_DURATION) {
|
||||
return FULL_SYNC;
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ describe(UserAdminService.name, () => {
|
|||
await sut.update(authStub.admin, userStub.user1.id, { storageLabel: '' });
|
||||
expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, {
|
||||
storageLabel: null,
|
||||
updatedAt: expect.any(Date),
|
||||
updatedAt: expect.any(String),
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -157,7 +157,7 @@ describe(UserAdminService.name, () => {
|
|||
await expect(sut.delete(authStub.admin, userStub.user1.id, {})).resolves.toEqual(mapUserAdmin(userStub.user1));
|
||||
expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, {
|
||||
status: UserStatus.DELETED,
|
||||
deletedAt: expect.any(Date),
|
||||
deletedAt: expect.any(String),
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -171,7 +171,7 @@ describe(UserAdminService.name, () => {
|
|||
|
||||
expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, {
|
||||
status: UserStatus.REMOVING,
|
||||
deletedAt: expect.any(Date),
|
||||
deletedAt: expect.any(String),
|
||||
});
|
||||
expect(jobMock.queue).toHaveBeenCalledWith({
|
||||
name: JobName.USER_DELETION,
|
||||
|
|
|
@ -85,7 +85,7 @@ export class UserAdminService {
|
|||
dto.storageLabel = null;
|
||||
}
|
||||
|
||||
const updatedUser = await this.userRepository.update(id, { ...dto, updatedAt: new Date() });
|
||||
const updatedUser = await this.userRepository.update(id, { ...dto, updatedAt: new Date().toISOString() });
|
||||
|
||||
return mapUserAdmin(updatedUser);
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ export class UserAdminService {
|
|||
await this.albumRepository.softDeleteAll(id);
|
||||
|
||||
const status = force ? UserStatus.REMOVING : UserStatus.DELETED;
|
||||
const user = await this.userRepository.update(id, { status, deletedAt: new Date() });
|
||||
const user = await this.userRepository.update(id, { status, deletedAt: new Date().toISOString() });
|
||||
|
||||
if (force) {
|
||||
await this.jobRepository.queue({ name: JobName.USER_DELETION, data: { id: user.id, force } });
|
||||
|
|
|
@ -24,7 +24,7 @@ import { Mocked } from 'vitest';
|
|||
const makeDeletedAt = (daysAgo: number) => {
|
||||
const deletedAt = new Date();
|
||||
deletedAt.setDate(deletedAt.getDate() - daysAgo);
|
||||
return deletedAt;
|
||||
return deletedAt.toISOString();
|
||||
};
|
||||
|
||||
describe(UserService.name, () => {
|
||||
|
|
|
@ -179,7 +179,7 @@ export class UserService {
|
|||
return false;
|
||||
}
|
||||
|
||||
return DateTime.now().minus({ days: deleteDelay }) > DateTime.fromJSDate(user.deletedAt);
|
||||
return DateTime.now().minus({ days: deleteDelay }) > DateTime.fromISO(user.deletedAt);
|
||||
}
|
||||
|
||||
private async findOrFail(id: string, options: UserFindOptions) {
|
||||
|
|
8
server/test/fixtures/session.stub.ts
vendored
8
server/test/fixtures/session.stub.ts
vendored
|
@ -7,8 +7,8 @@ export const sessionStub = {
|
|||
token: 'auth_token',
|
||||
userId: userStub.user1.id,
|
||||
user: userStub.user1,
|
||||
createdAt: new Date('2021-01-01'),
|
||||
updatedAt: new Date(),
|
||||
createdAt: new Date('2021-01-01').toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deviceType: '',
|
||||
deviceOS: '',
|
||||
}),
|
||||
|
@ -17,8 +17,8 @@ export const sessionStub = {
|
|||
token: 'auth_token',
|
||||
userId: userStub.user1.id,
|
||||
user: userStub.user1,
|
||||
createdAt: new Date('2021-01-01'),
|
||||
updatedAt: new Date('2021-01-01'),
|
||||
createdAt: new Date('2021-01-01').toISOString(),
|
||||
updatedAt: new Date('2021-01-01').toISOString(),
|
||||
deviceType: 'Mobile',
|
||||
deviceOS: 'Android',
|
||||
}),
|
||||
|
|
Loading…
Reference in a new issue