Skip to content

Instantly share code, notes, and snippets.

@grncdr
Last active August 29, 2015 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save grncdr/7b910144cf9a75583c64 to your computer and use it in GitHub Desktop.
Save grncdr/7b910144cf9a75583c64 to your computer and use it in GitHub Desktop.
Collect untranslated fields in a contentful entry and forward them elsewhere.
var hyperquest = require('hyperquest');
module.exports = checkForUntranslatedFields;
module.exports.schema = {
access_token: 'string',
translation_url: 'string',
space_id: 'string',
entry_id: 'string'
};
function checkForUntranslatedFields (hook) {
function ignore () {
hook.debug('ignored');
hook.res.end('{"message":"ignored"}');
}
function fail (err) {
hook.debug(err.stack);
hook.res.statusCode = 500;
hook.res.end(JSON.stringify({ message: err.message }));
}
var cma = createContentManagementClient(hook);
var getEntry;
if (hook.params.space_id && hook.params.entry_id) {
var entryPath = '/spaces/' + hook.params.space_id + '/entries/' + hook.params.entry_id + '/published';
hook.debug('entry from query params: ' + entryPath);
getEntry = cma.bind(null, entryPath);
} else if (hook.req.headers['x-contentful-topic'] !== "ContentManagement.Entry.publish") {
return ignore();
} else {
hook.debug('entry from request body');
getEntry = collectJSON.bind(null, hook.req);
}
getEntry(function (err, entry) {
if (err) {
return fail(err);
}
hook.debug('got entry');
getLocalesAndContentType(entry, function (err, locales, contentType) {
if (err) return fail(err);
var neededTranslations;
try {
neededTranslations = getNeededTranslations(locales, contentType, entry, hook);
} catch (err) {
return fail(err);
}
return hook.res.end(JSON.stringify(neededTranslations));
if (!neededTranslations.length) {
return ignore();
} else {
return hook.res.end(JSON.stringify(neededTranslations));
}
var req = hyperquest(hook.params.translation_url, {
method: 'POST',
headers: {
'content-type': 'application/json'
}
}).on('error', function (err) {
hook.debug('translation request failed');
fail(err);
}).on('response', function (response) {
hook.res.statusCode = response.statusCode;
for (var key in response.headers) if (key !== 'Host') {
hook.res.setHeader(key, response.headers[key]);
}
response.pipe(hook.res);
});
req.end(JSON.strinigy({
entry: entry,
neededTranslations: neededTranslations
}));
});
});
function getLocalesAndContentType(entry, callback) {
var spacePath = '/spaces/' + entry.sys.space.sys.id;
var result = {};
var remaining = 2;
getOne(spacePath + '/locales', 'locales');
getOne(spacePath + '/content_types/' + entry.sys.contentType.sys.id + '/published',
'contentType');
function getOne (path, property) {
cma(path, function (err, data) {
if (err && remaining) {
remaining = 0;
return callback(err);
} else {
hook.debug('got ' + property);
result[property] = data;
if (! --remaining) {
callback(null, result.locales, result.contentType);
}
}
});
}
}
}
function createContentManagementClient (hook) {
var opts = {
headers: { Authorization: 'Bearer ' + hook.params.access_token }
};
return function (path, callback) {
var uri = 'https://api.contentful.com' + path;
hook.debug('requesting ' + uri);
var stream = hyperquest(uri, opts);
var statusCode;
stream.on('response', function (response) { statusCode = response.statusCode; });
collectJSON(stream, function (err, data) {
hook.debug('status code: ' + statusCode);
if (err) {
callback(err);
} else if (statusCode && statusCode !== 200) {
callback(data);
} else {
callback(null, data);
}
});
};
}
function getNeededTranslations (locales, contentType, entry, hook) {
var fieldsById = lookup(contentType.fields, 'id');
var localesByCode = lookup(locales.items, 'code');
var neededTranslations = [];
for (var fieldId in entry.fields) if (fieldsById[fieldId].localized) {
var untranslated = [];
for (var locale in localesByCode) {
if (!entry.fields[fieldId][locale]) {
untranslated.push(locale);
}
}
if (untranslated.length) {
neededTranslations.push({
field: entry.fields[fieldId],
missingLocales: untranslated
});
}
}
return neededTranslations;
}
function lookup (objects, prop) {
return objects.reduce(function (result, object) {
result[object[prop]] = object;
return result;
}, {});
}
function collectJSON (stream, callback) {
return collect(stream, function (err, payload) {
if (err) return callback(err);
var data;
try {
data = JSON.parse(payload);
} catch (parseError) {
return callback(parseError);
}
callback(null, data);
});
}
function collect (stream, callback) {
var all = "";
var done = false;
stream
.on('error', function (err) {
if (!done) callback(err);
done = true;
})
.on('data', function (chunk) {
all += chunk;
})
.on('end', function () {
if (!done) callback(null, all);
done = true;
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment