Recommended Reading
Strapi Plugins
The strapi plugin system is surprisingly easy to use and access. By default there is a upload
plugin that is bundled with a standard strapi install. The strapi-plugin-upload code can be found here.
Safe Upload API Strategy
The upload API by default is found by POSTing to /upload
. This creates a File
model instance and sets it up in the database.
In order to filter images, we need a way to intercept the upload requests and submit the image to an AI platform like DeepAI's NSFW content filter.
To my knowledge is not an easy way to customize the code for an external plugin like strapi-plugin-upload
. The code is bundled in node_modules
and it provides no extension hooks.
However, if we create a completely new route, say /upload-safe
and then use that, we can then just use this new endpoint in our client instead of the default one. Then, in that endpoint we simply call the internal controller for the default upload plugin and upload the image to get the url. Then we can submit the url to DeepAI and if the results are unsatisfactory, we can just tell the upload plugin to remove the image and return a status message to the client saying the image was unsatisfactory.
Solution
Make sure to npm i -s form-data node-fetch
first.
Create a new api, like so called upload-safe
:
/api
/upload-safe
/config
routes.json
/controllers
upload-safe.js
routes.json
contains:
{
"routes": [
{
"method": "POST",
"path": "/upload-safe",
"handler": "upload-safe.upload",
"config": {
"policies": [],
"description": "Upload a file and reject NSFW photos",
"tag": {
"plugin": "upload",
"name": "File"
}
}
}
]
}
upload-safe.js
will contain something like this:
'use strict';
const FormData = require('form-data');
const fetch = require('node-fetch');
/**
* Read the documentation (https://strapi.io/documentation/developer-docs/latest/concepts/controllers.html#core-controllers)
* to customize this controller
*/
module.exports = {
upload: async function(context) {
// Perform the default upload functionality provided by the strapi upload plugin
await strapi.plugins.upload.controllers.upload.upload(context);
let deepai;
try {
const form = new FormData();
const url = context.body[0].formats && context.body[0].formats.small ? context.body[0].formats.small.url : context.body[0].url;
form.append('image', url);
// Hit the DeepAI API endpoint. You will not to provide your own apiKey
const resp = await fetch('https://api.deepai.org/api/nsfw-detector', {
method: 'POST',
body: form,
headers: {
'api-key': 'blah-blah-blah-blah'
}
});
deepai = await resp.json();
} catch (error) {
console.error('An error occurred fetching from DeepAI NSFW index', error);
}
let imageIsSafe = true;
if (deepai && deepai.output.nsfw_score > 0.95) {
// Delete the file if NSFW from the upload.
await strapi.plugins.upload.services.upload.remove(context.body[0]);
imageIsSafe = false;
}
context.send({
upload: context.body,
deepai,
imageIsSafe
});
}
}
That's it! Now when you hit /upload-safe
the normal upload strategy will be performed as long as the image is safe.