mirror of
https://github.com/immich-app/immich
synced 2026-08-15 13:03:57 +00:00
fix(server): require at least one field to be set when updating memory (#27842)
* add zod util to require one field is set in some schemas. appy to update memory endpoint * add test
This commit is contained in:
parent
9d33853544
commit
6798d5df32
3 changed files with 28 additions and 8 deletions
|
|
@ -96,6 +96,12 @@ describe(MemoryController.name, () => {
|
||||||
expect(status).toBe(400);
|
expect(status).toBe(400);
|
||||||
expect(body).toEqual(errorDto.badRequest(['Invalid input: expected object, received undefined']));
|
expect(body).toEqual(errorDto.badRequest(['Invalid input: expected object, received undefined']));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should require at least one field', async () => {
|
||||||
|
const { status, body } = await request(ctx.getHttpServer()).put(`/memories/${factory.uuid()}`).send({});
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.badRequest(['At least one field must be provided']));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('DELETE /memories/:id', () => {
|
describe('DELETE /memories/:id', () => {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { HistoryBuilder } from 'src/decorators';
|
||||||
import { AssetResponseSchema, mapAsset } from 'src/dtos/asset-response.dto';
|
import { AssetResponseSchema, mapAsset } from 'src/dtos/asset-response.dto';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
import { AssetOrderWithRandomSchema, MemoryType, MemoryTypeSchema } from 'src/enum';
|
import { AssetOrderWithRandomSchema, MemoryType, MemoryTypeSchema } from 'src/enum';
|
||||||
import { isoDatetimeToDate, stringToBool } from 'src/validation';
|
import { isoDatetimeToDate, nonEmptyPartial, stringToBool } from 'src/validation';
|
||||||
import z from 'zod';
|
import z from 'zod';
|
||||||
|
|
||||||
const MemorySearchSchema = z
|
const MemorySearchSchema = z
|
||||||
|
|
@ -26,13 +26,11 @@ const OnThisDaySchema = z
|
||||||
|
|
||||||
type MemoryData = z.infer<typeof OnThisDaySchema>;
|
type MemoryData = z.infer<typeof OnThisDaySchema>;
|
||||||
|
|
||||||
const MemoryUpdateSchema = z
|
const MemoryUpdateSchema = nonEmptyPartial({
|
||||||
.object({
|
isSaved: z.boolean().describe('Is memory saved'),
|
||||||
isSaved: z.boolean().optional().describe('Is memory saved'),
|
seenAt: isoDatetimeToDate.describe('Date when memory was seen'),
|
||||||
seenAt: isoDatetimeToDate.optional().describe('Date when memory was seen'),
|
memoryAt: isoDatetimeToDate.describe('Memory date'),
|
||||||
memoryAt: isoDatetimeToDate.optional().describe('Memory date'),
|
}).meta({ id: 'MemoryUpdateDto' });
|
||||||
})
|
|
||||||
.meta({ id: 'MemoryUpdateDto' });
|
|
||||||
|
|
||||||
const MemoryCreateSchema = z
|
const MemoryCreateSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,22 @@ export function IsIPRange(options?: IsIPRangeOptions) {
|
||||||
.refine((arr) => arr.every((item) => isIPOrRange(item, options)), 'Must be an ip address or ip address range');
|
.refine((arr) => arr.every((item) => isIPOrRange(item, options)), 'Must be an ip address or ip address range');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like z.object().partial(), but rejects objects where every field is undefined.
|
||||||
|
* Use for update/patch DTOs where at least one field must be provided.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* nonEmptyPartial({ name: z.string(), bio: z.string() }).meta({ id: 'UpdateDto' });
|
||||||
|
*/
|
||||||
|
export function nonEmptyPartial<T extends z.ZodRawShape>(shape: T) {
|
||||||
|
return z
|
||||||
|
.object(shape)
|
||||||
|
.partial()
|
||||||
|
.refine((data) => Object.values(data as Record<string, unknown>).some((value) => value !== undefined), {
|
||||||
|
message: 'At least one field must be provided',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zod schema that validates sibling-exclusion for object schemas.
|
* Zod schema that validates sibling-exclusion for object schemas.
|
||||||
* Validation passes when the target property is missing, or when none of the sibling properties are present.
|
* Validation passes when the target property is missing, or when none of the sibling properties are present.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue