Files
talk/services/moderation/index.js
T
2018-01-22 16:11:13 -07:00

131 lines
3.3 KiB
JavaScript

const errors = require('../../errors');
const get = require('lodash/get');
// Load in the phases to use.
const {
wordlist,
commentLength,
assetClosed,
karma,
staff,
links,
premod,
} = require('./phases');
// This phase checks to see if the comment was already prescribed a status. This
// essentially provides a hook for plugins to inject their own comments.
const applyPreexisting = (ctx, comment) => {
const status = get(comment, 'status');
// If the status was already defined, don't redefine it. It's only defined
// when specific external conditions exist, we don't want to override that.
if (status) {
return {
status,
};
}
};
// Applies the defaulted status.
const applyStatus = status => () => ({ status });
/**
* phases is an array of moderation phases carried out in order until a status is
* returned.
*/
const phases = [
commentLength,
assetClosed,
wordlist,
staff,
links,
karma,
applyPreexisting,
premod,
applyStatus('NONE'),
];
/**
* compose will create a moderation pipeline for which is executable with the
* passed actions.
*
* @param {Array} phases the set of moderation phases to pass the comment and
* their options through.
*/
const compose = phases => async (ctx, comment, options) => {
const actions = get(comment, 'actions', []);
// Loop over all the moderation phases and see if we've resolved the status.
for (const phase of phases) {
const result = await phase(ctx, comment, options);
if (result) {
if (result.actions) {
actions.push(...result.actions);
}
// If this result contained a status, then we've finished resolving
// phases!
if (result.status) {
return { status: result.status, actions };
}
}
}
};
/**
* fetchOptions will generate the options used by the moderation service to
* determine the end status.
*
* @param {Object} ctx graph context
* @param {Object} comment comment object to use
*/
const fetchOptions = async (ctx, comment) => {
const {
connectors: { services: { Assets: AssetsService } },
loaders: { Settings, Assets },
} = ctx;
// Load the settings.
const settings = await Settings.load();
// Pull the asset id out of the comment.
const assetID = get(comment, 'asset_id', null);
if (assetID === null) {
// And leave now if this asset wasn't found.
throw errors.ErrNotFound;
}
// Load the asset.
const asset = await Assets.getByID.load(assetID);
if (!asset) {
// And leave now if this asset wasn't found.
throw errors.ErrNotFound;
}
// Combine the asset and the settings to get the asset settings.
asset.settings = await AssetsService.rectifySettings(asset, settings);
// Create the options that will be consumed by the phases.
return {
asset,
settings,
};
};
/**
* process the comment and return moderation details.
*
* @param {Object} ctx graphql context
* @param {Object} comment comment to perform the moderation phases on
*/
const process = async (ctx, comment) => {
// Fetch the options to use for the moderation phases.
const options = await fetchOptions(ctx, comment);
// Compose a moderation pipeline from the moderation phases and execute it on
// the comment.
return compose(phases)(ctx, comment, options);
};
module.exports.process = process;