diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index c94fcb4..e5e28fe 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -8,6 +8,7 @@ import v2ReportRoutes from 'routes/v2/report'; import v3DataRoutes from 'routes/v3/data'; import v3ReportRoutes from 'routes/v3/report'; import v4DataRoutes from 'routes/v4/data'; +import v4IssuesRoutes from 'routes/v4/issues'; import v4ReportRoutes from 'routes/v4/report'; import environment from 'services/environment'; @@ -34,6 +35,7 @@ server.register(v2ReportRoutes, { prefix: '/rest/v2' }); server.register(v3DataRoutes, { prefix: '/rest/v3' }); server.register(v3ReportRoutes, { prefix: '/rest/v3' }); server.register(v4DataRoutes, { prefix: '/rest/v4' }); +server.register(v4IssuesRoutes, { prefix: '/rest/v4' }); server.register(v4ReportRoutes, { prefix: '/rest/v4' }); server.listen({ host: '0.0.0.0', port: environment.port }, (error, address) => { diff --git a/packages/api/src/routes/v2/report.ts b/packages/api/src/routes/v2/report.ts index 64e17f1..538d3e4 100644 --- a/packages/api/src/routes/v2/report.ts +++ b/packages/api/src/routes/v2/report.ts @@ -5,7 +5,7 @@ import { validatorCompiler } from 'services/validation'; import { UAParser } from 'ua-parser-js'; import * as yup from 'yup'; -const PostBodyReportSchema = yup.object().shape({ +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(), @@ -16,14 +16,14 @@ const PostBodyReportSchema = yup.object().shape({ .required(), }); -type PostReportBody = yup.InferType; +type PostReportBody = yup.InferType; export default (server: FastifyInstance, options: RouteShorthandOptions, done: () => void) => { server.post<{ Body: PostReportBody }>( '/report/', { schema: { - body: PostBodyReportSchema, + body: PostReportBodySchema, }, validatorCompiler, }, diff --git a/packages/api/src/routes/v3/report.ts b/packages/api/src/routes/v3/report.ts index 7fe8ebf..5aedf02 100644 --- a/packages/api/src/routes/v3/report.ts +++ b/packages/api/src/routes/v3/report.ts @@ -5,7 +5,7 @@ import { validatorCompiler } from 'services/validation'; import { UAParser } from 'ua-parser-js'; import * as yup from 'yup'; -const PostBodyReportSchema = yup.object().shape({ +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(), @@ -16,27 +16,24 @@ const PostBodyReportSchema = yup.object().shape({ .required(), }); -type PostReportBody = yup.InferType; +type PostReportBody = yup.InferType; export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => { server.post<{ Body: PostReportBody }>( '/report/', { schema: { - body: PostBodyReportSchema, + body: PostReportBodySchema, }, validatorCompiler, }, async (request, reply) => { - const ua = new UAParser(request.body.userAgent ?? '').getResult(); - const url = new URL(request.body.url).hostname - .split('.') - .slice(-3) - .join('.') - .replace('www.', ''); + 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}+${url}`, + q: `in:title+is:issue+repo:${environment.github.owner}/${environment.github.repo}+${hostname}`, }); const existingIssue = existingIssues.data.items[0]; diff --git a/packages/api/src/routes/v4/issues.ts b/packages/api/src/routes/v4/issues.ts new file mode 100644 index 0000000..54d937c --- /dev/null +++ b/packages/api/src/routes/v4/issues.ts @@ -0,0 +1,60 @@ +import { FastifyInstance, RouteShorthandOptions } from 'fastify'; +import environment from 'services/environment'; +import { octokit } from 'services/octokit'; +import { validatorCompiler } from 'services/validation'; +import * as yup from 'yup'; + +const GetIssuesParamsSchema = yup.object().shape({ + hostname: yup.string().required(), +}); + +type GetIssuesParams = yup.InferType; + +export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => { + server.get<{ Params: GetIssuesParams }>( + '/issues/:hostname', + { + schema: { + params: GetIssuesParamsSchema, + }, + validatorCompiler, + }, + async (request, reply) => { + try { + const { hostname } = request.params; + 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]; + + if ( + existingIssue && + (existingIssue.state === 'open' || + (existingIssue.state === 'closed' && + existingIssue.labels.some((label) => label.name === 'wontfix'))) + ) { + reply.send({ + data: { + flags: existingIssue.labels.map((label) => label.name), + url: existingIssue.html_url, + }, + success: true, + }); + } else { + reply.send({ + data: {}, + success: true, + }); + } + } catch (error) { + reply.send({ + errors: [error.message], + success: false, + }); + } + } + ); + + done(); +};