diff --git a/schemas/common.json b/schemas/common.json index dc3b5508..98c8c09e 100644 --- a/schemas/common.json +++ b/schemas/common.json @@ -1071,6 +1071,14 @@ }, "categories": { "$ref": "common#/definitions/categories" + }, + "$remove": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "minItems": 1 } } }, diff --git a/src/actions/update.js b/src/actions/update.js index 61856b3e..8ae7d47e 100644 --- a/src/actions/update.js +++ b/src/actions/update.js @@ -1,6 +1,7 @@ const { ActionTransport } = require('@microfleet/plugin-router'); const Promise = require('bluebird'); const { HttpStatusError } = require('common-errors'); +const ld = require('lodash'); const handlePipeline = require('../utils/pipeline-error'); const fetchData = require('../utils/fetch-data'); const isProcessed = require('../utils/is-processed'); @@ -81,6 +82,27 @@ function preProcessMetadata(data) { return data; } +/** + * Process metadata remove operation + * @param {Object} pipeline + * @param {Object} meta + */ +function handleRemoveFromMeta(pipeline, key, meta, data) { + const { $remove } = meta; + + if ($remove && $remove.length > 0) { + const existsData = ld.pick(data, $remove); + const esistsKeys = ld.keys(existsData); + + pipeline.hdel(key, esistsKeys); + + $remove.forEach((removeKey) => { + delete meta[removeKey]; + }); + delete meta.$remove; + } +} + async function updateMeta(lock, ctx, params) { const { uploadId, username, directOnly, immutable, includeReferences } = params; const { redis } = ctx; @@ -151,6 +173,8 @@ async function updateMeta(lock, ctx, params) { delete meta[FILES_ALIAS_FIELD]; // <-- this field is empty at this point } + handleRemoveFromMeta(pipeline, key, meta, data); + if (hasOwnProperty.call(meta, FILES_TAGS_FIELD) && data[FILES_TAGS_FIELD]) { // @todo migrate all tags in files data to lowercase and then remove this tag.toLowerCase() for (const tag of data[FILES_TAGS_FIELD].values()) { diff --git a/test/suites/update.js b/test/suites/update.js index 56a71604..8e138576 100644 --- a/test/suites/update.js +++ b/test/suites/update.js @@ -371,6 +371,73 @@ describe('update suite', function suite() { assert.strictEqual(fileInfo.file.description, 'foo', 'Description should be trimmed'); }); + + it('remove description', async function test() { + const { uploadId } = this.response; + + await this.send({ + uploadId, + username, + meta: { + description: 'some-new-description', + $remove: ['description'], + }, + }, 45000); + + const fileInfo = await getInfo.call(this, { + filename: uploadId, + username, + }); + + assert.strictEqual(fileInfo.file.description, undefined, 'Description should be not exists'); + }); + }); + + describe('update website', function updateWebsite() { + it('failed to update wrong url', async function test() { + meta.website = 'wrong-url'; + + await assert.rejects(this.send({ uploadId: this.response.uploadId, username, meta }, 45000), { + statusCode: 400, + }); + }); + + it('able to update website any website', async function test() { + const { uploadId } = this.response; + meta.website = faker.image.imageUrl(); + + await this.send({ + uploadId, + username, + meta, + }, 45000); + + const fileInfo = await getInfo.call(this, { + filename: uploadId, + username, + }); + + assert.strictEqual(fileInfo.file.website, meta.website, 'Website should be equal with update data'); + }); + + it('able to unset website passing an empty string', async function test() { + const { uploadId } = this.response; + + await this.send({ + uploadId, + username, + meta: { + $remove: ['website'], + }, + }, 45000); + + const fileInfo = await getInfo.call(this, { + filename: uploadId, + username, + }); + + assert.strictEqual(fileInfo.file.website, undefined, 'Website must not exists'); + }); }); describe('playerSettings', function playerSettingsSuite() { @@ -530,10 +597,15 @@ describe('update suite', function suite() { }); }); - it('able to unset backgroundImage passing an empty string', function test() { - meta.backgroundImage = ''; - return this - .send({ uploadId: this.response.uploadId, username, meta }, 45000) + it('remove backgroundImage', async function test() { + await this + .send({ + uploadId: this.response.uploadId, + username, + meta: { + $remove: ['backgroundImage'], + }, + }, 45000) .then(async (result) => { assert.equal(result, true); @@ -542,7 +614,7 @@ describe('update suite', function suite() { username, }); - assert.equal(verifyResult.file.backgroundImage, meta.backgroundImage); + assert.equal(verifyResult.file.backgroundImage, undefined, 'backgroundImage should be not exists'); }); }); @@ -559,7 +631,13 @@ describe('update suite', function suite() { let modelWithReference; before('upload-file', async function uploadFile() { - meta.backgroundImage = ''; + await initAndUpload(backgroundData, false).call(this) + .then(downloadFile.bind(this)) + .then(({ urls }) => { + [meta.backgroundImage] = urls; + return null; + }); + const uploaded = await initAndUpload({ ...modelData, message: {