mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat(client): allow empty source code testing (#53797)
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
@@ -872,7 +872,8 @@
|
||||
"own-work-url": "Remember to submit your own work.",
|
||||
"publicly-visible-url": "Remember to submit a publicly visible app URL.",
|
||||
"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."
|
||||
},
|
||||
"certification": {
|
||||
"executive": "Executive Director, freeCodeCamp.org",
|
||||
|
||||
@@ -14,13 +14,15 @@ import {
|
||||
composeValidators,
|
||||
fCCValidator,
|
||||
httpValidator,
|
||||
pathValidator
|
||||
pathValidator,
|
||||
sourceCodeLinkExistsValidator
|
||||
} from './form-validators';
|
||||
|
||||
export type FormOptions = {
|
||||
ignored?: string[];
|
||||
isEditorLinkAllowed?: boolean;
|
||||
isLocalLinkAllowed?: boolean;
|
||||
isSourceCodeLinkRequired?: boolean;
|
||||
required?: string[];
|
||||
types?: { [key: string]: string };
|
||||
placeholders?: { [key: string]: string };
|
||||
@@ -38,7 +40,8 @@ function FormFields({ formFields, options }: FormFieldsProps): JSX.Element {
|
||||
required = [],
|
||||
types = {},
|
||||
isEditorLinkAllowed = false,
|
||||
isLocalLinkAllowed = false
|
||||
isLocalLinkAllowed = false,
|
||||
isSourceCodeLinkRequired = false
|
||||
} = options;
|
||||
|
||||
const nullOrWarning = (
|
||||
@@ -64,6 +67,9 @@ function FormFields({ formFields, options }: FormFieldsProps): JSX.Element {
|
||||
validators.push(pathValidator);
|
||||
}
|
||||
}
|
||||
if (isSourceCodeLinkRequired && name === 'githubLink') {
|
||||
validators.push(sourceCodeLinkExistsValidator);
|
||||
}
|
||||
if (!isLocalLinkAllowed) {
|
||||
validators.push(localhostValidator);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,9 @@ export const httpValidator: Validator = value =>
|
||||
export const pathValidator: Validator = value =>
|
||||
isPathRoot(value) ? <Trans>validation.path-url</Trans> : null;
|
||||
|
||||
export const sourceCodeLinkExistsValidator: Validator = value =>
|
||||
value ? null : <Trans>validation.source-code-link-required</Trans>;
|
||||
|
||||
export function composeValidators(...validators: Validator[]) {
|
||||
return (value: string): ReturnType<Validator> | null =>
|
||||
validators.reduce(
|
||||
|
||||
@@ -8,7 +8,8 @@ import {
|
||||
editorValidator,
|
||||
composeValidators,
|
||||
fCCValidator,
|
||||
httpValidator
|
||||
httpValidator,
|
||||
sourceCodeLinkExistsValidator
|
||||
} from './form-validators';
|
||||
import FormFields, { FormOptions } from './form-fields';
|
||||
|
||||
@@ -35,43 +36,59 @@ function validateFormValues(
|
||||
formValues: FormValues,
|
||||
options: FormOptions
|
||||
): ValidatedValues {
|
||||
const { isEditorLinkAllowed, isLocalLinkAllowed, types } = options;
|
||||
const {
|
||||
isEditorLinkAllowed,
|
||||
isLocalLinkAllowed,
|
||||
isSourceCodeLinkRequired,
|
||||
types
|
||||
} = options;
|
||||
const validatedValues: ValidatedValues = {
|
||||
values: {},
|
||||
errors: [],
|
||||
invalidValues: []
|
||||
};
|
||||
const urlValues = Object.entries(formValues).reduce(
|
||||
(result, [key, value]) => {
|
||||
// NOTE: pathValidator is not used here, because it is only used as a
|
||||
// suggestion - should not prevent form submission
|
||||
const validators = [fCCValidator, httpValidator];
|
||||
const isSolutionLink = key !== 'githubLink';
|
||||
if (isSolutionLink && !isEditorLinkAllowed) {
|
||||
validators.push(editorValidator);
|
||||
}
|
||||
if (!isLocalLinkAllowed) {
|
||||
validators.push(localhostValidator);
|
||||
}
|
||||
|
||||
const nullOrWarning = composeValidators(...validators)(value);
|
||||
if (nullOrWarning) {
|
||||
validatedValues.invalidValues.push(nullOrWarning);
|
||||
const formFields = Object.entries(formValues);
|
||||
// We don't always get a githubLink field in formValues, so we can't simply
|
||||
// validate that field like the others. We have to handle it separately.
|
||||
if (isSourceCodeLinkRequired) {
|
||||
const githubLink = formValues['githubLink'];
|
||||
if (!githubLink) {
|
||||
validatedValues.invalidValues.push(sourceCodeLinkExistsValidator(''));
|
||||
}
|
||||
}
|
||||
|
||||
const urlValues = formFields.reduce((result, [key, value]) => {
|
||||
// NOTE: pathValidator is not used here, because it is only used as a
|
||||
// suggestion - should not prevent form submission
|
||||
const validators = [fCCValidator, httpValidator];
|
||||
const isSolutionLink = key !== 'githubLink';
|
||||
if (isSolutionLink && !isEditorLinkAllowed) {
|
||||
validators.push(editorValidator);
|
||||
}
|
||||
if (!isLocalLinkAllowed) {
|
||||
validators.push(localhostValidator);
|
||||
}
|
||||
if (isSourceCodeLinkRequired) {
|
||||
validators.push(sourceCodeLinkExistsValidator);
|
||||
}
|
||||
|
||||
const nullOrWarning = composeValidators(...validators)(value);
|
||||
if (nullOrWarning) {
|
||||
validatedValues.invalidValues.push(nullOrWarning);
|
||||
}
|
||||
if (value && types && types[key] === 'url') {
|
||||
try {
|
||||
value = normalizeUrl(value, normalizeOptions);
|
||||
} catch (err: unknown) {
|
||||
validatedValues.errors.push({
|
||||
error: err as { message?: string },
|
||||
value
|
||||
});
|
||||
}
|
||||
if (value && types && types[key] === 'url') {
|
||||
try {
|
||||
value = normalizeUrl(value, normalizeOptions);
|
||||
} catch (err: unknown) {
|
||||
validatedValues.errors.push({
|
||||
error: err as { message?: string },
|
||||
value
|
||||
});
|
||||
}
|
||||
}
|
||||
return { ...result, [key]: value };
|
||||
},
|
||||
{}
|
||||
);
|
||||
}
|
||||
return { ...result, [key]: value };
|
||||
}, {});
|
||||
validatedValues.values = urlValues;
|
||||
return validatedValues;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,8 @@ export class SolutionForm extends Component<SolutionFormProps> {
|
||||
},
|
||||
required: ['solution'],
|
||||
isEditorLinkAllowed: false,
|
||||
isLocalLinkAllowed: false
|
||||
isLocalLinkAllowed: false,
|
||||
isSourceCodeLinkRequired: false
|
||||
};
|
||||
|
||||
let formFields = solutionField;
|
||||
@@ -85,7 +86,8 @@ export class SolutionForm extends Component<SolutionFormProps> {
|
||||
|
||||
case challengeTypes.backEndProject:
|
||||
formFields = backEndProjectFields;
|
||||
options.required.push('githubLink');
|
||||
// options.required.push('githubLink');
|
||||
options.isSourceCodeLinkRequired = true;
|
||||
options.isLocalLinkAllowed = true;
|
||||
solutionLink = solutionLink + 'https://3000-project-url.gitpod.io/';
|
||||
solutionFormID = 'back-end-form';
|
||||
|
||||
Reference in New Issue
Block a user