mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
fix(api): update backend project validation (#54218)
Co-authored-by: Sem Bauke <semboot699@gmail.com>
This commit is contained in:
@@ -362,7 +362,33 @@ describe('challengeRoutes', () => {
|
||||
expect(response.body).toStrictEqual(
|
||||
isValidChallengeCompletionErrorMsg
|
||||
);
|
||||
expect(response.statusCode).toBe(400);
|
||||
expect(response.statusCode).toBe(403);
|
||||
});
|
||||
|
||||
it('POST rejects backendProject requests without URL githubLinks', async () => {
|
||||
const response = await superPost('/project-completed').send({
|
||||
id: id1,
|
||||
challengeType: challengeTypes.backEndProject,
|
||||
// Solution is allowed to be localhost for backEndProject
|
||||
solution: 'http://localhost:3000'
|
||||
});
|
||||
|
||||
expect(response.body).toStrictEqual(
|
||||
isValidChallengeCompletionErrorMsg
|
||||
);
|
||||
expect(response.statusCode).toBe(403);
|
||||
|
||||
const response_2 = await superPost('/project-completed').send({
|
||||
id: id1,
|
||||
challengeType: challengeTypes.backEndProject,
|
||||
solution: 'http://localhost:3000',
|
||||
githubLink: 'not-a-valid-url'
|
||||
});
|
||||
|
||||
expect(response_2.body).toStrictEqual(
|
||||
isValidChallengeCompletionErrorMsg
|
||||
);
|
||||
expect(response_2.statusCode).toBe(403);
|
||||
});
|
||||
|
||||
it('POST rejects CodeRoad/CodeAlly projects when the user has not completed the required challenges', async () => {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebo
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { uniqBy } from 'lodash';
|
||||
import { CompletedExam, ExamResults } from '@prisma/client';
|
||||
import isURL from 'validator/lib/isURL';
|
||||
|
||||
import { challengeTypes } from '../../../shared/config/challenge-types';
|
||||
import { schemas } from '../schemas';
|
||||
@@ -192,9 +193,28 @@ export const challengeRoutes: FastifyPluginCallbackTypebox = (
|
||||
}
|
||||
},
|
||||
async (req, reply) => {
|
||||
// TODO: considering validation is determined by `challengeType`, it should not come from the client
|
||||
// Determine `challengeType` by `id`
|
||||
const { id: projectId, challengeType, solution, githubLink } = req.body;
|
||||
const userId = req.user?.id;
|
||||
|
||||
// If `backEndProject`:
|
||||
// - `solution` needs to exist, but does not have to be valid URL
|
||||
// - `githubLink` needs to exist and be valid URL
|
||||
if (challengeType === challengeTypes.backEndProject) {
|
||||
if (!solution || !isURL(githubLink + '')) {
|
||||
return void reply.code(403).send({
|
||||
type: 'error',
|
||||
message: 'That does not appear to be a valid challenge submission.'
|
||||
});
|
||||
}
|
||||
} else if (solution && !isURL(solution + '')) {
|
||||
return void reply.code(403).send({
|
||||
type: 'error',
|
||||
message: 'That does not appear to be a valid challenge submission.'
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const user = await fastify.prisma.user.findUniqueOrThrow({
|
||||
where: { id: userId },
|
||||
@@ -221,6 +241,7 @@ export const challengeRoutes: FastifyPluginCallbackTypebox = (
|
||||
const oldChallenge = user.completedChallenges?.find(
|
||||
({ id }) => id === projectId
|
||||
);
|
||||
|
||||
const updatedChallenge = {
|
||||
challengeType,
|
||||
solution,
|
||||
|
||||
+10
-5
@@ -526,8 +526,8 @@ export const schemas = {
|
||||
body: Type.Object({
|
||||
id: Type.String({ format: 'objectid', maxLength: 24, minLength: 24 }),
|
||||
challengeType: Type.Optional(Type.Number()),
|
||||
solution: Type.String({ format: 'url', maxLength: 1024 }),
|
||||
// TODO(Post-MVP): require format: 'url' for githubLink
|
||||
// The solution must be a valid URL only if it is a `backEndProject`.
|
||||
solution: Type.String({ maxLength: 1024 }),
|
||||
githubLink: Type.Optional(Type.String())
|
||||
}),
|
||||
response: {
|
||||
@@ -551,9 +551,14 @@ export const schemas = {
|
||||
}),
|
||||
403: Type.Object({
|
||||
type: Type.Literal('error'),
|
||||
message: Type.Literal(
|
||||
'You have to complete the project before you can submit a URL.'
|
||||
)
|
||||
message: Type.Union([
|
||||
Type.Literal(
|
||||
'You have to complete the project before you can submit a URL.'
|
||||
),
|
||||
Type.Literal(
|
||||
'That does not appear to be a valid challenge submission.'
|
||||
)
|
||||
])
|
||||
}),
|
||||
500: Type.Object({
|
||||
message: Type.Literal(
|
||||
|
||||
Reference in New Issue
Block a user