mirror of
https://github.com/immich-app/immich.git
synced 2026-03-22 16:29:27 +03:00
fix(server): accept showAt and hideAt for creating memories (#26429)
* fix(server): accept showAt and hideAt for creating memories * fix history
This commit is contained in:
38
mobile/openapi/lib/model/memory_create_dto.dart
generated
38
mobile/openapi/lib/model/memory_create_dto.dart
generated
@@ -15,9 +15,11 @@ class MemoryCreateDto {
|
|||||||
MemoryCreateDto({
|
MemoryCreateDto({
|
||||||
this.assetIds = const [],
|
this.assetIds = const [],
|
||||||
required this.data,
|
required this.data,
|
||||||
|
this.hideAt,
|
||||||
this.isSaved,
|
this.isSaved,
|
||||||
required this.memoryAt,
|
required this.memoryAt,
|
||||||
this.seenAt,
|
this.seenAt,
|
||||||
|
this.showAt,
|
||||||
required this.type,
|
required this.type,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -26,6 +28,15 @@ class MemoryCreateDto {
|
|||||||
|
|
||||||
OnThisDayDto data;
|
OnThisDayDto data;
|
||||||
|
|
||||||
|
/// Date when memory should be hidden
|
||||||
|
///
|
||||||
|
/// Please note: This property should have been non-nullable! Since the specification file
|
||||||
|
/// does not include a default value (using the "default:" property), however, the generated
|
||||||
|
/// source code must fall back to having a nullable type.
|
||||||
|
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||||
|
///
|
||||||
|
DateTime? hideAt;
|
||||||
|
|
||||||
/// Is memory saved
|
/// Is memory saved
|
||||||
///
|
///
|
||||||
/// Please note: This property should have been non-nullable! Since the specification file
|
/// Please note: This property should have been non-nullable! Since the specification file
|
||||||
@@ -47,6 +58,15 @@ class MemoryCreateDto {
|
|||||||
///
|
///
|
||||||
DateTime? seenAt;
|
DateTime? seenAt;
|
||||||
|
|
||||||
|
/// Date when memory should be shown
|
||||||
|
///
|
||||||
|
/// Please note: This property should have been non-nullable! Since the specification file
|
||||||
|
/// does not include a default value (using the "default:" property), however, the generated
|
||||||
|
/// source code must fall back to having a nullable type.
|
||||||
|
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||||
|
///
|
||||||
|
DateTime? showAt;
|
||||||
|
|
||||||
/// Memory type
|
/// Memory type
|
||||||
MemoryType type;
|
MemoryType type;
|
||||||
|
|
||||||
@@ -54,9 +74,11 @@ class MemoryCreateDto {
|
|||||||
bool operator ==(Object other) => identical(this, other) || other is MemoryCreateDto &&
|
bool operator ==(Object other) => identical(this, other) || other is MemoryCreateDto &&
|
||||||
_deepEquality.equals(other.assetIds, assetIds) &&
|
_deepEquality.equals(other.assetIds, assetIds) &&
|
||||||
other.data == data &&
|
other.data == data &&
|
||||||
|
other.hideAt == hideAt &&
|
||||||
other.isSaved == isSaved &&
|
other.isSaved == isSaved &&
|
||||||
other.memoryAt == memoryAt &&
|
other.memoryAt == memoryAt &&
|
||||||
other.seenAt == seenAt &&
|
other.seenAt == seenAt &&
|
||||||
|
other.showAt == showAt &&
|
||||||
other.type == type;
|
other.type == type;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -64,18 +86,25 @@ class MemoryCreateDto {
|
|||||||
// ignore: unnecessary_parenthesis
|
// ignore: unnecessary_parenthesis
|
||||||
(assetIds.hashCode) +
|
(assetIds.hashCode) +
|
||||||
(data.hashCode) +
|
(data.hashCode) +
|
||||||
|
(hideAt == null ? 0 : hideAt!.hashCode) +
|
||||||
(isSaved == null ? 0 : isSaved!.hashCode) +
|
(isSaved == null ? 0 : isSaved!.hashCode) +
|
||||||
(memoryAt.hashCode) +
|
(memoryAt.hashCode) +
|
||||||
(seenAt == null ? 0 : seenAt!.hashCode) +
|
(seenAt == null ? 0 : seenAt!.hashCode) +
|
||||||
|
(showAt == null ? 0 : showAt!.hashCode) +
|
||||||
(type.hashCode);
|
(type.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'MemoryCreateDto[assetIds=$assetIds, data=$data, isSaved=$isSaved, memoryAt=$memoryAt, seenAt=$seenAt, type=$type]';
|
String toString() => 'MemoryCreateDto[assetIds=$assetIds, data=$data, hideAt=$hideAt, isSaved=$isSaved, memoryAt=$memoryAt, seenAt=$seenAt, showAt=$showAt, type=$type]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
json[r'assetIds'] = this.assetIds;
|
json[r'assetIds'] = this.assetIds;
|
||||||
json[r'data'] = this.data;
|
json[r'data'] = this.data;
|
||||||
|
if (this.hideAt != null) {
|
||||||
|
json[r'hideAt'] = this.hideAt!.toUtc().toIso8601String();
|
||||||
|
} else {
|
||||||
|
// json[r'hideAt'] = null;
|
||||||
|
}
|
||||||
if (this.isSaved != null) {
|
if (this.isSaved != null) {
|
||||||
json[r'isSaved'] = this.isSaved;
|
json[r'isSaved'] = this.isSaved;
|
||||||
} else {
|
} else {
|
||||||
@@ -86,6 +115,11 @@ class MemoryCreateDto {
|
|||||||
json[r'seenAt'] = this.seenAt!.toUtc().toIso8601String();
|
json[r'seenAt'] = this.seenAt!.toUtc().toIso8601String();
|
||||||
} else {
|
} else {
|
||||||
// json[r'seenAt'] = null;
|
// json[r'seenAt'] = null;
|
||||||
|
}
|
||||||
|
if (this.showAt != null) {
|
||||||
|
json[r'showAt'] = this.showAt!.toUtc().toIso8601String();
|
||||||
|
} else {
|
||||||
|
// json[r'showAt'] = null;
|
||||||
}
|
}
|
||||||
json[r'type'] = this.type;
|
json[r'type'] = this.type;
|
||||||
return json;
|
return json;
|
||||||
@@ -104,9 +138,11 @@ class MemoryCreateDto {
|
|||||||
? (json[r'assetIds'] as Iterable).cast<String>().toList(growable: false)
|
? (json[r'assetIds'] as Iterable).cast<String>().toList(growable: false)
|
||||||
: const [],
|
: const [],
|
||||||
data: OnThisDayDto.fromJson(json[r'data'])!,
|
data: OnThisDayDto.fromJson(json[r'data'])!,
|
||||||
|
hideAt: mapDateTime(json, r'hideAt', r''),
|
||||||
isSaved: mapValueOfType<bool>(json, r'isSaved'),
|
isSaved: mapValueOfType<bool>(json, r'isSaved'),
|
||||||
memoryAt: mapDateTime(json, r'memoryAt', r'')!,
|
memoryAt: mapDateTime(json, r'memoryAt', r'')!,
|
||||||
seenAt: mapDateTime(json, r'seenAt', r''),
|
seenAt: mapDateTime(json, r'seenAt', r''),
|
||||||
|
showAt: mapDateTime(json, r'showAt', r''),
|
||||||
type: MemoryType.fromJson(json[r'type'])!,
|
type: MemoryType.fromJson(json[r'type'])!,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18651,6 +18651,22 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"$ref": "#/components/schemas/OnThisDayDto"
|
"$ref": "#/components/schemas/OnThisDayDto"
|
||||||
},
|
},
|
||||||
|
"hideAt": {
|
||||||
|
"description": "Date when memory should be hidden",
|
||||||
|
"format": "date-time",
|
||||||
|
"type": "string",
|
||||||
|
"x-immich-history": [
|
||||||
|
{
|
||||||
|
"version": "v2.6.0",
|
||||||
|
"state": "Added"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v2.6.0",
|
||||||
|
"state": "Stable"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"x-immich-state": "Stable"
|
||||||
|
},
|
||||||
"isSaved": {
|
"isSaved": {
|
||||||
"description": "Is memory saved",
|
"description": "Is memory saved",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@@ -18665,6 +18681,22 @@
|
|||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"showAt": {
|
||||||
|
"description": "Date when memory should be shown",
|
||||||
|
"format": "date-time",
|
||||||
|
"type": "string",
|
||||||
|
"x-immich-history": [
|
||||||
|
{
|
||||||
|
"version": "v2.6.0",
|
||||||
|
"state": "Added"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v2.6.0",
|
||||||
|
"state": "Stable"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"x-immich-state": "Stable"
|
||||||
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1404,12 +1404,16 @@ export type MemoryCreateDto = {
|
|||||||
/** Asset IDs to associate with memory */
|
/** Asset IDs to associate with memory */
|
||||||
assetIds?: string[];
|
assetIds?: string[];
|
||||||
data: OnThisDayDto;
|
data: OnThisDayDto;
|
||||||
|
/** Date when memory should be hidden */
|
||||||
|
hideAt?: string;
|
||||||
/** Is memory saved */
|
/** Is memory saved */
|
||||||
isSaved?: boolean;
|
isSaved?: boolean;
|
||||||
/** Memory date */
|
/** Memory date */
|
||||||
memoryAt: string;
|
memoryAt: string;
|
||||||
/** Date when memory was seen */
|
/** Date when memory was seen */
|
||||||
seenAt?: string;
|
seenAt?: string;
|
||||||
|
/** Date when memory should be shown */
|
||||||
|
showAt?: string;
|
||||||
/** Memory type */
|
/** Memory type */
|
||||||
"type": MemoryType;
|
"type": MemoryType;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -51,6 +51,20 @@ describe(MemoryController.name, () => {
|
|||||||
errorDto.badRequest(['data.year must be a positive number', 'data.year must be an integer number']),
|
errorDto.badRequest(['data.year must be a positive number', 'data.year must be an integer number']),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should accept showAt and hideAt', async () => {
|
||||||
|
const { status } = await request(ctx.getHttpServer())
|
||||||
|
.post('/memories')
|
||||||
|
.send({
|
||||||
|
type: 'on_this_day',
|
||||||
|
data: { year: 2020 },
|
||||||
|
memoryAt: new Date(2021).toISOString(),
|
||||||
|
showAt: new Date(2022).toISOString(),
|
||||||
|
hideAt: new Date(2023).toISOString(),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(status).toBe(201);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET /memories/statistics', () => {
|
describe('GET /memories/statistics', () => {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ApiProperty } from '@nestjs/swagger';
|
|||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
import { IsInt, IsObject, IsPositive, ValidateNested } from 'class-validator';
|
import { IsInt, IsObject, IsPositive, ValidateNested } from 'class-validator';
|
||||||
import { Memory } from 'src/database';
|
import { Memory } from 'src/database';
|
||||||
|
import { HistoryBuilder } from 'src/decorators';
|
||||||
import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto';
|
import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
import { AssetOrderWithRandom, MemoryType } from 'src/enum';
|
import { AssetOrderWithRandom, MemoryType } from 'src/enum';
|
||||||
@@ -77,6 +78,20 @@ export class MemoryCreateDto extends MemoryBaseDto {
|
|||||||
@ValidateDate({ description: 'Memory date' })
|
@ValidateDate({ description: 'Memory date' })
|
||||||
memoryAt!: Date;
|
memoryAt!: Date;
|
||||||
|
|
||||||
|
@ValidateDate({
|
||||||
|
optional: true,
|
||||||
|
description: 'Date when memory should be shown',
|
||||||
|
history: new HistoryBuilder().added('v2.6.0').stable('v2.6.0'),
|
||||||
|
})
|
||||||
|
showAt?: Date;
|
||||||
|
|
||||||
|
@ValidateDate({
|
||||||
|
optional: true,
|
||||||
|
description: 'Date when memory should be hidden',
|
||||||
|
history: new HistoryBuilder().added('v2.6.0').stable('v2.6.0'),
|
||||||
|
})
|
||||||
|
hideAt?: Date;
|
||||||
|
|
||||||
@ValidateUUID({ optional: true, each: true, description: 'Asset IDs to associate with memory' })
|
@ValidateUUID({ optional: true, each: true, description: 'Asset IDs to associate with memory' })
|
||||||
assetIds?: string[];
|
assetIds?: string[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,8 @@ export class MemoryService extends BaseService {
|
|||||||
data: dto.data,
|
data: dto.data,
|
||||||
isSaved: dto.isSaved,
|
isSaved: dto.isSaved,
|
||||||
memoryAt: dto.memoryAt,
|
memoryAt: dto.memoryAt,
|
||||||
|
showAt: dto.showAt,
|
||||||
|
hideAt: dto.hideAt,
|
||||||
seenAt: dto.seenAt,
|
seenAt: dto.seenAt,
|
||||||
},
|
},
|
||||||
allowedAssetIds,
|
allowedAssetIds,
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ export const ValidateHexColor = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type DateOptions = OptionalOptions & { optional?: boolean; format?: 'date' | 'date-time' };
|
type DateOptions = OptionalOptions & { optional?: boolean; format?: 'date' | 'date-time' };
|
||||||
export const ValidateDate = (options?: DateOptions & ApiPropertyOptions) => {
|
export const ValidateDate = (options?: DateOptions & PropertyOptions) => {
|
||||||
const {
|
const {
|
||||||
optional,
|
optional,
|
||||||
nullable = false,
|
nullable = false,
|
||||||
@@ -243,7 +243,7 @@ export const ValidateDate = (options?: DateOptions & ApiPropertyOptions) => {
|
|||||||
} = options || {};
|
} = options || {};
|
||||||
|
|
||||||
return applyDecorators(
|
return applyDecorators(
|
||||||
ApiProperty({ format, ...apiPropertyOptions }),
|
Property({ format, ...apiPropertyOptions }),
|
||||||
IsDate(),
|
IsDate(),
|
||||||
optional ? Optional({ nullable, emptyToNull }) : IsNotEmpty(),
|
optional ? Optional({ nullable, emptyToNull }) : IsNotEmpty(),
|
||||||
Transform(({ key, value }) => {
|
Transform(({ key, value }) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user