diff --git a/mobile/lib/shared/models/album.dart b/mobile/lib/shared/models/album.dart index 3223a465b9..a3cffa1698 100644 --- a/mobile/lib/shared/models/album.dart +++ b/mobile/lib/shared/models/album.dart @@ -128,8 +128,8 @@ class Album { final Album a = Album( remoteId: dto.id, name: dto.albumName, - createdAt: DateTime.parse(dto.createdAt), - modifiedAt: DateTime.parse(dto.updatedAt), + createdAt: dto.createdAt, + modifiedAt: dto.updatedAt, shared: dto.shared, ); a.owner.value = await db.users.getById(dto.ownerId); diff --git a/mobile/lib/shared/models/user.dart b/mobile/lib/shared/models/user.dart index d6e3d487cd..267503c304 100644 --- a/mobile/lib/shared/models/user.dart +++ b/mobile/lib/shared/models/user.dart @@ -22,9 +22,7 @@ class User { User.fromDto(UserResponseDto dto) : id = dto.id, - updatedAt = dto.updatedAt != null - ? DateTime.parse(dto.updatedAt!).toUtc() - : DateTime.now().toUtc(), + updatedAt = dto.updatedAt, email = dto.email, firstName = dto.firstName, lastName = dto.lastName, diff --git a/mobile/lib/shared/services/sync.service.dart b/mobile/lib/shared/services/sync.service.dart index fae95a84fc..f5471d1546 100644 --- a/mobile/lib/shared/services/sync.service.dart +++ b/mobile/lib/shared/services/sync.service.dart @@ -279,7 +279,7 @@ class SyncService { album.name = dto.albumName; album.shared = dto.shared; - album.modifiedAt = DateTime.parse(dto.updatedAt); + album.modifiedAt = dto.updatedAt; if (album.thumbnail.value?.remoteId != dto.albumThumbnailAssetId) { album.thumbnail.value = await _db.assets .where() @@ -713,5 +713,5 @@ bool _hasAlbumResponseDtoChanged(AlbumResponseDto dto, Album a) { dto.albumThumbnailAssetId != a.thumbnail.value?.remoteId || dto.shared != a.shared || dto.sharedUsers.length != a.sharedUsers.length || - !DateTime.parse(dto.updatedAt).isAtSameMomentAs(a.modifiedAt); + !dto.updatedAt.isAtSameMomentAs(a.modifiedAt); } diff --git a/mobile/openapi/doc/APIKeyResponseDto.md b/mobile/openapi/doc/APIKeyResponseDto.md index 81367fb184..7e36819b9b 100644 Binary files a/mobile/openapi/doc/APIKeyResponseDto.md and b/mobile/openapi/doc/APIKeyResponseDto.md differ diff --git a/mobile/openapi/doc/AdminSignupResponseDto.md b/mobile/openapi/doc/AdminSignupResponseDto.md index ff9890de5d..bfca912d9a 100644 Binary files a/mobile/openapi/doc/AdminSignupResponseDto.md and b/mobile/openapi/doc/AdminSignupResponseDto.md differ diff --git a/mobile/openapi/doc/AlbumResponseDto.md b/mobile/openapi/doc/AlbumResponseDto.md index 3b65af2760..d257dea2e9 100644 Binary files a/mobile/openapi/doc/AlbumResponseDto.md and b/mobile/openapi/doc/AlbumResponseDto.md differ diff --git a/mobile/openapi/doc/CreateAssetsShareLinkDto.md b/mobile/openapi/doc/CreateAssetsShareLinkDto.md index c36b519d76..59a6f02f38 100644 Binary files a/mobile/openapi/doc/CreateAssetsShareLinkDto.md and b/mobile/openapi/doc/CreateAssetsShareLinkDto.md differ diff --git a/mobile/openapi/doc/EditSharedLinkDto.md b/mobile/openapi/doc/EditSharedLinkDto.md index a875bdbe7c..8097bb1183 100644 Binary files a/mobile/openapi/doc/EditSharedLinkDto.md and b/mobile/openapi/doc/EditSharedLinkDto.md differ diff --git a/mobile/openapi/doc/SharedLinkResponseDto.md b/mobile/openapi/doc/SharedLinkResponseDto.md index b8de598bee..8ffe0787a8 100644 Binary files a/mobile/openapi/doc/SharedLinkResponseDto.md and b/mobile/openapi/doc/SharedLinkResponseDto.md differ diff --git a/mobile/openapi/doc/UserResponseDto.md b/mobile/openapi/doc/UserResponseDto.md index 658f5b8d1f..c551dd5c77 100644 Binary files a/mobile/openapi/doc/UserResponseDto.md and b/mobile/openapi/doc/UserResponseDto.md differ diff --git a/mobile/openapi/lib/model/admin_signup_response_dto.dart b/mobile/openapi/lib/model/admin_signup_response_dto.dart index 4e19b9473e..cd937c9332 100644 Binary files a/mobile/openapi/lib/model/admin_signup_response_dto.dart and b/mobile/openapi/lib/model/admin_signup_response_dto.dart differ diff --git a/mobile/openapi/lib/model/album_response_dto.dart b/mobile/openapi/lib/model/album_response_dto.dart index af1ed3f073..4661d5f281 100644 Binary files a/mobile/openapi/lib/model/album_response_dto.dart and b/mobile/openapi/lib/model/album_response_dto.dart differ diff --git a/mobile/openapi/lib/model/api_key_response_dto.dart b/mobile/openapi/lib/model/api_key_response_dto.dart index 237674e3cf..8b34b4b9e5 100644 Binary files a/mobile/openapi/lib/model/api_key_response_dto.dart and b/mobile/openapi/lib/model/api_key_response_dto.dart differ diff --git a/mobile/openapi/lib/model/create_assets_share_link_dto.dart b/mobile/openapi/lib/model/create_assets_share_link_dto.dart index 04d9d2f6ac..c8391c1db6 100644 Binary files a/mobile/openapi/lib/model/create_assets_share_link_dto.dart and b/mobile/openapi/lib/model/create_assets_share_link_dto.dart differ diff --git a/mobile/openapi/lib/model/edit_shared_link_dto.dart b/mobile/openapi/lib/model/edit_shared_link_dto.dart index f6f64d76fa..e6a38994fb 100644 Binary files a/mobile/openapi/lib/model/edit_shared_link_dto.dart and b/mobile/openapi/lib/model/edit_shared_link_dto.dart differ diff --git a/mobile/openapi/lib/model/shared_link_response_dto.dart b/mobile/openapi/lib/model/shared_link_response_dto.dart index ec8472c810..e7f2f9bf57 100644 Binary files a/mobile/openapi/lib/model/shared_link_response_dto.dart and b/mobile/openapi/lib/model/shared_link_response_dto.dart differ diff --git a/mobile/openapi/lib/model/user_response_dto.dart b/mobile/openapi/lib/model/user_response_dto.dart index 3a637a7e30..f6af4a2519 100644 Binary files a/mobile/openapi/lib/model/user_response_dto.dart and b/mobile/openapi/lib/model/user_response_dto.dart differ diff --git a/mobile/openapi/test/admin_signup_response_dto_test.dart b/mobile/openapi/test/admin_signup_response_dto_test.dart index d71763a327..62eb488fe1 100644 Binary files a/mobile/openapi/test/admin_signup_response_dto_test.dart and b/mobile/openapi/test/admin_signup_response_dto_test.dart differ diff --git a/mobile/openapi/test/album_response_dto_test.dart b/mobile/openapi/test/album_response_dto_test.dart index e911f76df4..bc8c153958 100644 Binary files a/mobile/openapi/test/album_response_dto_test.dart and b/mobile/openapi/test/album_response_dto_test.dart differ diff --git a/mobile/openapi/test/api_key_response_dto_test.dart b/mobile/openapi/test/api_key_response_dto_test.dart index 702f474116..c849e7629f 100644 Binary files a/mobile/openapi/test/api_key_response_dto_test.dart and b/mobile/openapi/test/api_key_response_dto_test.dart differ diff --git a/mobile/openapi/test/create_assets_share_link_dto_test.dart b/mobile/openapi/test/create_assets_share_link_dto_test.dart index 1f8dc10bad..832e269047 100644 Binary files a/mobile/openapi/test/create_assets_share_link_dto_test.dart and b/mobile/openapi/test/create_assets_share_link_dto_test.dart differ diff --git a/mobile/openapi/test/edit_shared_link_dto_test.dart b/mobile/openapi/test/edit_shared_link_dto_test.dart index 4e80594887..1308ee71d2 100644 Binary files a/mobile/openapi/test/edit_shared_link_dto_test.dart and b/mobile/openapi/test/edit_shared_link_dto_test.dart differ diff --git a/mobile/openapi/test/shared_link_response_dto_test.dart b/mobile/openapi/test/shared_link_response_dto_test.dart index c89ae970fc..0554a0553d 100644 Binary files a/mobile/openapi/test/shared_link_response_dto_test.dart and b/mobile/openapi/test/shared_link_response_dto_test.dart differ diff --git a/mobile/openapi/test/user_response_dto_test.dart b/mobile/openapi/test/user_response_dto_test.dart index 136643b2aa..ae05daf608 100644 Binary files a/mobile/openapi/test/user_response_dto_test.dart and b/mobile/openapi/test/user_response_dto_test.dart differ diff --git a/server/apps/immich/src/api-v1/album/album-repository.ts b/server/apps/immich/src/api-v1/album/album-repository.ts index a369cdfa59..e52f5178c0 100644 --- a/server/apps/immich/src/api-v1/album/album-repository.ts +++ b/server/apps/immich/src/api-v1/album/album-repository.ts @@ -61,7 +61,7 @@ export class AlbumRepository implements IAlbumRepository { async addSharedUsers(album: AlbumEntity, addUsersDto: AddUsersDto): Promise { album.sharedUsers.push(...addUsersDto.sharedUserIds.map((id) => ({ id } as UserEntity))); - album.updatedAt = new Date().toISOString(); + album.updatedAt = new Date(); await this.albumRepository.save(album); @@ -71,7 +71,7 @@ export class AlbumRepository implements IAlbumRepository { async removeUser(album: AlbumEntity, userId: string): Promise { album.sharedUsers = album.sharedUsers.filter((user) => user.id !== userId); - album.updatedAt = new Date().toISOString(); + album.updatedAt = new Date(); await this.albumRepository.save(album); } @@ -84,7 +84,7 @@ export class AlbumRepository implements IAlbumRepository { const numRemovedAssets = assetCount - album.assets.length; if (numRemovedAssets > 0) { - album.updatedAt = new Date().toISOString(); + album.updatedAt = new Date(); } await this.albumRepository.save(album, {}); @@ -111,7 +111,7 @@ export class AlbumRepository implements IAlbumRepository { const successfullyAdded = addAssetsDto.assetIds.length - alreadyExisting.length; if (successfullyAdded > 0) { - album.updatedAt = new Date().toISOString(); + album.updatedAt = new Date(); } await this.albumRepository.save(album); diff --git a/server/apps/immich/src/api-v1/album/album.service.spec.ts b/server/apps/immich/src/api-v1/album/album.service.spec.ts index e1b1def7f9..1b24ee8d58 100644 --- a/server/apps/immich/src/api-v1/album/album.service.spec.ts +++ b/server/apps/immich/src/api-v1/album/album.service.spec.ts @@ -32,8 +32,9 @@ describe('Album service', () => { ...authUser, firstName: 'auth', lastName: 'user', - createdAt: 'date', - updatedAt: 'date', + createdAt: new Date('2022-06-19T23:41:36.910Z'), + deletedAt: null, + updatedAt: new Date('2022-06-19T23:41:36.910Z'), profileImagePath: '', shouldChangePassword: false, oauthId: '', @@ -52,8 +53,8 @@ describe('Album service', () => { albumEntity.owner = albumOwner; albumEntity.id = albumId; albumEntity.albumName = 'name'; - albumEntity.createdAt = 'date'; - albumEntity.updatedAt = 'date'; + albumEntity.createdAt = new Date('2022-06-19T23:41:36.910Z'); + albumEntity.updatedAt = new Date('2022-06-19T23:41:36.910Z'); albumEntity.sharedUsers = []; albumEntity.assets = []; albumEntity.albumThumbnailAssetId = null; @@ -67,7 +68,7 @@ describe('Album service', () => { albumEntity.owner = albumOwner; albumEntity.id = albumId; albumEntity.albumName = 'name'; - albumEntity.createdAt = 'date'; + albumEntity.createdAt = new Date('2022-06-19T23:41:36.910Z'); albumEntity.assets = []; albumEntity.albumThumbnailAssetId = null; albumEntity.sharedUsers = [ @@ -86,7 +87,7 @@ describe('Album service', () => { albumEntity.owner = albumOwner; albumEntity.id = albumId; albumEntity.albumName = 'name'; - albumEntity.createdAt = 'date'; + albumEntity.createdAt = new Date('2022-06-19T23:41:36.910Z'); albumEntity.assets = []; albumEntity.albumThumbnailAssetId = null; albumEntity.sharedUsers = [ @@ -109,7 +110,7 @@ describe('Album service', () => { albumEntity.ownerId = '5555'; albumEntity.id = albumId; albumEntity.albumName = 'name'; - albumEntity.createdAt = 'date'; + albumEntity.createdAt = new Date('2022-06-19T23:41:36.910Z'); albumEntity.sharedUsers = []; albumEntity.assets = []; albumEntity.albumThumbnailAssetId = null; @@ -158,8 +159,8 @@ describe('Album service', () => { owner: mapUser(albumOwner), id: albumId, albumName: 'name', - createdAt: 'date', - updatedAt: 'date', + createdAt: new Date('2022-06-19T23:41:36.910Z'), + updatedAt: new Date('2022-06-19T23:41:36.910Z'), sharedUsers: [], assets: [], albumThumbnailAssetId: null, diff --git a/server/apps/immich/src/api-v1/album/dto/create-album-shared-link.dto.ts b/server/apps/immich/src/api-v1/album/dto/create-album-shared-link.dto.ts index a35e527489..bda8439814 100644 --- a/server/apps/immich/src/api-v1/album/dto/create-album-shared-link.dto.ts +++ b/server/apps/immich/src/api-v1/album/dto/create-album-shared-link.dto.ts @@ -1,15 +1,17 @@ import { ApiProperty } from '@nestjs/swagger'; import { ValidateUUID } from 'apps/immich/src/decorators/validate-uuid.decorator'; -import { IsBoolean, IsISO8601, IsOptional, IsString } from 'class-validator'; +import { Type } from 'class-transformer'; +import { IsBoolean, IsDate, IsOptional, IsString } from 'class-validator'; export class CreateAlbumShareLinkDto { @ValidateUUID() albumId!: string; - @IsISO8601() @IsOptional() - @ApiProperty({ format: 'date-time' }) - expiresAt?: string; + @IsDate() + @Type(() => Date) + @ApiProperty() + expiresAt?: Date; @IsBoolean() @IsOptional() diff --git a/server/apps/immich/src/api-v1/asset/dto/create-asset-shared-link.dto.ts b/server/apps/immich/src/api-v1/asset/dto/create-asset-shared-link.dto.ts index 3e6cb0960d..258e7009a9 100644 --- a/server/apps/immich/src/api-v1/asset/dto/create-asset-shared-link.dto.ts +++ b/server/apps/immich/src/api-v1/asset/dto/create-asset-shared-link.dto.ts @@ -1,5 +1,6 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsArray, IsBoolean, IsNotEmpty, IsOptional, IsString } from 'class-validator'; +import { Type } from 'class-transformer'; +import { IsArray, IsBoolean, IsDate, IsNotEmpty, IsOptional, IsString } from 'class-validator'; export class CreateAssetsShareLinkDto { @IsArray() @@ -17,9 +18,10 @@ export class CreateAssetsShareLinkDto { }) assetIds!: string[]; - @IsString() + @IsDate() + @Type(() => Date) @IsOptional() - expiresAt?: string; + expiresAt?: Date; @IsBoolean() @IsOptional() diff --git a/server/apps/immich/src/api-v1/tag/tag.service.spec.ts b/server/apps/immich/src/api-v1/tag/tag.service.spec.ts index 69c92f82cd..4609bb781e 100644 --- a/server/apps/immich/src/api-v1/tag/tag.service.spec.ts +++ b/server/apps/immich/src/api-v1/tag/tag.service.spec.ts @@ -21,9 +21,9 @@ describe('TagService', () => { email: 'testuser@email.com', profileImagePath: '', shouldChangePassword: true, - createdAt: '2022-12-02T19:29:23.603Z', - deletedAt: undefined, - updatedAt: '2022-12-02T19:29:23.603Z', + createdAt: new Date('2022-12-02T19:29:23.603Z'), + deletedAt: null, + updatedAt: new Date('2022-12-02T19:29:23.603Z'), tags: [], assets: [], oauthId: 'oauth-id-1', diff --git a/server/immich-openapi-specs.json b/server/immich-openapi-specs.json index 2fbf1a22a4..aa674ea604 100644 --- a/server/immich-openapi-specs.json +++ b/server/immich-openapi-specs.json @@ -4196,9 +4196,6 @@ "type": "string", "nullable": true }, - "createdAt": { - "type": "string" - }, "profileImagePath": { "type": "string" }, @@ -4208,11 +4205,17 @@ "isAdmin": { "type": "boolean" }, - "deletedAt": { + "createdAt": { "format": "date-time", "type": "string" }, + "deletedAt": { + "format": "date-time", + "type": "string", + "nullable": true + }, "updatedAt": { + "format": "date-time", "type": "string" }, "oauthId": { @@ -4225,10 +4228,12 @@ "firstName", "lastName", "storageLabel", - "createdAt", "profileImagePath", "shouldChangePassword", "isAdmin", + "createdAt", + "deletedAt", + "updatedAt", "oauthId" ] }, @@ -4536,9 +4541,11 @@ "type": "string" }, "createdAt": { + "format": "date-time", "type": "string" }, "updatedAt": { + "format": "date-time", "type": "string" }, "albumThumbnailAssetId": { @@ -4633,9 +4640,11 @@ "type": "string" }, "createdAt": { + "format": "date-time", "type": "string" }, "updatedAt": { + "format": "date-time", "type": "string" } }, @@ -4800,6 +4809,7 @@ "type": "string" }, "createdAt": { + "format": "date-time", "type": "string" } }, @@ -5396,9 +5406,11 @@ "type": "string" }, "createdAt": { + "format": "date-time", "type": "string" }, "expiresAt": { + "format": "date-time", "type": "string", "nullable": true }, @@ -5441,6 +5453,7 @@ "type": "string" }, "expiresAt": { + "format": "date-time", "type": "string", "nullable": true }, @@ -6255,6 +6268,7 @@ } }, "expiresAt": { + "format": "date-time", "type": "string" }, "allowUpload": { @@ -6393,8 +6407,8 @@ "format": "uuid" }, "expiresAt": { - "type": "string", - "format": "date-time" + "format": "date-time", + "type": "string" }, "allowUpload": { "type": "boolean" diff --git a/server/libs/domain/src/album/album.service.spec.ts b/server/libs/domain/src/album/album.service.spec.ts index 81dcd9926c..005b8e0b10 100644 --- a/server/libs/domain/src/album/album.service.spec.ts +++ b/server/libs/domain/src/album/album.service.spec.ts @@ -128,7 +128,6 @@ describe(AlbumService.name, () => { createdAt: expect.anything(), id: 'album-1', owner: { - createdAt: '2021-01-01', email: 'admin@test.com', firstName: 'admin_first_name', id: 'admin_id', @@ -138,7 +137,9 @@ describe(AlbumService.name, () => { profileImagePath: '', shouldChangePassword: false, storageLabel: 'admin', - updatedAt: '2021-01-01', + createdAt: new Date('2021-01-01'), + deletedAt: null, + updatedAt: new Date('2021-01-01'), }, ownerId: 'admin_id', shared: false, diff --git a/server/libs/domain/src/album/response-dto/album-response.dto.ts b/server/libs/domain/src/album/response-dto/album-response.dto.ts index 9f911e0208..629bc5e070 100644 --- a/server/libs/domain/src/album/response-dto/album-response.dto.ts +++ b/server/libs/domain/src/album/response-dto/album-response.dto.ts @@ -7,8 +7,8 @@ export class AlbumResponseDto { id!: string; ownerId!: string; albumName!: string; - createdAt!: string; - updatedAt!: string; + createdAt!: Date; + updatedAt!: Date; albumThumbnailAssetId!: string | null; shared!: boolean; sharedUsers!: UserResponseDto[]; diff --git a/server/libs/domain/src/api-key/api-key-response.dto.ts b/server/libs/domain/src/api-key/api-key-response.dto.ts index f7b5b5e9f9..541984179c 100644 --- a/server/libs/domain/src/api-key/api-key-response.dto.ts +++ b/server/libs/domain/src/api-key/api-key-response.dto.ts @@ -8,8 +8,8 @@ export class APIKeyCreateResponseDto { export class APIKeyResponseDto { id!: string; name!: string; - createdAt!: string; - updatedAt!: string; + createdAt!: Date; + updatedAt!: Date; } export function mapKey(entity: APIKeyEntity): APIKeyResponseDto { diff --git a/server/libs/domain/src/auth/auth.service.spec.ts b/server/libs/domain/src/auth/auth.service.spec.ts index e0a02c814c..3a3d73415d 100644 --- a/server/libs/domain/src/auth/auth.service.spec.ts +++ b/server/libs/domain/src/auth/auth.service.spec.ts @@ -231,10 +231,10 @@ describe('AuthService', () => { it('should sign up the admin', async () => { userMock.getAdmin.mockResolvedValue(null); - userMock.create.mockResolvedValue({ ...dto, id: 'admin', createdAt: 'today' } as UserEntity); + userMock.create.mockResolvedValue({ ...dto, id: 'admin', createdAt: new Date('2021-01-01') } as UserEntity); await expect(sut.adminSignUp(dto)).resolves.toEqual({ id: 'admin', - createdAt: 'today', + createdAt: new Date('2021-01-01'), email: 'test@immich.com', firstName: 'immich', lastName: 'admin', diff --git a/server/libs/domain/src/auth/response-dto/admin-signup-response.dto.ts b/server/libs/domain/src/auth/response-dto/admin-signup-response.dto.ts index 436405c903..5c2e4413ce 100644 --- a/server/libs/domain/src/auth/response-dto/admin-signup-response.dto.ts +++ b/server/libs/domain/src/auth/response-dto/admin-signup-response.dto.ts @@ -5,7 +5,7 @@ export class AdminSignupResponseDto { email!: string; firstName!: string; lastName!: string; - createdAt!: string; + createdAt!: Date; } export function mapAdminSignupResponse(entity: UserEntity): AdminSignupResponseDto { diff --git a/server/libs/domain/src/partner/partner.service.spec.ts b/server/libs/domain/src/partner/partner.service.spec.ts index b2f55ee3ab..2598567cc6 100644 --- a/server/libs/domain/src/partner/partner.service.spec.ts +++ b/server/libs/domain/src/partner/partner.service.spec.ts @@ -6,8 +6,6 @@ import { PartnerService } from './partner.service'; const responseDto = { admin: { - createdAt: '2021-01-01', - deletedAt: undefined, email: 'admin@test.com', firstName: 'admin_first_name', id: 'admin_id', @@ -16,12 +14,12 @@ const responseDto = { oauthId: '', profileImagePath: '', shouldChangePassword: false, - updatedAt: '2021-01-01', storageLabel: 'admin', + createdAt: new Date('2021-01-01'), + deletedAt: null, + updatedAt: new Date('2021-01-01'), }, user1: { - createdAt: '2021-01-01', - deletedAt: undefined, email: 'immich@test.com', firstName: 'immich_first_name', id: 'user-id', @@ -30,8 +28,10 @@ const responseDto = { oauthId: '', profileImagePath: '', shouldChangePassword: false, - updatedAt: '2021-01-01', storageLabel: null, + createdAt: new Date('2021-01-01'), + deletedAt: null, + updatedAt: new Date('2021-01-01'), }, }; diff --git a/server/libs/domain/src/share/dto/create-shared-link.dto.ts b/server/libs/domain/src/share/dto/create-shared-link.dto.ts index 7f5af8b08e..db82021c6a 100644 --- a/server/libs/domain/src/share/dto/create-shared-link.dto.ts +++ b/server/libs/domain/src/share/dto/create-shared-link.dto.ts @@ -2,7 +2,7 @@ import { AlbumEntity, AssetEntity, SharedLinkType } from '@app/infra/entities'; export class CreateSharedLinkDto { description?: string; - expiresAt?: string; + expiresAt?: Date; type!: SharedLinkType; assets!: AssetEntity[]; album?: AlbumEntity; diff --git a/server/libs/domain/src/share/dto/edit-shared-link.dto.ts b/server/libs/domain/src/share/dto/edit-shared-link.dto.ts index 92ea2619ad..f35f5ed9ac 100644 --- a/server/libs/domain/src/share/dto/edit-shared-link.dto.ts +++ b/server/libs/domain/src/share/dto/edit-shared-link.dto.ts @@ -5,7 +5,7 @@ export class EditSharedLinkDto { description?: string; @IsOptional() - expiresAt?: string | null; + expiresAt?: Date | null; @IsOptional() allowUpload?: boolean; diff --git a/server/libs/domain/src/share/response-dto/shared-link-response.dto.ts b/server/libs/domain/src/share/response-dto/shared-link-response.dto.ts index 2618a264c7..bb76567896 100644 --- a/server/libs/domain/src/share/response-dto/shared-link-response.dto.ts +++ b/server/libs/domain/src/share/response-dto/shared-link-response.dto.ts @@ -12,8 +12,8 @@ export class SharedLinkResponseDto { @ApiProperty({ enumName: 'SharedLinkType', enum: SharedLinkType }) type!: SharedLinkType; - createdAt!: string; - expiresAt!: string | null; + createdAt!: Date; + expiresAt!: Date | null; assets!: AssetResponseDto[]; album?: AlbumResponseDto; allowUpload!: boolean; diff --git a/server/libs/domain/src/share/share.core.ts b/server/libs/domain/src/share/share.core.ts index 4229999a4e..706650a7b7 100644 --- a/server/libs/domain/src/share/share.core.ts +++ b/server/libs/domain/src/share/share.core.ts @@ -23,7 +23,7 @@ export class ShareCore { key: Buffer.from(this.cryptoRepository.randomBytes(50)), description: dto.description, userId, - createdAt: new Date().toISOString(), + createdAt: new Date(), expiresAt: dto.expiresAt ?? null, type: dto.type, assets: dto.assets, diff --git a/server/libs/domain/src/user/response-dto/user-response.dto.ts b/server/libs/domain/src/user/response-dto/user-response.dto.ts index 53da95fd52..6ad8e848c4 100644 --- a/server/libs/domain/src/user/response-dto/user-response.dto.ts +++ b/server/libs/domain/src/user/response-dto/user-response.dto.ts @@ -6,12 +6,12 @@ export class UserResponseDto { firstName!: string; lastName!: string; storageLabel!: string | null; - createdAt!: string; profileImagePath!: string; shouldChangePassword!: boolean; isAdmin!: boolean; - deletedAt?: Date; - updatedAt?: string; + createdAt!: Date; + deletedAt!: Date | null; + updatedAt!: Date; oauthId!: string; } @@ -22,10 +22,10 @@ export function mapUser(entity: UserEntity): UserResponseDto { firstName: entity.firstName, lastName: entity.lastName, storageLabel: entity.storageLabel, - createdAt: entity.createdAt, profileImagePath: entity.profileImagePath, shouldChangePassword: entity.shouldChangePassword, isAdmin: entity.isAdmin, + createdAt: entity.createdAt, deletedAt: entity.deletedAt, updatedAt: entity.updatedAt, oauthId: entity.oauthId, diff --git a/server/libs/domain/src/user/user.service.spec.ts b/server/libs/domain/src/user/user.service.spec.ts index 895d86bfca..1fbe5cccbb 100644 --- a/server/libs/domain/src/user/user.service.spec.ts +++ b/server/libs/domain/src/user/user.service.spec.ts @@ -47,8 +47,9 @@ const adminUser: UserEntity = Object.freeze({ oauthId: '', shouldChangePassword: false, profileImagePath: '', - createdAt: '2021-01-01', - updatedAt: '2021-01-01', + createdAt: new Date('2021-01-01'), + deletedAt: null, + updatedAt: new Date('2021-01-01'), tags: [], assets: [], storageLabel: 'admin', @@ -64,8 +65,9 @@ const immichUser: UserEntity = Object.freeze({ oauthId: '', shouldChangePassword: false, profileImagePath: '', - createdAt: '2021-01-01', - updatedAt: '2021-01-01', + createdAt: new Date('2021-01-01'), + deletedAt: null, + updatedAt: new Date('2021-01-01'), tags: [], assets: [], storageLabel: null, @@ -81,8 +83,9 @@ const updatedImmichUser: UserEntity = Object.freeze({ oauthId: '', shouldChangePassword: true, profileImagePath: '', - createdAt: '2021-01-01', - updatedAt: '2021-01-01', + createdAt: new Date('2021-01-01'), + deletedAt: null, + updatedAt: new Date('2021-01-01'), tags: [], assets: [], storageLabel: null, @@ -91,15 +94,15 @@ const updatedImmichUser: UserEntity = Object.freeze({ const adminUserResponse = Object.freeze({ id: adminUserAuth.id, email: 'admin@test.com', - deletedAt: undefined, firstName: 'admin_first_name', lastName: 'admin_last_name', isAdmin: true, oauthId: '', shouldChangePassword: false, profileImagePath: '', - createdAt: '2021-01-01', - updatedAt: '2021-01-01', + createdAt: new Date('2021-01-01'), + deletedAt: null, + updatedAt: new Date('2021-01-01'), storageLabel: 'admin', }); @@ -140,15 +143,15 @@ describe(UserService.name, () => { { id: adminUserAuth.id, email: 'admin@test.com', - deletedAt: undefined, firstName: 'admin_first_name', lastName: 'admin_last_name', isAdmin: true, oauthId: '', shouldChangePassword: false, profileImagePath: '', - createdAt: '2021-01-01', - updatedAt: '2021-01-01', + createdAt: new Date('2021-01-01'), + deletedAt: null, + updatedAt: new Date('2021-01-01'), storageLabel: 'admin', }, ]); diff --git a/server/libs/domain/test/fixtures.ts b/server/libs/domain/test/fixtures.ts index da420346fe..3d00e7f249 100644 --- a/server/libs/domain/test/fixtures.ts +++ b/server/libs/domain/test/fixtures.ts @@ -85,8 +85,9 @@ export const userEntityStub = { oauthId: '', shouldChangePassword: false, profileImagePath: '', - createdAt: '2021-01-01', - updatedAt: '2021-01-01', + createdAt: new Date('2021-01-01'), + deletedAt: null, + updatedAt: new Date('2021-01-01'), tags: [], assets: [], }), @@ -99,8 +100,9 @@ export const userEntityStub = { oauthId: '', shouldChangePassword: false, profileImagePath: '', - createdAt: '2021-01-01', - updatedAt: '2021-01-01', + createdAt: new Date('2021-01-01'), + deletedAt: null, + updatedAt: new Date('2021-01-01'), tags: [], assets: [], }), @@ -113,8 +115,9 @@ export const userEntityStub = { oauthId: '', shouldChangePassword: false, profileImagePath: '', - createdAt: '2021-01-01', - updatedAt: '2021-01-01', + createdAt: new Date('2021-01-01'), + deletedAt: null, + updatedAt: new Date('2021-01-01'), tags: [], assets: [], }), @@ -317,8 +320,8 @@ export const albumStub = { assets: [], albumThumbnailAsset: null, albumThumbnailAssetId: null, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + createdAt: new Date(), + updatedAt: new Date(), sharedLinks: [], sharedUsers: [], }), @@ -330,8 +333,8 @@ export const albumStub = { assets: [], albumThumbnailAsset: null, albumThumbnailAssetId: null, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + createdAt: new Date(), + updatedAt: new Date(), sharedLinks: [], sharedUsers: [userEntityStub.user1], }), @@ -343,8 +346,8 @@ export const albumStub = { assets: [], albumThumbnailAsset: null, albumThumbnailAssetId: null, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + createdAt: new Date(), + updatedAt: new Date(), sharedLinks: [], sharedUsers: [userEntityStub.admin], }), @@ -356,8 +359,8 @@ export const albumStub = { assets: [assetEntityStub.image], albumThumbnailAsset: null, albumThumbnailAssetId: null, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + createdAt: new Date(), + updatedAt: new Date(), sharedLinks: [], sharedUsers: [], }), @@ -369,8 +372,8 @@ export const albumStub = { assets: [], albumThumbnailAsset: assetEntityStub.image, albumThumbnailAssetId: assetEntityStub.image.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + createdAt: new Date(), + updatedAt: new Date(), sharedLinks: [], sharedUsers: [], }), @@ -382,8 +385,8 @@ export const albumStub = { assets: [], albumThumbnailAsset: null, albumThumbnailAssetId: null, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + createdAt: new Date(), + updatedAt: new Date(), sharedLinks: [], sharedUsers: [], }), @@ -395,8 +398,8 @@ export const albumStub = { assets: [assetEntityStub.image], albumThumbnailAsset: assetEntityStub.livePhotoMotionAsset, albumThumbnailAssetId: assetEntityStub.livePhotoMotionAsset.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + createdAt: new Date(), + updatedAt: new Date(), sharedLinks: [], sharedUsers: [], }), @@ -408,8 +411,8 @@ export const albumStub = { assets: [assetEntityStub.image], albumThumbnailAsset: assetEntityStub.image, albumThumbnailAssetId: assetEntityStub.image.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + createdAt: new Date(), + updatedAt: new Date(), sharedLinks: [], sharedUsers: [], }), @@ -468,8 +471,8 @@ const assetResponse: AssetResponseDto = { const albumResponse: AlbumResponseDto = { albumName: 'Test Album', albumThumbnailAssetId: null, - createdAt: today.toISOString(), - updatedAt: today.toISOString(), + createdAt: today, + updatedAt: today, id: 'album-123', ownerId: 'admin_id', owner: mapUser(userEntityStub.admin), @@ -645,8 +648,8 @@ export const sharedLinkStub = { user: userEntityStub.admin, key: Buffer.from('secret-key', 'utf8'), type: SharedLinkType.ALBUM, - createdAt: today.toISOString(), - expiresAt: tomorrow.toISOString(), + createdAt: today, + expiresAt: tomorrow, allowUpload: true, allowDownload: true, showExif: true, @@ -659,8 +662,8 @@ export const sharedLinkStub = { user: userEntityStub.admin, key: Buffer.from('secret-key', 'utf8'), type: SharedLinkType.ALBUM, - createdAt: today.toISOString(), - expiresAt: yesterday.toISOString(), + createdAt: today, + expiresAt: yesterday, allowUpload: true, allowDownload: true, showExif: true, @@ -672,8 +675,8 @@ export const sharedLinkStub = { user: userEntityStub.admin, key: Buffer.from('secret-key', 'utf8'), type: SharedLinkType.ALBUM, - createdAt: today.toISOString(), - expiresAt: tomorrow.toISOString(), + createdAt: today, + expiresAt: tomorrow, allowUpload: false, allowDownload: false, showExif: true, @@ -683,8 +686,8 @@ export const sharedLinkStub = { ownerId: authStub.admin.id, owner: userEntityStub.admin, albumName: 'Test Album', - createdAt: today.toISOString(), - updatedAt: today.toISOString(), + createdAt: today, + updatedAt: today, albumThumbnailAsset: null, albumThumbnailAssetId: null, sharedUsers: [], @@ -763,9 +766,9 @@ export const sharedLinkResponseStub = { allowDownload: true, allowUpload: true, assets: [], - createdAt: today.toISOString(), + createdAt: today, description: undefined, - expiresAt: tomorrow.toISOString(), + expiresAt: tomorrow, id: '123', key: '7365637265742d6b6579', showExif: true, @@ -777,9 +780,9 @@ export const sharedLinkResponseStub = { allowDownload: true, allowUpload: true, assets: [], - createdAt: today.toISOString(), + createdAt: today, description: undefined, - expiresAt: yesterday.toISOString(), + expiresAt: yesterday, id: '123', key: '7365637265742d6b6579', showExif: true, @@ -791,8 +794,8 @@ export const sharedLinkResponseStub = { userId: 'admin_id', key: '7365637265742d6b6579', type: SharedLinkType.ALBUM, - createdAt: today.toISOString(), - expiresAt: tomorrow.toISOString(), + createdAt: today, + expiresAt: tomorrow, description: undefined, allowUpload: false, allowDownload: false, @@ -805,8 +808,8 @@ export const sharedLinkResponseStub = { userId: 'admin_id', key: '7365637265742d6b6579', type: SharedLinkType.ALBUM, - createdAt: today.toISOString(), - expiresAt: tomorrow.toISOString(), + createdAt: today, + expiresAt: tomorrow, description: undefined, allowUpload: false, allowDownload: false, diff --git a/server/libs/infra/src/entities/album.entity.ts b/server/libs/infra/src/entities/album.entity.ts index 6dcebf8a17..6dd4b92740 100644 --- a/server/libs/infra/src/entities/album.entity.ts +++ b/server/libs/infra/src/entities/album.entity.ts @@ -28,10 +28,10 @@ export class AlbumEntity { albumName!: string; @CreateDateColumn({ type: 'timestamptz' }) - createdAt!: string; + createdAt!: Date; @UpdateDateColumn({ type: 'timestamptz' }) - updatedAt!: string; + updatedAt!: Date; @ManyToOne(() => AssetEntity, { nullable: true, onDelete: 'SET NULL', onUpdate: 'CASCADE' }) albumThumbnailAsset!: AssetEntity | null; diff --git a/server/libs/infra/src/entities/api-key.entity.ts b/server/libs/infra/src/entities/api-key.entity.ts index 54108832d8..0c8252fe43 100644 --- a/server/libs/infra/src/entities/api-key.entity.ts +++ b/server/libs/infra/src/entities/api-key.entity.ts @@ -19,8 +19,8 @@ export class APIKeyEntity { userId!: string; @CreateDateColumn({ type: 'timestamptz' }) - createdAt!: string; + createdAt!: Date; @UpdateDateColumn({ type: 'timestamptz' }) - updatedAt!: string; + updatedAt!: Date; } diff --git a/server/libs/infra/src/entities/shared-link.entity.ts b/server/libs/infra/src/entities/shared-link.entity.ts index 231b3a9660..7bca8dddf4 100644 --- a/server/libs/infra/src/entities/shared-link.entity.ts +++ b/server/libs/infra/src/entities/shared-link.entity.ts @@ -35,10 +35,10 @@ export class SharedLinkEntity { type!: SharedLinkType; @CreateDateColumn({ type: 'timestamptz' }) - createdAt!: string; + createdAt!: Date; @Column({ type: 'timestamptz', nullable: true }) - expiresAt!: string | null; + expiresAt!: Date | null; @Column({ type: 'boolean', default: false }) allowUpload!: boolean; diff --git a/server/libs/infra/src/entities/user.entity.ts b/server/libs/infra/src/entities/user.entity.ts index 06c6981263..f175a603c3 100644 --- a/server/libs/infra/src/entities/user.entity.ts +++ b/server/libs/infra/src/entities/user.entity.ts @@ -42,14 +42,14 @@ export class UserEntity { @Column({ default: true }) shouldChangePassword!: boolean; - @CreateDateColumn() - createdAt!: string; + @CreateDateColumn({ type: 'timestamptz' }) + createdAt!: Date; - @DeleteDateColumn() - deletedAt?: Date; + @DeleteDateColumn({ type: 'timestamptz' }) + deletedAt!: Date | null; @UpdateDateColumn({ type: 'timestamptz' }) - updatedAt!: string; + updatedAt!: Date; @OneToMany(() => TagEntity, (tag) => tag.user) tags!: TagEntity[]; diff --git a/server/libs/infra/src/migrations/1685370430343-UserDatesTimestamptz.ts b/server/libs/infra/src/migrations/1685370430343-UserDatesTimestamptz.ts new file mode 100644 index 0000000000..0a70e012d8 --- /dev/null +++ b/server/libs/infra/src/migrations/1685370430343-UserDatesTimestamptz.ts @@ -0,0 +1,16 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class UserDatesTimestamptz1685370430343 implements MigrationInterface { + name = 'UserDatesTimestamptz1685370430343' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "createdAt" TYPE TIMESTAMP WITH TIME ZONE`); + await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "deletedAt" TYPE TIMESTAMP WITH TIME ZONE`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "deletedAt" TYPE TIMESTAMP`); + await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "createdAt" TYPE TIMESTAMP`); + } + +} diff --git a/web/src/api/open-api/api.ts b/web/src/api/open-api/api.ts index 269fd55c10..cc4a6355e9 100644 --- a/web/src/api/open-api/api.ts +++ b/web/src/api/open-api/api.ts @@ -2712,12 +2712,6 @@ export interface UserResponseDto { * @memberof UserResponseDto */ 'storageLabel': string | null; - /** - * - * @type {string} - * @memberof UserResponseDto - */ - 'createdAt': string; /** * * @type {string} @@ -2741,13 +2735,19 @@ export interface UserResponseDto { * @type {string} * @memberof UserResponseDto */ - 'deletedAt'?: string; + 'createdAt': string; /** * * @type {string} * @memberof UserResponseDto */ - 'updatedAt'?: string; + 'deletedAt': string | null; + /** + * + * @type {string} + * @memberof UserResponseDto + */ + 'updatedAt': string; /** * * @type {string}