fix(client): fix backend code source submission (#58832)

Co-authored-by: sembauke <semboot699@gmail.com>
This commit is contained in:
Arif Khalid
2025-03-27 07:26:33 +08:00
committed by GitHub
parent 350424701f
commit e411c1eea6
6 changed files with 46 additions and 11 deletions

View File

@@ -981,7 +981,8 @@
"publicly-visible-url": "Remember to submit a publicly visible app URL.", "publicly-visible-url": "Remember to submit a publicly visible app URL.",
"ms-learn-link": "Please use a valid Microsoft Learn trophy link.", "ms-learn-link": "Please use a valid Microsoft Learn trophy link.",
"path-url": "You probably want to submit the root path i.e. https://example.com, not https://example.com/path", "path-url": "You probably want to submit the root path i.e. https://example.com, not https://example.com/path",
"source-code-link-required": "Remember to submit the link to your source code." "source-code-link-required": "Remember to submit the link to your source code.",
"source-code-link-public": "Source code link must be publicly visible."
}, },
"certification": { "certification": {
"executive": "Executive Director, freeCodeCamp.org", "executive": "Executive Director, freeCodeCamp.org",

View File

@@ -15,7 +15,8 @@ import {
fCCValidator, fCCValidator,
httpValidator, httpValidator,
pathValidator, pathValidator,
sourceCodeLinkExistsValidator sourceCodeLinkExistsValidator,
sourceCodeLinkPublicValidator
} from './form-validators'; } from './form-validators';
export type FormOptions = { export type FormOptions = {
@@ -67,8 +68,11 @@ function FormFields({ formFields, options }: FormFieldsProps): JSX.Element {
validators.push(pathValidator); validators.push(pathValidator);
} }
} }
if (isSourceCodeLinkRequired && name === 'githubLink') { if (name === 'githubLink') {
validators.push(sourceCodeLinkExistsValidator); if (isSourceCodeLinkRequired) {
validators.push(sourceCodeLinkExistsValidator);
}
validators.push(sourceCodeLinkPublicValidator);
} }
if (!isLocalLinkAllowed) { if (!isLocalLinkAllowed) {
validators.push(localhostValidator); validators.push(localhostValidator);

View File

@@ -41,6 +41,8 @@ export const pathValidator: Validator = value =>
export const sourceCodeLinkExistsValidator: Validator = value => export const sourceCodeLinkExistsValidator: Validator = value =>
value ? null : <Trans>validation.source-code-link-required</Trans>; value ? null : <Trans>validation.source-code-link-required</Trans>;
export const sourceCodeLinkPublicValidator: Validator = value =>
isPrivate(value) ? <Trans>validation.source-code-link-public</Trans> : null;
export function composeValidators(...validators: Validator[]) { export function composeValidators(...validators: Validator[]) {
return (value: string): ReturnType<Validator> | null => return (value: string): ReturnType<Validator> | null =>
validators.reduce( validators.reduce(

View File

@@ -9,7 +9,8 @@ import {
composeValidators, composeValidators,
fCCValidator, fCCValidator,
httpValidator, httpValidator,
sourceCodeLinkExistsValidator sourceCodeLinkExistsValidator,
sourceCodeLinkPublicValidator
} from './form-validators'; } from './form-validators';
import FormFields, { FormOptions } from './form-fields'; import FormFields, { FormOptions } from './form-fields';
@@ -69,8 +70,11 @@ function validateFormValues(
if (!isLocalLinkAllowed) { if (!isLocalLinkAllowed) {
validators.push(localhostValidator); validators.push(localhostValidator);
} }
if (isSourceCodeLinkRequired) { if (key === 'githubLink') {
validators.push(sourceCodeLinkExistsValidator); if (isSourceCodeLinkRequired) {
validators.push(sourceCodeLinkExistsValidator);
}
validators.push(sourceCodeLinkPublicValidator);
} }
const nullOrWarning = composeValidators(...validators)(value); const nullOrWarning = composeValidators(...validators)(value);

View File

@@ -56,7 +56,7 @@ function postChallenge(update) {
const saveChallenge = postUpdate$(update).pipe( const saveChallenge = postUpdate$(update).pipe(
retry(3), retry(3),
switchMap(({ data }) => { switchMap(({ data }) => {
const { savedChallenges, message, examResults } = data; const { type, savedChallenges, message, examResults } = data;
const payloadWithClientProperties = { const payloadWithClientProperties = {
...omit(update.payload, ['files']) ...omit(update.payload, ['files'])
}; };
@@ -79,8 +79,15 @@ function postChallenge(update) {
submitChallengeComplete() submitChallengeComplete()
]; ];
if (message && challengeType === challengeTypes.msTrophy) { if (
actions = [createFlashMessage(data), submitChallengeError()]; type === 'error' ||
(message && challengeType === challengeTypes.msTrophy)
) {
actions = [];
if (message) {
actions.push(createFlashMessage(data));
}
actions.push(submitChallengeError());
} else if (challengeType === challengeTypes.msTrophy) { } else if (challengeType === challengeTypes.msTrophy) {
actions.push(createFlashMessage(msTrophyVerified)); actions.push(createFlashMessage(msTrophyVerified));
} }

View File

@@ -3,7 +3,9 @@ import { test, expect } from '@playwright/test';
const locations = { const locations = {
index: index:
'learn/back-end-development-and-apis/managing-packages-with-npm/' + 'learn/back-end-development-and-apis/managing-packages-with-npm/' +
'how-to-use-package-json-the-core-of-any-node-js-project-or-npm-package' 'how-to-use-package-json-the-core-of-any-node-js-project-or-npm-package',
project:
'/learn/back-end-development-and-apis/back-end-development-and-apis-projects/timestamp-microservice'
}; };
const unhandledErrorMessage = 'Something is not quite right'; const unhandledErrorMessage = 'Something is not quite right';
@@ -28,3 +30,18 @@ test.describe('Backend challenge', () => {
await expect(page.getByText(unhandledErrorMessage)).not.toBeVisible(); await expect(page.getByText(unhandledErrorMessage)).not.toBeVisible();
}); });
}); });
test.describe('Backend project', () => {
test.beforeEach(async ({ page }) => {
await page.goto(locations.project);
});
test('warns against private source code links', async ({ page }) => {
await page.fill('input[name="solution"]', 'https://example.com');
await page.fill('input[name="githubLink"]', 'https://localhost:3000');
await expect(
page.getByText('Source code link must be publicly visible.')
).toBeVisible();
});
});