-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
114 lines (110 loc) · 3.89 KB
/
index.js
File metadata and controls
114 lines (110 loc) · 3.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
const {send, json, createError} = require('micro');
const akismetAPI = require('akismet-api');
const Perspective = require('perspective-api-client');
const microCors = require('micro-cors');
const pkg = require('./package.json');
const cors = microCors({allowMethods: ['GET', 'POST', 'OPTIONS']});
const perspectiveEnabled = Boolean(process.env.PERSPECTIVE_API_KEY && process.env.PERSPECTIVE_ENABLED !== 'false');
const akismetEnabled = Boolean(process.env.AKISMET_API_KEY && process.env.AKISMET_ENABLED !== 'false');
/**
* Catch errors from the wrapped function.
* If any errors are caught, a JSON response is generated for that error.
*
* @param {function} fn: The handler function.
* @returns {function} Decorated handler function.
*/
const handleErrors = fn => async (req, res) => {
try {
return await fn(req, res);
} catch (error) {
if (process.env.NODE_ENV === 'dev' && error.stack) {
console.error(error.stack);
}
const status = error.statusCode || 500;
send(res, status, {
status,
message: error.message,
});
}
};
/**
* Factory for a micro handler containing the main routing logic.
*
* @param {function} backend: The backend to use for the service. The backend receives the
* parsed input JSON from the client.
* @param {object} attributes: Optional attributes about the backend, e.g. name, version.
* @return {function} Micro handler.
*/
module.exports = (backend, attributes) =>
handleErrors(
cors(async (req, res) => {
if (req.method === 'GET') {
const response = {
message:
'Welcome to the microfeedback API. Send a POST ' +
'request to send feedback.',
core: {
version: pkg.version,
perspectiveEnabled,
akismetEnabled,
},
};
if (attributes) {
response.backend = attributes;
}
send(res, 200, response);
} else if (req.method === 'POST') {
const input = await json(req);
if (!input.body) {
throw createError(422, '"body" is required in request payload');
}
let perspective = null;
let akismet = null;
if (perspectiveEnabled) {
const perspectiveClient = new Perspective(({apiKey: process.env.PERSPECTIVE_API_KEY}));
try {
const response = await perspectiveClient.analyze(input.body, {truncate: true});
const toxicity = response.attributeScores.TOXICITY.summaryScore.value;
perspective = {toxicity};
} catch (error) {
console.error(error.stack || error);
}
}
if (akismetEnabled) {
const akismetClient = akismetAPI.client({
key: process.env.AKISMET_API_KEY,
blog: req.headers.origin,
});
let spam = null;
try {
/* eslint-disable camelcase */
spam = await akismetClient.checkSpam({
user_ip: req.headers['remote-addr'],
user_agent: req.headers['user-agent'],
referrer: req.headers.referer,
comment_type: 'comment',
comment_content: input.body || '',
});
/* eslint-enable camelcase */
} catch (error) {
console.error(error.stack || error);
}
if (spam !== null) {
const allowSpam = Boolean(process.env.ALLOW_SPAM && process.env.ALLOW_SPAM !== 'false');
if (spam && !allowSpam) {
throw createError(400, 'Spam detected.');
}
akismet = {spam};
}
}
const result = await backend({input, perspective, akismet}, req, res);
const responseData = {result};
if (attributes) {
responseData.backend = attributes;
}
send(res, 201, responseData);
} else {
throw createError(405, `Method ${req.method} not allowed.`);
}
})
);