diff --git a/functions/imagemagick/index.js b/functions/imagemagick/index.js index 470cd79a97..2e06a0ff02 100644 --- a/functions/imagemagick/index.js +++ b/functions/imagemagick/index.js @@ -28,7 +28,7 @@ const client = new vision.ImageAnnotatorClient(); // [START functions_imagemagick_analyze] // Blurs uploaded images that are flagged as Adult or Violence. exports.blurOffensiveImages = (event) => { - const object = event.data; + const object = event.data || event; // Exit if this is a deletion or a deploy event. if (object.resourceState === 'not_exists') { @@ -42,6 +42,12 @@ exports.blurOffensiveImages = (event) => { const file = storage.bucket(object.bucket).file(object.name); const filePath = `gs://${object.bucket}/${object.name}`; + // Ignore already-blurred files (to prevent re-invoking this function) + if (file.name.startsWith('blurred-')) { + console.log(`The image ${file.name} is already blurred.`); + return; + } + console.log(`Analyzing ${file.name}.`); return client.safeSearchDetection(filePath) @@ -92,8 +98,11 @@ function blurImage (file) { .then(() => { console.log(`Image ${file.name} has been blurred.`); + // Mark result as blurred, to avoid re-triggering this function. + const newName = `blurred-${file.name}`; + // Upload the Blurred image back into the bucket. - return file.bucket.upload(tempLocalPath, { destination: file.name }) + return file.bucket.upload(tempLocalPath, { destination: newName }) .catch((err) => { console.error('Failed to upload blurred image.', err); return Promise.reject(err); diff --git a/functions/imagemagick/test/index.test.js b/functions/imagemagick/test/index.test.js index abddf6a663..016b898758 100644 --- a/functions/imagemagick/test/index.test.js +++ b/functions/imagemagick/test/index.test.js @@ -22,7 +22,7 @@ const tools = require(`@google-cloud/nodejs-repo-tools`); const vision = require('@google-cloud/vision').v1p1beta1; const bucketName = `my-bucket`; -const filename = `image.jpg`; +const defaultFileName = `image.jpg`; var VisionStub = sinon.stub(vision, 'ImageAnnotatorClient'); VisionStub.returns({ @@ -34,7 +34,7 @@ VisionStub.returns({ }])) }); -function getSample () { +function getSample (filename) { const file = { getMetadata: sinon.stub().returns(Promise.resolve([{}])), setMetadata: sinon.stub().returns(Promise.resolve()), @@ -82,20 +82,20 @@ test.beforeEach(tools.stubConsole); test.afterEach.always(tools.restoreConsole); test.serial(`blurOffensiveImages does nothing on delete`, async (t) => { - await getSample().program.blurOffensiveImages({ data: { resourceState: `not_exists` } }); + await getSample(defaultFileName).program.blurOffensiveImages({ data: { resourceState: `not_exists` } }); t.is(console.log.callCount, 1); t.deepEqual(console.log.getCall(0).args, ['This is a deletion event.']); }); test.serial(`blurOffensiveImages does nothing on deploy`, async (t) => { - await getSample().program.blurOffensiveImages({ data: {} }); + await getSample(defaultFileName).program.blurOffensiveImages({ data: {} }); t.is(console.log.callCount, 1); t.deepEqual(console.log.getCall(0).args, ['This is a deploy event.']); }); -test.serial(`blurOffensiveImages blurs images`, async (t) => { - const sample = getSample(); - await sample.program.blurOffensiveImages({ data: { bucket: bucketName, name: filename } }); +test.serial(`blurOffensiveImages blurs unblurred images (Node 6 syntax)`, async (t) => { + const sample = getSample(defaultFileName); + await sample.program.blurOffensiveImages({ data: { bucket: bucketName, name: defaultFileName } }); t.is(console.log.callCount, 5); t.deepEqual(console.log.getCall(0).args, [`Analyzing ${sample.mocks.file.name}.`]); t.deepEqual(console.log.getCall(1).args, [`The image ${sample.mocks.file.name} has been detected as inappropriate.`]); @@ -104,6 +104,24 @@ test.serial(`blurOffensiveImages blurs images`, async (t) => { t.deepEqual(console.log.getCall(4).args, [`Blurred image has been uploaded to ${sample.mocks.file.name}.`]); }); +test.serial(`blurOffensiveImages blurs unblurred images (Node 8 syntax)`, async (t) => { + const sample = getSample(defaultFileName); + await sample.program.blurOffensiveImages({ bucket: bucketName, name: defaultFileName }); + t.is(console.log.callCount, 5); + t.deepEqual(console.log.getCall(0).args, [`Analyzing ${sample.mocks.file.name}.`]); + t.deepEqual(console.log.getCall(1).args, [`The image ${sample.mocks.file.name} has been detected as inappropriate.`]); + t.deepEqual(console.log.getCall(2).args, [`Image ${sample.mocks.file.name} has been downloaded to /tmp/${sample.mocks.file.name}.`]); + t.deepEqual(console.log.getCall(3).args, [`Image ${sample.mocks.file.name} has been blurred.`]); + t.deepEqual(console.log.getCall(4).args, [`Blurred image has been uploaded to ${sample.mocks.file.name}.`]); +}); + +test.serial(`blurOffensiveImages ignores already-blurred images`, async (t) => { + const sample = getSample(`blurred-${defaultFileName}`); + await sample.program.blurOffensiveImages({ data: { bucket: bucketName, name: `blurred-${defaultFileName}` } }); + t.is(console.log.callCount, 1); + t.deepEqual(console.log.getCall(0).args, [`The image ${sample.mocks.file.name} is already blurred.`]); +}); + test.serial(`blurOffensiveImages ignores safe images`, async (t) => { VisionStub.restore(); VisionStub = sinon.stub(vision, 'ImageAnnotatorClient'); @@ -115,8 +133,8 @@ test.serial(`blurOffensiveImages ignores safe images`, async (t) => { } }])) }); - const sample = getSample(); - await sample.program.blurOffensiveImages({ data: { bucket: bucketName, name: filename } }); + const sample = getSample(defaultFileName); + await sample.program.blurOffensiveImages({ data: { bucket: bucketName, name: defaultFileName } }); t.is(console.log.callCount, 2); t.deepEqual(console.log.getCall(0).args, [`Analyzing ${sample.mocks.file.name}.`]); t.deepEqual(console.log.getCall(1).args, [`The image ${sample.mocks.file.name} has been detected as OK.`]);