mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2025-12-23 21:04:36 -05:00
fix(client): fix backend code source submission (#58832)
Co-authored-by: sembauke <semboot699@gmail.com>
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user