feat(api): add user id to user report (#59816)

This commit is contained in:
Shaun Hamilton
2025-04-22 16:28:16 +02:00
committed by GitHub
parent fdbca0bd1f
commit 6478bea038
5 changed files with 50 additions and 26 deletions
+10 -12
View File
@@ -13,7 +13,8 @@ import {
devLogin,
setupServer,
superRequest,
createSuperRequest
createSuperRequest,
defaultUsername
} from '../../../jest.utils';
import { JWT_SECRET } from '../../utils/env';
import {
@@ -802,29 +803,25 @@ describe('userRoutes', () => {
reportDescription: 'Test Report'
});
expect(response.statusCode).toBe(400);
expect(response.statusCode).toBe(404);
expect(response.body).toStrictEqual({
type: 'danger',
message: 'flash.provide-username'
message: 'flash.report-error'
});
});
test('POST returns 400 for empty report', async () => {
const response = await superPost('/user/report-user').send({
username: 'darth-vader',
username: testUserData.username,
reportDescription: ''
});
expect(response.statusCode).toBe(400);
expect(response.body).toStrictEqual({
type: 'danger',
message: 'flash.provide-username'
});
});
test('POST sanitises report description', async () => {
await superPost('/user/report-user').send({
username: 'darth-vader',
username: defaultUsername,
reportDescription:
'<script>const breath = "loud"</script>Luke, I am your father'
});
@@ -846,7 +843,7 @@ describe('userRoutes', () => {
}
);
const response = await superPost('/user/report-user').send({
username: 'darth-vader',
username: testUser.username,
reportDescription: 'Luke, I am your father'
});
@@ -855,11 +852,11 @@ describe('userRoutes', () => {
from: 'team@freecodecamp.org',
to: 'support@freecodecamp.org',
cc: 'foo@bar.com',
subject: "Abuse Report : Reporting darth-vader's profile.",
subject: `Abuse Report : Reporting ${testUser.username}'s profile.`,
text: `
Hello Team,
This is to report the profile of darth-vader.
This is to report the profile of ${testUser.username}. ID: ${defaultUserId}.
Report Details:
@@ -867,6 +864,7 @@ Luke, I am your father
Reported by:
ID: ${testUser.id}
Username: ${testUser.username}
Name:
Email: foo@bar.com
+31 -7
View File
@@ -19,7 +19,7 @@ import {
normalizeTwitter,
removeNulls
} from '../../utils/normalize';
import type { UpdateReqType } from '../../utils';
import { mapErr, type UpdateReqType } from '../../utils';
import {
getCalendar,
getPoints,
@@ -176,21 +176,45 @@ export const userRoutes: FastifyPluginCallbackTypebox = (
});
const { username, reportDescription: report } = req.body;
if (!username || !report) {
logger.warn('Missing username or reportDescription');
void reply.code(400);
// TODO: `findUnique` once db migration forces unique usernames
const maybeReportedUsers = await mapErr(
fastify.prisma.user.findMany({
where: { username }
})
);
if (maybeReportedUsers.hasError) {
logger.error(
{ error: maybeReportedUsers.error, username },
'Error finding reported user.'
);
fastify.Sentry.captureException(maybeReportedUsers.error);
void reply.code(500);
return {
type: 'danger',
message: 'flash.provide-username'
message: 'flash.generic-error'
} as const;
}
const reportedUsers = maybeReportedUsers.data;
if (reportedUsers.length !== 1) {
logger.warn({ username }, 'Reported user not found');
void reply.code(404);
return {
type: 'danger',
message: 'flash.report-error'
} as const;
}
const reportedUser = reportedUsers[0]!;
await fastify.sendEmail({
from: 'team@freecodecamp.org',
to: 'support@freecodecamp.org',
cc: user.email,
subject: `Abuse Report : Reporting ${username}'s profile.`,
text: generateReportEmail(user, username, report)
subject: `Abuse Report : Reporting ${reportedUser.username}'s profile.`,
text: generateReportEmail(user, reportedUser, report)
});
return {
+4 -4
View File
@@ -4,7 +4,7 @@ import { genericError } from '../types';
export const reportUser = {
body: Type.Object({
username: Type.String(),
reportDescription: Type.String()
reportDescription: Type.String({ minLength: 1 })
}),
response: {
200: Type.Object({
@@ -14,10 +14,10 @@ export const reportUser = {
email: Type.String()
})
}),
400: Type.Object({
404: Type.Object({
type: Type.Literal('danger'),
message: Type.Literal('flash.provide-username')
message: Type.Literal('flash.report-error')
}),
default: genericError
500: genericError
}
};
+4 -3
View File
@@ -9,13 +9,13 @@ import { user } from '@prisma/client';
*/
export const generateReportEmail = (
reporter: user,
abuser: string,
abuser: user,
reportDesc: string
) => {
return `
Hello Team,
This is to report the profile of ${abuser}.
This is to report the profile of ${abuser.username}. ID: ${abuser.id}.
Report Details:
@@ -23,10 +23,11 @@ ${reportDesc}
Reported by:
ID: ${reporter.id}
Username: ${reporter.username}
Name:${reporter.name ? ' ' + reporter.name : ''}
Email: ${reporter.email}
Thanks and regards,
${reporter.name ?? ''}`;
${reporter.name ?? reporter.username}`;
};
@@ -905,6 +905,7 @@
"unlink-success": "You've successfully unlinked your {{website}}",
"provide-username": "Check if you have provided a username and a report",
"report-sent": "A report was sent to the team with {{email}} in copy",
"report-error": "Unable to report this user at this time.",
"certificate-missing": "The certification you tried to view does not exist",
"create-token-err": "An error occurred while creating your user token",
"delete-token-err": "An error occurred while deleting your user token",