91 lines
2.7 KiB
TypeScript
91 lines
2.7 KiB
TypeScript
import { FastifyInstance, RouteShorthandOptions } from 'fastify';
|
|
import environment from 'services/environment';
|
|
import { octokit } from 'services/octokit';
|
|
import { validatorCompiler } from 'services/validation';
|
|
import { UAParser } from 'ua-parser-js';
|
|
import * as yup from 'yup';
|
|
|
|
const PostReportBodySchema = yup.object().shape({
|
|
reason: yup.string().min(10).max(1000).required(),
|
|
url: yup.string().max(1000).url().required(),
|
|
userAgent: yup.string().max(1000).optional(),
|
|
version: yup
|
|
.string()
|
|
.max(10)
|
|
.matches(/^\d+(\.\d+){0,3}$/)
|
|
.required(),
|
|
});
|
|
|
|
type PostReportBody = yup.InferType<typeof PostReportBodySchema>;
|
|
|
|
export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => {
|
|
server.post<{ Body: PostReportBody }>(
|
|
'/report/',
|
|
{
|
|
schema: {
|
|
body: PostReportBodySchema,
|
|
},
|
|
validatorCompiler,
|
|
},
|
|
async (request, reply) => {
|
|
const { url, userAgent } = request.body;
|
|
const ua = new UAParser(userAgent ?? '').getResult();
|
|
const hostname = new URL(url).hostname.split('.').slice(-3).join('.').replace('www.', '');
|
|
const existingIssues = await octokit.request('GET /search/issues', {
|
|
per_page: 1,
|
|
q: `in:title+is:issue+repo:${environment.github.owner}/${environment.github.repo}+${hostname}`,
|
|
});
|
|
const existingIssue = existingIssues.data.items[0];
|
|
|
|
try {
|
|
if (existingIssue) {
|
|
reply.send({
|
|
errors: [`Issue already exists, ${existingIssue.html_url}`],
|
|
success: false,
|
|
});
|
|
return;
|
|
}
|
|
|
|
const response = await octokit.request('POST /repos/{owner}/{repo}/issues', {
|
|
assignees: [environment.github.owner],
|
|
body: generateText(request.body, ua),
|
|
labels: ['bug'],
|
|
owner: environment.github.owner,
|
|
repo: environment.github.repo,
|
|
title: url,
|
|
});
|
|
|
|
reply.send({
|
|
data: response.data.html_url,
|
|
success: true,
|
|
});
|
|
} catch (error) {
|
|
reply.send({
|
|
errors: [error.message],
|
|
success: false,
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
done();
|
|
};
|
|
|
|
function generateText(body: PostReportBody, ua: UAParser.IResult): string {
|
|
return [
|
|
'## Issue information',
|
|
...(ua.browser.name && ua.browser.version
|
|
? ['#### 🖥️ Browser', `${ua.browser.name} (${ua.browser.version})`]
|
|
: []),
|
|
...(ua.device.type && ua.device.vendor
|
|
? ['#### 📱 Device', `${ua.device.vendor} (${ua.device.type})`]
|
|
: []),
|
|
'#### 📝 Reason',
|
|
body.reason,
|
|
'#### 🔗 URL',
|
|
body.url,
|
|
'#### 🏷️ Version',
|
|
body.version,
|
|
].join('\n');
|
|
}
|