moderator
text
/messages
/functions-project-12345 /messages /key-123456 text: "This is my first message!" /key-123457 text: "IN THIS MESSAGE I AM SHOUTING!!!"
true
sanitized
moderated
/functions-project-12345 /messages /key-123456 text: "This is my first message!", sanitized: true, moderated: false /key-123457 text: "In this message I am shouting." sanitized: true, moderated: true
functions.database().path('/messages/{messageId}').onWrite(...)
exports.moderator = functions.database.ref('/messages/{messageId}') .onWrite(event => { const message = event.data.val(); if (message && !message.sanitized) { // Retrieved the message values. console.log('Retrieved message content: ', message); // Run moderation checks on on the message and moderate if needed. const moderatedMessage = moderateMessage(message.text); // Update the Firebase DB with checked message. console.log('Message has been moderated. Saving to DB: ', moderatedMessage); return event.data.adminRef.update({ text: moderatedMessage, sanitized: true, moderated: message.text !== moderatedMessage }); } });
moderateMessage
bad-words
function moderateMessage(message) { // Re-capitalize if the user is Shouting. if (isShouting(message)) { console.log('User is shouting. Fixing sentence case...'); message = stopShouting(message); } // Moderate if the user uses SwearWords. if (containsSwearwords(message)) { console.log('User is swearing. moderating...'); message = moderateSwearwords(message); } return message; } // Returns true if the string contains swearwords. function containsSwearwords(message) { return message !== badWordsFilter.clean(message); } // Hide all swearwords. e.g: Crap => ****. function moderateSwearwords(message) { return badWordsFilter.clean(message); } // Detect if the current message is shouting. i.e. there are too many Uppercase // characters or exclamation points. function isShouting(message) { return message.replace(/[^A-Z]/g, '').length > message.length / 2 || message.replace(/[^!]/g, '').length >= 3; } // Correctly capitalize the string as a sentence (e.g. uppercase after dots) // and remove exclamation points. function stopShouting(message) { return capitalizeSentence(message.toLowerCase()).replace(/!+/g, '.'); }
blurOffensiveImages
functions.cloud.storage().onChange(...)
exports.blurOffensiveImages = functions.storage.object().onChange(event => { const object = event.data; const file = gcs.bucket(object.bucket).file(object.name); // Exit if this is a move or deletion event. if (object.resourceState === 'not_exists') { return console.log('This is a deletion event.'); } // Check the image content using the Cloud Vision API. return vision.detectSafeSearch(file).then(data => { const safeSearch = data[0]; console.log('SafeSearch results on image', safeSearch); if (safeSearch.adult || safeSearch.violence) { return blurImage(object.name, object.bucket, object.metadata); } }); });
function blurImage(filePath, bucketName, metadata) { const filePathSplit = filePath.split('/'); filePathSplit.pop(); const fileDir = filePathSplit.join('/'); const tempLocalDir = `${LOCAL_TMP_FOLDER}${fileDir}`; const tempLocalFile = `${LOCAL_TMP_FOLDER}${filePath}`; const bucket = gcs.bucket(bucketName); // Create the temp directory where the storage file will be downloaded. return mkdirp(tempLocalDir).then(() => { console.log('Temporary directory has been created', tempLocalDir); // Download file from bucket. return bucket.file(filePath).download({ destination: tempLocalFile }); }).then(() => { console.log('The file has been downloaded to', tempLocalFile); // Blur the image using ImageMagick. return exec(`convert ${tempLocalFile} -channel RGBA -blur 0x8 ${tempLocalFile}`); }).then(() => { console.log('Blurred image created at', tempLocalFile); // Uploading the Blurred image. return bucket.upload(tempLocalFile, { destination: filePath, metadata: {metadata: metadata} // Keeping custom metadata. }); }).then(() => { console.log('Blurred image uploaded to Storage at', filePath); }); }