diff --git a/packages/plugin-core/src/index.ts b/packages/plugin-core/src/index.ts index 251393ace..ec6a3bb69 100644 --- a/packages/plugin-core/src/index.ts +++ b/packages/plugin-core/src/index.ts @@ -187,7 +187,7 @@ const methods = wrapper({ for (const tag of config.tags) { if (assetTags.includes(tag)) { if (config.matching === 'any') { - break; + return { workflow: { continue: true } }; } else if (config.matching === 'none') { return { workflow: { continue: false } }; } @@ -196,7 +196,7 @@ const methods = wrapper({ } } - return { workflow: { continue: true } }; + return { workflow: { continue: config.matching !== 'any' } }; }, assetTypeFilter: ({ config, data }) => { diff --git a/server/test/medium/specs/workflow/workflow-core-plugin.spec.ts b/server/test/medium/specs/workflow/workflow-core-plugin.spec.ts index 6ae7a8ba7..77a8cdce7 100644 --- a/server/test/medium/specs/workflow/workflow-core-plugin.spec.ts +++ b/server/test/medium/specs/workflow/workflow-core-plugin.spec.ts @@ -21,6 +21,7 @@ import { WorkflowExecutionService } from 'src/services/workflow-execution.servic import { resolveMethod } from 'src/utils/workflow.js'; import { MediumTestContext } from 'test/medium.factory.js'; import { mockEnvData } from 'test/repositories/config.repository.mock.js'; +import { newUuid } from 'test/small.factory.js'; import { getKyselyDB } from 'test/utils.js'; let isInitialized = false; @@ -602,6 +603,126 @@ describe('core plugin', () => { }); }); + describe('assetTagFilter', () => { + it('should favorite asset if it matches any tag', async () => { + const { user } = await ctx.newUser(); + const { asset } = await ctx.newAsset({ ownerId: user.id }); + const { tag } = await ctx.newTag({ userId: user.id, value: 'foo' }); + await ctx.newTagAsset({ tagIds: [tag.id], assetIds: [asset.id] }); + + const workflow = await createWorkflow({ + ownerId: user.id, + trigger: WorkflowTrigger.AssetCreate, + steps: [ + { + method: 'immich-plugin-core#assetTagFilter', + config: { matching: 'any', tags: [tag.id, newUuid()] }, + }, + { + method: 'immich-plugin-core#assetFavorite', + }, + ], + }); + + await expect(ctx.sut.handleAssetTrigger({ workflowId: workflow.id, assetId: asset.id })).resolves.toBeUndefined(); + await expect(ctx.get(AssetRepository).getById(asset.id)).resolves.toMatchObject({ isFavorite: true }); + }); + + it('should not favorite asset if it has no tags with any filter', async () => { + const { user } = await ctx.newUser(); + const { asset } = await ctx.newAsset({ ownerId: user.id }); + const { tag } = await ctx.newTag({ userId: user.id, value: 'foo' }); + + const workflow = await createWorkflow({ + ownerId: user.id, + trigger: WorkflowTrigger.AssetCreate, + steps: [ + { + method: 'immich-plugin-core#assetTagFilter', + config: { matching: 'any', tags: [tag.id, newUuid()] }, + }, + { + method: 'immich-plugin-core#assetFavorite', + }, + ], + }); + + await expect(ctx.sut.handleAssetTrigger({ workflowId: workflow.id, assetId: asset.id })).resolves.toBeUndefined(); + await expect(ctx.get(AssetRepository).getById(asset.id)).resolves.toMatchObject({ isFavorite: false }); + }); + + it('should favorite asset if it matches all tags', async () => { + const { user } = await ctx.newUser(); + const { asset } = await ctx.newAsset({ ownerId: user.id }); + const { tag } = await ctx.newTag({ userId: user.id, value: 'foo' }); + await ctx.newTagAsset({ tagIds: [tag.id], assetIds: [asset.id] }); + + const workflow = await createWorkflow({ + ownerId: user.id, + trigger: WorkflowTrigger.AssetCreate, + steps: [ + { + method: 'immich-plugin-core#assetTagFilter', + config: { matching: 'all', tags: [tag.id] }, + }, + { + method: 'immich-plugin-core#assetFavorite', + }, + ], + }); + + await expect(ctx.sut.handleAssetTrigger({ workflowId: workflow.id, assetId: asset.id })).resolves.toBeUndefined(); + await expect(ctx.get(AssetRepository).getById(asset.id)).resolves.toMatchObject({ isFavorite: true }); + }); + + it('should not favorite asset if it has no tags with all filter', async () => { + const { user } = await ctx.newUser(); + const { asset } = await ctx.newAsset({ ownerId: user.id }); + const { tag } = await ctx.newTag({ userId: user.id, value: 'foo' }); + + const workflow = await createWorkflow({ + ownerId: user.id, + trigger: WorkflowTrigger.AssetCreate, + steps: [ + { + method: 'immich-plugin-core#assetTagFilter', + config: { matching: 'all', tags: [tag.id, newUuid()] }, + }, + { + method: 'immich-plugin-core#assetFavorite', + }, + ], + }); + + await expect(ctx.sut.handleAssetTrigger({ workflowId: workflow.id, assetId: asset.id })).resolves.toBeUndefined(); + await expect(ctx.get(AssetRepository).getById(asset.id)).resolves.toMatchObject({ isFavorite: false }); + }); + + it('should favorite asset if it has none of the tags', async () => { + const { user } = await ctx.newUser(); + const { asset } = await ctx.newAsset({ ownerId: user.id }); + const { tag } = await ctx.newTag({ userId: user.id, value: 'foo' }); + await ctx.newTagAsset({ tagIds: [tag.id], assetIds: [asset.id] }); + + const workflow = await createWorkflow({ + ownerId: user.id, + trigger: WorkflowTrigger.AssetCreate, + steps: [ + { + method: 'immich-plugin-core#assetTagFilter', + config: { matching: 'none', tags: [newUuid()] }, + }, + { + method: 'immich-plugin-core#assetFavorite', + }, + ], + }); + + await expect(ctx.sut.handleAssetTrigger({ workflowId: workflow.id, assetId: asset.id })).resolves.toBeUndefined(); + await expect(ctx.get(AssetRepository).getById(asset.id)).resolves.toMatchObject({ isFavorite: true }); + }); + }); + describe('webhook', () => { it('should trigger a webhook on asset upload', async () => { const { user } = await ctx.newUser();