feat(learn): add python video challenges (#38424)
This commit is contained in:
committed by
Mrugesh Mohapatra
parent
22afc2a0ca
commit
e776529ed0
@ -167,6 +167,16 @@
|
||||
"description": "Camper is information security and quality assurance certified",
|
||||
"default": false
|
||||
},
|
||||
"isQaCert": {
|
||||
"type": "boolean",
|
||||
"description": "Camper is quality assurance certified",
|
||||
"default": false
|
||||
},
|
||||
"isInfosecCert": {
|
||||
"type": "boolean",
|
||||
"description": "Camper is information security certified",
|
||||
"default": false
|
||||
},
|
||||
"is2018FullStackCert": {
|
||||
"type": "boolean",
|
||||
"description": "Camper is full stack certified (2018)",
|
||||
|
@ -19,6 +19,8 @@ import {
|
||||
dataVis2018Id,
|
||||
apisMicroservicesId,
|
||||
infosecQaId,
|
||||
infosecId,
|
||||
qaId,
|
||||
fullStackId,
|
||||
sciCompPyId,
|
||||
dataAnalysisPyId,
|
||||
@ -107,6 +109,8 @@ function createCertTypeIds(app) {
|
||||
Challenge
|
||||
),
|
||||
[certTypes.infosecQa]: getIdsForCert$(infosecQaId, Challenge),
|
||||
[certTypes.qa]: getIdsForCert$(qaId, Challenge),
|
||||
[certTypes.infosec]: getIdsForCert$(infosecId, Challenge),
|
||||
[certTypes.fullStack]: getIdsForCert$(fullStackId, Challenge),
|
||||
[certTypes.sciCompPy]: getIdsForCert$(sciCompPyId, Challenge),
|
||||
[certTypes.dataAnalysisPy]: getIdsForCert$(dataAnalysisPyId, Challenge),
|
||||
@ -133,6 +137,8 @@ const certIds = {
|
||||
[certTypes.dataVis2018]: dataVis2018Id,
|
||||
[certTypes.apisMicroservices]: apisMicroservicesId,
|
||||
[certTypes.infosecQa]: infosecQaId,
|
||||
[certTypes.qa]: qaId,
|
||||
[certTypes.infosec]: infosecId,
|
||||
[certTypes.fullStack]: fullStackId,
|
||||
[certTypes.sciCompPy]: sciCompPyId,
|
||||
[certTypes.dataAnalysisPy]: dataAnalysisPyId,
|
||||
@ -150,6 +156,8 @@ const certText = {
|
||||
[certTypes.dataVis2018]: 'Data Visualization',
|
||||
[certTypes.apisMicroservices]: 'APIs and Microservices',
|
||||
[certTypes.infosecQa]: 'Information Security and Quality Assurance',
|
||||
[certTypes.qa]: 'Quality Assurance',
|
||||
[certTypes.infosec]: 'Information Security',
|
||||
[certTypes.sciCompPy]: 'Scientific Computing with Python',
|
||||
[certTypes.dataAnalysisPy]: 'Data Analysis with Python',
|
||||
[certTypes.machineLearningPy]: 'Machine Learning with Python'
|
||||
@ -166,6 +174,8 @@ const completionHours = {
|
||||
[certTypes.dataVis2018]: 300,
|
||||
[certTypes.apisMicroservices]: 300,
|
||||
[certTypes.infosecQa]: 300,
|
||||
[certTypes.qa]: 300,
|
||||
[certTypes.infosec]: 300,
|
||||
[certTypes.sciCompPy]: 400,
|
||||
[certTypes.dataAnalysisPy]: 400,
|
||||
[certTypes.machineLearningPy]: 400
|
||||
@ -193,6 +203,8 @@ function sendCertifiedEmail(
|
||||
isDataVisCert,
|
||||
isApisMicroservicesCert,
|
||||
isInfosecQaCert,
|
||||
isQaCert,
|
||||
isInfosecCert,
|
||||
isSciCompPyCert,
|
||||
isDataAnalysisPyCert,
|
||||
isMachineLearningPyCert
|
||||
@ -207,6 +219,8 @@ function sendCertifiedEmail(
|
||||
!isDataVisCert ||
|
||||
!isApisMicroservicesCert ||
|
||||
!isInfosecQaCert ||
|
||||
!isQaCert ||
|
||||
!isInfosecCert ||
|
||||
!isSciCompPyCert ||
|
||||
!isDataAnalysisPyCert ||
|
||||
!isMachineLearningPyCert
|
||||
@ -237,6 +251,8 @@ function getUserIsCertMap(user) {
|
||||
is2018DataVisCert = false,
|
||||
isApisMicroservicesCert = false,
|
||||
isInfosecQaCert = false,
|
||||
isQaCert = false,
|
||||
isInfosecCert = false,
|
||||
isFrontEndCert = false,
|
||||
isBackEndCert = false,
|
||||
isDataVisCert = false,
|
||||
@ -253,6 +269,8 @@ function getUserIsCertMap(user) {
|
||||
is2018DataVisCert,
|
||||
isApisMicroservicesCert,
|
||||
isInfosecQaCert,
|
||||
isQaCert,
|
||||
isInfosecCert,
|
||||
isFrontEndCert,
|
||||
isBackEndCert,
|
||||
isDataVisCert,
|
||||
@ -380,6 +398,8 @@ function createShowCert(app) {
|
||||
is2018DataVisCert: true,
|
||||
isApisMicroservicesCert: true,
|
||||
isInfosecQaCert: true,
|
||||
isQaCert: true,
|
||||
isInfosecCert: true,
|
||||
isSciCompPyCert: true,
|
||||
isDataAnalysisPyCert: true,
|
||||
isMachineLearningPyCert: true,
|
||||
|
@ -162,6 +162,8 @@ function postResetProgress(req, res, next) {
|
||||
isJsAlgoDataStructCert: false,
|
||||
isApisMicroservicesCert: false,
|
||||
isInfosecQaCert: false,
|
||||
isQaCert: false,
|
||||
isInfosecCert: false,
|
||||
is2018FullStackCert: false,
|
||||
isFrontEndCert: false,
|
||||
isBackEndCert: false,
|
||||
|
@ -8,6 +8,8 @@
|
||||
"jsAlgoDataStruct": "isJsAlgoDataStructCert",
|
||||
"apisMicroservices": "isApisMicroservicesCert",
|
||||
"infosecQa": "isInfosecQaCert",
|
||||
"qa": "isQaCert",
|
||||
"infosec": "isInfosecCert",
|
||||
"fullStack": "isFullStackCert",
|
||||
"sciCompPy": "isSciCompPyCert",
|
||||
"dataAnalysisPy": "isDataAnalysisPyCert",
|
||||
|
@ -8,6 +8,8 @@
|
||||
"dataVisCert": "Data Visualisation Certification",
|
||||
"apisMicroservicesCert": "APIs and Microservices Certification",
|
||||
"infosecQaCert": "Information Security and Quality Assurance Certification",
|
||||
"qaCert": "Quality Assurance Certification",
|
||||
"infosecCert": "Information Security Certification",
|
||||
"sciCompPyCert": "Scientific Computing with Python Certification",
|
||||
"dataAnalysisPyCert": "Data Analysis with Python Certification",
|
||||
"machineLearningPyCert": "Machine Learning with Python Certification"
|
||||
|
@ -18,6 +18,8 @@ export function completeCommitment$(user) {
|
||||
isDataVisCert,
|
||||
isApisMicroservicesCert,
|
||||
isInfosecQaCert,
|
||||
isQaCert,
|
||||
isInfosecCert,
|
||||
isSciCompPyCert,
|
||||
isDataAnalysisPyCert,
|
||||
isMachineLearningPyCert
|
||||
@ -40,6 +42,8 @@ export function completeCommitment$(user) {
|
||||
(isDataVisCert && goal === commitGoals.dataVisCert) ||
|
||||
(isApisMicroservicesCert && goal === commitGoals.apisMicroservicesCert) ||
|
||||
(isInfosecQaCert && goal === commitGoals.infosecQaCert) ||
|
||||
(isQaCert && goal === commitGoals.QaCert) ||
|
||||
(isInfosecCert && goal === commitGoals.infosecCert) ||
|
||||
(isSciCompPyCert && goal === commitGoals.sciCompPyCert) ||
|
||||
(isDataAnalysisPyCert && goal === commitGoals.dataAnalysisPyCert) ||
|
||||
(isMachineLearningPyCert && goal === commitGoals.machineLearningPyCert)
|
||||
|
@ -11,6 +11,8 @@
|
||||
"jsAlgoDataStructId": "561abd10cb81ac38a17513bc",
|
||||
"apisMicroservicesId": "561add10cb82ac38a17523bc",
|
||||
"infosecQaId": "561add10cb82ac38a17213bc",
|
||||
"qaId": "5e611829481575a52dc59c0e",
|
||||
"infosecId": "5e6021435ac9d0ecd8b94b00",
|
||||
"fullStackId": "561add10cb82ac38a17213bd",
|
||||
"sciCompPyId": "5e44431b903586ffb414c951",
|
||||
"dataAnalysisPyId": "5e46fc95ac417301a38fb934",
|
||||
|
@ -4,6 +4,8 @@ function getCompletedCertCount(user) {
|
||||
'is2018DataVisCert',
|
||||
'isFrontEndLibsCert',
|
||||
'isInfosecQaCert',
|
||||
'isQaCert',
|
||||
'isInfosecCert',
|
||||
'isJsAlgoDataStructCert',
|
||||
'isRespWebDesignCert',
|
||||
'isSciCompPyCert',
|
||||
|
@ -23,6 +23,8 @@ export const publicUserProps = [
|
||||
'isFrontEndLibsCert',
|
||||
'isHonest',
|
||||
'isInfosecQaCert',
|
||||
'isQaCert',
|
||||
'isInfosecCert',
|
||||
'isJsAlgoDataStructCert',
|
||||
'isRespWebDesignCert',
|
||||
'isSciCompPyCert',
|
||||
|
@ -13,6 +13,8 @@ const superBlockCertTypeMap = {
|
||||
'data-visualization': certTypes.dataVis2018,
|
||||
'apis-and-microservices': certTypes.apisMicroservices,
|
||||
'information-security-and-quality-assurance': certTypes.infosecQa,
|
||||
'quality-assurance': certTypes.qa,
|
||||
'information-security': certTypes.infosec,
|
||||
'full-stack': certTypes.fullStack,
|
||||
'scientific-computing-with-python': certTypes.sciCompPy,
|
||||
'data-analysis-with-python': certTypes.dataAnalysisPy,
|
||||
|
@ -143,6 +143,8 @@ function getCompletedCertCount(user) {
|
||||
'is2018DataVisCert',
|
||||
'isFrontEndLibsCert',
|
||||
'isInfosecQaCert',
|
||||
'isQaCert',
|
||||
'isInfosecCert',
|
||||
'isJsAlgoDataStructCert',
|
||||
'isRespWebDesignCert',
|
||||
'isSciCompPyCert',
|
||||
|
@ -60,6 +60,8 @@ const propTypes = {
|
||||
isFullStackCert: PropTypes.bool,
|
||||
isHonest: PropTypes.bool,
|
||||
isInfosecQaCert: PropTypes.bool,
|
||||
isQaCert: PropTypes.bool,
|
||||
isInfosecCert: PropTypes.bool,
|
||||
isJsAlgoDataStructCert: PropTypes.bool,
|
||||
isRespWebDesignCert: PropTypes.bool,
|
||||
isSciCompPyCert: PropTypes.bool,
|
||||
@ -132,6 +134,8 @@ export function ShowSettings(props) {
|
||||
isDataVisCert,
|
||||
isFrontEndCert,
|
||||
isInfosecQaCert,
|
||||
isQaCert,
|
||||
isInfosecCert,
|
||||
isFrontEndLibsCert,
|
||||
isFullStackCert,
|
||||
isRespWebDesignCert,
|
||||
@ -245,9 +249,11 @@ export function ShowSettings(props) {
|
||||
isFrontEndLibsCert={isFrontEndLibsCert}
|
||||
isFullStackCert={isFullStackCert}
|
||||
isHonest={isHonest}
|
||||
isInfosecCert={isInfosecCert}
|
||||
isInfosecQaCert={isInfosecQaCert}
|
||||
isJsAlgoDataStructCert={isJsAlgoDataStructCert}
|
||||
isMachineLearningPyCert={isMachineLearningPyCert}
|
||||
isQaCert={isQaCert}
|
||||
isRespWebDesignCert={isRespWebDesignCert}
|
||||
isSciCompPyCert={isSciCompPyCert}
|
||||
username={username}
|
||||
|
@ -40,7 +40,7 @@ const AsFeaturedSection = () => (
|
||||
|
||||
export const Landing = ({ edges }) => {
|
||||
const superBlocks = uniq(edges.map(element => element.node.superBlock));
|
||||
const interviewPrep = superBlocks.splice(9, 1);
|
||||
const interviewPrep = superBlocks.splice(10, 1);
|
||||
return (
|
||||
<Fragment>
|
||||
<Helmet>
|
||||
|
@ -50,9 +50,11 @@ const propTypes = {
|
||||
isFrontEndLibsCert: PropTypes.bool,
|
||||
isFullStackCert: PropTypes.bool,
|
||||
isHonest: PropTypes.bool,
|
||||
isInfosecCert: PropTypes.bool,
|
||||
isInfosecQaCert: PropTypes.bool,
|
||||
isJsAlgoDataStructCert: PropTypes.bool,
|
||||
isMachineLearningPyCert: PropTypes.bool,
|
||||
isQaCert: PropTypes.bool,
|
||||
isRespWebDesignCert: PropTypes.bool,
|
||||
isSciCompPyCert: PropTypes.bool,
|
||||
updateLegacyCert: PropTypes.func.isRequired,
|
||||
@ -70,6 +72,8 @@ const isCertSelector = ({
|
||||
isDataVisCert,
|
||||
isFrontEndCert,
|
||||
isInfosecQaCert,
|
||||
isQaCert,
|
||||
isInfosecCert,
|
||||
isFrontEndLibsCert,
|
||||
isFullStackCert,
|
||||
isRespWebDesignCert,
|
||||
@ -84,6 +88,8 @@ const isCertSelector = ({
|
||||
isDataVisCert,
|
||||
isFrontEndCert,
|
||||
isInfosecQaCert,
|
||||
isQaCert,
|
||||
isInfosecCert,
|
||||
isFrontEndLibsCert,
|
||||
isFullStackCert,
|
||||
isRespWebDesignCert,
|
||||
@ -99,6 +105,8 @@ const isCertMapSelector = createSelector(
|
||||
isApisMicroservicesCert,
|
||||
isJsAlgoDataStructCert,
|
||||
isInfosecQaCert,
|
||||
isQaCert,
|
||||
isInfosecCert,
|
||||
isFrontEndLibsCert,
|
||||
isRespWebDesignCert,
|
||||
isDataVisCert,
|
||||
@ -114,6 +122,8 @@ const isCertMapSelector = createSelector(
|
||||
'Data Visualization': is2018DataVisCert,
|
||||
"API's and Microservices": isApisMicroservicesCert,
|
||||
'Information Security And Quality Assurance': isInfosecQaCert,
|
||||
'Quality Assurance': isQaCert,
|
||||
'Information Security': isInfosecCert,
|
||||
'Scientific Computing with Python': isSciCompPyCert,
|
||||
'Data Analysis with Python': isDataAnalysisPyCert,
|
||||
'Machine Learning with Python': isMachineLearningPyCert,
|
||||
@ -462,7 +472,7 @@ export class CertificationSettings extends Component {
|
||||
is2018DataVisCert,
|
||||
isApisMicroservicesCert,
|
||||
isFrontEndLibsCert,
|
||||
isInfosecQaCert,
|
||||
isQaCert,
|
||||
isJsAlgoDataStructCert,
|
||||
isRespWebDesignCert
|
||||
} = this.props;
|
||||
@ -471,7 +481,7 @@ export class CertificationSettings extends Component {
|
||||
is2018DataVisCert &&
|
||||
isApisMicroservicesCert &&
|
||||
isFrontEndLibsCert &&
|
||||
isInfosecQaCert &&
|
||||
isQaCert &&
|
||||
isJsAlgoDataStructCert &&
|
||||
isRespWebDesignCert;
|
||||
|
||||
@ -509,7 +519,7 @@ export class CertificationSettings extends Component {
|
||||
<li>Front End Libraries</li>
|
||||
<li>Data Visualization</li>
|
||||
<li>APIs and Microservices</li>
|
||||
<li>Information Security and Quality Assurance</li>
|
||||
<li>Quality Assurance</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
@ -189,6 +189,8 @@ const defaultTestProps = {
|
||||
isFullStackCert: false,
|
||||
isHonest: false,
|
||||
isInfosecQaCert: false,
|
||||
isQaCert: false,
|
||||
isInfosecCert: false,
|
||||
isJsAlgoDataStructCert: false,
|
||||
isRespWebDesignCert: false,
|
||||
isSciCompPyCert: false,
|
||||
|
@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Information Security and Quality Assurance
|
||||
superBlock: Information Security and Quality Assurance
|
||||
---
|
||||
## Introduction to Information Security and Quality Assurance
|
||||
|
||||
This is a stub introduction for Information Security and Quality Assurance
|
@ -1,19 +0,0 @@
|
||||
---
|
||||
title: Introduction to the Information Security and Quality Assurance Projects
|
||||
block: Information Security and Quality Assurance Projects
|
||||
superBlock: Information Security and Quality Assurance
|
||||
---
|
||||
## Introduction to the Information Security and Quality Assurance Projects
|
||||
|
||||
Now it’s time to put your newly learned skills to work! By working on these projects, you will have the opportunity of applying all the skills, principles, and concepts from the Information Security and Quality Assurance sections.
|
||||
|
||||
In this section you get the chance to:
|
||||
* Build a Metric-Imperial Converter
|
||||
* Build an Issue Tracker
|
||||
* Build a Personal Library
|
||||
* Build a Stock Price Checker
|
||||
* Build an Anonymous Message Board
|
||||
* Port Scanner
|
||||
* Packet Capturer
|
||||
|
||||
When you are done, you will have plenty of Information Security & Quality Assurance projects under your belt along with a certification that you can show off to friends, family, and employers. Have fun and remember to use the [Read-Search-Ask](https://www.freecodecamp.org/forum/t/how-to-get-help-when-you-are-stuck/19514) method if you get stuck.
|
7
client/src/pages/learn/information-security/index.md
Normal file
7
client/src/pages/learn/information-security/index.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
title: Information Security
|
||||
superBlock: Information Security
|
||||
---
|
||||
## Introduction to Information Security
|
||||
|
||||
This is a stub introduction for Information Security
|
@ -0,0 +1,17 @@
|
||||
---
|
||||
title: Introduction to the Information Security Projects
|
||||
block: Information Security Projects
|
||||
superBlock: Information Security
|
||||
---
|
||||
## Introduction to the Information Security Projects
|
||||
|
||||
Now it’s time to put your newly learned skills to work! By working on these projects, you will have the opportunity of applying all the skills, principles, and concepts from the Information Security sections.
|
||||
|
||||
In this section you get the chance to:
|
||||
* Build a Stock Price Checker
|
||||
* Build an Anonymous Message Board
|
||||
* Secure Real Time Multiplayer Game
|
||||
* Port Scanner
|
||||
* Packet Capturer
|
||||
|
||||
When you are done, you will have plenty of Information Security projects under your belt along with a certification that you can show off to friends, family, and employers. Have fun and remember to use the [Read-Search-Ask](https://www.freecodecamp.org/forum/t/how-to-get-help-when-you-are-stuck/19514) method if you get stuck.
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Introduction to Information Security with HelmetJS Challenges
|
||||
block: Information Security with HelmetJS
|
||||
superBlock: Information Security and Quality Assurance
|
||||
superBlock: Information Security
|
||||
---
|
||||
## Introduction to Information Security with HelmetJS Challenges
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Introduction to the Advanced Node and Express Challenges
|
||||
block: Advanced Node and Express
|
||||
superBlock: Information Security and Quality Assurance
|
||||
superBlock: Quality Assurance
|
||||
---
|
||||
## Introduction to Advanced Node and Express Challenges
|
||||
|
7
client/src/pages/learn/quality-assurance/index.md
Normal file
7
client/src/pages/learn/quality-assurance/index.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
title: Quality Assurance
|
||||
superBlock: Quality Assurance
|
||||
---
|
||||
## Introduction to Quality Assurance
|
||||
|
||||
This is a stub introduction for Quality Assurance
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Introduction to the Quality Assurance with Chai Challenges
|
||||
block: Quality Assurance and Testing with Chai
|
||||
superBlock: Information Security and Quality Assurance
|
||||
superBlock: Quality Assurance
|
||||
---
|
||||
## Introduction to Quality Assurance with Chai Challenges
|
||||
|
@ -0,0 +1,17 @@
|
||||
---
|
||||
title: Introduction to the Quality Assurance Projects
|
||||
block: Quality Assurance Projects
|
||||
superBlock: Quality Assurance
|
||||
---
|
||||
## Introduction to the Quality Assurance Projects
|
||||
|
||||
Now it’s time to put your newly learned skills to work! By working on these projects, you will have the opportunity of applying all the skills, principles, and concepts from the Quality Assurance sections.
|
||||
|
||||
In this section you get the chance to:
|
||||
* Build a Metric-Imperial Converter
|
||||
* Build an Issue Tracker
|
||||
* Build a Personal Library
|
||||
* Sudoku Solver
|
||||
* American British Translator
|
||||
|
||||
When you are done, you will have plenty of Quality Assurance projects under your belt along with a certification that you can show off to friends, family, and employers. Have fun and remember to use the [Read-Search-Ask](https://www.freecodecamp.org/forum/t/how-to-get-help-when-you-are-stuck/19514) method if you get stuck.
|
@ -0,0 +1,12 @@
|
||||
---
|
||||
title: Introduction to Python for Everybody
|
||||
block: Python for Everybody
|
||||
superBlock: Scientific Computing with Python
|
||||
---
|
||||
## Introduction to Python for Everybody
|
||||
|
||||
Python for Everybody is a video course that teaches the basics of programming computers using Python 3.
|
||||
|
||||
The course was created by Dr. Charles Severance (a.k.a. Dr. Chuck). He is a Clinical Professor at the University of Michigan School of Information, where he teaches various technology-oriented courses including programming, database design, and Web development.
|
||||
|
||||
|
@ -213,6 +213,8 @@ export const certificatesByNameSelector = username => state => {
|
||||
isJsAlgoDataStructCert,
|
||||
isApisMicroservicesCert,
|
||||
isInfosecQaCert,
|
||||
isQaCert,
|
||||
isInfosecCert,
|
||||
isFrontEndCert,
|
||||
isBackEndCert,
|
||||
isDataVisCert,
|
||||
@ -229,6 +231,8 @@ export const certificatesByNameSelector = username => state => {
|
||||
isJsAlgoDataStructCert ||
|
||||
isApisMicroservicesCert ||
|
||||
isInfosecQaCert ||
|
||||
isQaCert ||
|
||||
isInfosecCert ||
|
||||
isFullStackCert ||
|
||||
isSciCompPyCert ||
|
||||
isDataAnalysisPyCert ||
|
||||
@ -270,6 +274,16 @@ export const certificatesByNameSelector = username => state => {
|
||||
title: 'Information Security and Quality Assurance Certification',
|
||||
showURL: 'information-security-and-quality-assurance'
|
||||
},
|
||||
{
|
||||
show: isQaCert,
|
||||
title: ' Quality Assurance Certification',
|
||||
showURL: 'information-security-and-quality-assurance'
|
||||
},
|
||||
{
|
||||
show: isInfosecCert,
|
||||
title: 'Information Security Certification',
|
||||
showURL: 'information-security-and-quality-assurance'
|
||||
},
|
||||
{
|
||||
show: isSciCompPyCert,
|
||||
title: 'Scientific Computing with Python Certification',
|
||||
|
@ -7,9 +7,8 @@ const feLibsBase = '/learn/front-end-libraries/front-end-libraries-projects';
|
||||
const dataVisBase = '/learn/data-visualization/data-visualization-projects';
|
||||
const apiMicroBase =
|
||||
'/learn/apis-and-microservices/apis-and-microservices-projects';
|
||||
const infoSecBase =
|
||||
'/learn/information-security-and-quality-assurance/' +
|
||||
'information-security-and-quality-assurance-projects';
|
||||
const qaBase = 'learn/quality-assurance/quality-assurance-projects';
|
||||
const infoSecBase = '/learn/information-security/information-security-projects';
|
||||
const sciCompPyBase =
|
||||
'/learn/scientific-computing-with-python/' +
|
||||
'scientific-computing-with-python-projects';
|
||||
@ -371,48 +370,68 @@ export const projectMap = {
|
||||
superBlock: 'apis-and-microservices'
|
||||
}
|
||||
],
|
||||
'Information Security And Quality Assurance': [
|
||||
'Quality Assurance': [
|
||||
{
|
||||
id: '587d8249367417b2b2512c41',
|
||||
title: 'Metric-Imperial Converter',
|
||||
link: `${infoSecBase}/metric-imperial-converter`,
|
||||
superBlock: 'information-security-and-quality-assurance'
|
||||
link: `${qaBase}/metric-imperial-converter`,
|
||||
superBlock: 'quality-assurance'
|
||||
},
|
||||
{
|
||||
id: '587d8249367417b2b2512c42',
|
||||
title: 'Issue Tracker',
|
||||
link: `${infoSecBase}/issue-tracker`,
|
||||
superBlock: 'information-security-and-quality-assurance'
|
||||
link: `${qaBase}/issue-tracker`,
|
||||
superBlock: 'quality-assurance'
|
||||
},
|
||||
{
|
||||
id: '587d824a367417b2b2512c43',
|
||||
title: 'Personal Library',
|
||||
link: `${infoSecBase}/personal-library`,
|
||||
superBlock: 'information-security-and-quality-assurance'
|
||||
link: `${qaBase}/personal-library`,
|
||||
superBlock: 'quality-assurance'
|
||||
},
|
||||
{
|
||||
id: '5e601bf95ac9d0ecd8b94afd',
|
||||
title: 'Sudoku Solver',
|
||||
link: `${qaBase}/sudoku-solver`,
|
||||
superBlock: 'quality-assurance'
|
||||
},
|
||||
{
|
||||
id: '5e601c0d5ac9d0ecd8b94afe',
|
||||
title: 'American British Translator',
|
||||
link: `${qaBase}/american-british-translator`,
|
||||
superBlock: 'quality-assurance'
|
||||
}
|
||||
],
|
||||
'Information Security': [
|
||||
{
|
||||
id: '587d824a367417b2b2512c44',
|
||||
title: 'Stock Price Checker',
|
||||
link: `${infoSecBase}/stock-price-checker`,
|
||||
superBlock: 'information-security-and-quality-assurance'
|
||||
superBlock: 'information-security'
|
||||
},
|
||||
{
|
||||
id: '587d824a367417b2b2512c45',
|
||||
title: 'Anonymous Message Board',
|
||||
link: `${infoSecBase}/anonymous-message-board`,
|
||||
superBlock: 'information-security-and-quality-assurance'
|
||||
superBlock: 'information-security'
|
||||
},
|
||||
{
|
||||
id: '5e46f979ac417301a38fb932',
|
||||
title: 'Port Scanner',
|
||||
link: `${infoSecBase}/port-scanner`,
|
||||
superBlock: 'information-security-and-quality-assurance'
|
||||
superBlock: 'information-security'
|
||||
},
|
||||
{
|
||||
id: '5e46f983ac417301a38fb933',
|
||||
title: 'SHA-1 Password Cracker',
|
||||
link: `${infoSecBase}/sha-1-password-cracker`,
|
||||
superBlock: 'information-security-and-quality-assurance'
|
||||
superBlock: 'information-security'
|
||||
},
|
||||
{
|
||||
id: '5e601c775ac9d0ecd8b94aff',
|
||||
title: 'Real Time Multiplayer Game',
|
||||
link: `${infoSecBase}/real-time-multiplayer-game`,
|
||||
superBlock: 'information-security'
|
||||
}
|
||||
],
|
||||
'Scientific Computing with Python': [
|
||||
|
@ -0,0 +1,301 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import noop from 'lodash/noop';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { Button, Modal } from '@freecodecamp/react-bootstrap';
|
||||
import { useStaticQuery, graphql } from 'gatsby';
|
||||
import SanitizedSpan from '../components/SanitizedSpan';
|
||||
|
||||
import Login from '../../../components/Header/components/Login';
|
||||
|
||||
import './completion-modal.css';
|
||||
|
||||
import {
|
||||
closeModal,
|
||||
submitChallenge,
|
||||
completedChallengesIds,
|
||||
isCompletionModalOpenSelector,
|
||||
challengeFilesSelector,
|
||||
challengeMetaSelector,
|
||||
lastBlockChalSubmitted
|
||||
} from '../redux';
|
||||
|
||||
import { isSignedInSelector, executeGA } from '../../../redux';
|
||||
|
||||
const mapStateToProps = createSelector(
|
||||
challengeFilesSelector,
|
||||
challengeMetaSelector,
|
||||
completedChallengesIds,
|
||||
isCompletionModalOpenSelector,
|
||||
isSignedInSelector,
|
||||
(files, { title, id }, completedChallengesIds, isOpen, isSignedIn) => ({
|
||||
files,
|
||||
title,
|
||||
id,
|
||||
completedChallengesIds,
|
||||
isOpen,
|
||||
isSignedIn
|
||||
})
|
||||
);
|
||||
|
||||
const mapDispatchToProps = function(dispatch) {
|
||||
const dispatchers = {
|
||||
close: () => dispatch(closeModal('completion')),
|
||||
submitChallenge: () => {
|
||||
dispatch(submitChallenge());
|
||||
},
|
||||
lastBlockChalSubmitted: () => {
|
||||
dispatch(lastBlockChalSubmitted());
|
||||
},
|
||||
executeGA
|
||||
};
|
||||
return () => dispatchers;
|
||||
};
|
||||
|
||||
const propTypes = {
|
||||
answers: PropTypes.array,
|
||||
blockName: PropTypes.string,
|
||||
close: PropTypes.func.isRequired,
|
||||
completedChallengesIds: PropTypes.array,
|
||||
currentBlockIds: PropTypes.array,
|
||||
executeGA: PropTypes.func,
|
||||
files: PropTypes.object.isRequired,
|
||||
id: PropTypes.string,
|
||||
isOpen: PropTypes.bool,
|
||||
isSignedIn: PropTypes.bool.isRequired,
|
||||
lastBlockChalSubmitted: PropTypes.func,
|
||||
question: PropTypes.string,
|
||||
solution: PropTypes.number,
|
||||
submitChallenge: PropTypes.func.isRequired,
|
||||
title: PropTypes.string
|
||||
};
|
||||
|
||||
export function getCompletedPercent(
|
||||
completedChallengesIds = [],
|
||||
currentBlockIds = [],
|
||||
currentChallengeId
|
||||
) {
|
||||
completedChallengesIds = completedChallengesIds.includes(currentChallengeId)
|
||||
? completedChallengesIds
|
||||
: [...completedChallengesIds, currentChallengeId];
|
||||
|
||||
const completedChallengesInBlock = completedChallengesIds.filter(id => {
|
||||
return currentBlockIds.includes(id);
|
||||
});
|
||||
|
||||
const completedPercent = Math.round(
|
||||
(completedChallengesInBlock.length / currentBlockIds.length) * 100
|
||||
);
|
||||
|
||||
return completedPercent > 100 ? 100 : completedPercent;
|
||||
}
|
||||
|
||||
export class CompletionModalInner extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.handleKeypress = this.handleKeypress.bind(this);
|
||||
}
|
||||
|
||||
state = {
|
||||
downloadURL: null,
|
||||
completedPercent: 0,
|
||||
selectedOption: 0,
|
||||
answer: 1,
|
||||
showWrong: false
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps(props, state) {
|
||||
const { files, isOpen } = props;
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
const { downloadURL } = state;
|
||||
if (downloadURL) {
|
||||
URL.revokeObjectURL(downloadURL);
|
||||
}
|
||||
let newURL = null;
|
||||
if (Object.keys(files).length) {
|
||||
const filesForDownload = Object.keys(files)
|
||||
.map(key => files[key])
|
||||
.reduce((allFiles, { path, contents }) => {
|
||||
const beforeText = `** start of ${path} **\n\n`;
|
||||
const afterText = `\n\n** end of ${path} **\n\n`;
|
||||
allFiles +=
|
||||
files.length > 1 ? beforeText + contents + afterText : contents;
|
||||
return allFiles;
|
||||
}, '');
|
||||
const blob = new Blob([filesForDownload], {
|
||||
type: 'text/json'
|
||||
});
|
||||
newURL = URL.createObjectURL(blob);
|
||||
}
|
||||
|
||||
const { completedChallengesIds, currentBlockIds, id, isSignedIn } = props;
|
||||
let completedPercent = isSignedIn
|
||||
? getCompletedPercent(completedChallengesIds, currentBlockIds, id)
|
||||
: 0;
|
||||
return { downloadURL: newURL, completedPercent: completedPercent };
|
||||
}
|
||||
|
||||
handleKeypress(e) {
|
||||
if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) {
|
||||
e.preventDefault();
|
||||
// Since Hotkeys also listens to Ctrl + Enter we have to stop this event
|
||||
// getting to it.
|
||||
e.stopPropagation();
|
||||
this.handleSubmit();
|
||||
}
|
||||
}
|
||||
|
||||
handleSubmit() {
|
||||
if (this.props.solution - 1 === this.state.selectedOption) {
|
||||
this.setState({
|
||||
showWrong: false
|
||||
});
|
||||
this.props.submitChallenge();
|
||||
this.checkBlockCompletion();
|
||||
} else {
|
||||
this.setState({
|
||||
showWrong: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// check block completion for donation
|
||||
checkBlockCompletion() {
|
||||
if (
|
||||
this.state.completedPercent === 100 &&
|
||||
!this.props.completedChallengesIds.includes(this.props.id)
|
||||
) {
|
||||
this.props.lastBlockChalSubmitted();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.state.downloadURL) {
|
||||
URL.revokeObjectURL(this.state.downloadURL);
|
||||
}
|
||||
this.props.close();
|
||||
}
|
||||
|
||||
handleOptionChange = changeEvent => {
|
||||
console.log(this.state.selectedOption);
|
||||
this.setState({
|
||||
selectedOption: parseInt(changeEvent.target.value, 10)
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { close, isOpen, isSignedIn, question, answers } = this.props;
|
||||
|
||||
if (isOpen) {
|
||||
executeGA({ type: 'modal', data: '/completion-modal' });
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
animation={false}
|
||||
bsSize='lg'
|
||||
dialogClassName='challenge-success-modal'
|
||||
keyboard={true}
|
||||
onHide={close}
|
||||
onKeyDown={isOpen ? this.handleKeypress : noop}
|
||||
show={isOpen}
|
||||
>
|
||||
<Modal.Header
|
||||
className='challenge-list-header fcc-modal'
|
||||
closeButton={true}
|
||||
>
|
||||
<Modal.Title className='completion-message'>Video Quiz</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body className='question-modal-body'>
|
||||
<SanitizedSpan text={question} />
|
||||
<form>
|
||||
{answers.map((option, index) => (
|
||||
<div className='form-check'>
|
||||
<label>
|
||||
<input
|
||||
checked={this.state.selectedOption === index}
|
||||
name='quiz'
|
||||
onChange={this.handleOptionChange}
|
||||
type='radio'
|
||||
value={index}
|
||||
/>{' '}
|
||||
<SanitizedSpan text={option} />
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</form>
|
||||
<div
|
||||
style={{
|
||||
visibility: this.state.showWrong ? 'visible' : 'hidden'
|
||||
}}
|
||||
>
|
||||
Wrong. Try again.
|
||||
</div>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
{isSignedIn ? null : (
|
||||
<Login
|
||||
block={true}
|
||||
bsSize='lg'
|
||||
bsStyle='primary'
|
||||
className='btn-cta'
|
||||
>
|
||||
Sign in to save your progress
|
||||
</Login>
|
||||
)}
|
||||
<Button
|
||||
block={true}
|
||||
bsSize='large'
|
||||
bsStyle='primary'
|
||||
onClick={this.handleSubmit}
|
||||
>
|
||||
Submit answer <span className='hidden-xs'>(Ctrl + Enter)</span>
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
CompletionModalInner.propTypes = propTypes;
|
||||
|
||||
const useCurrentBlockIds = blockName => {
|
||||
const {
|
||||
allChallengeNode: { edges }
|
||||
} = useStaticQuery(graphql`
|
||||
query getCurrentBlockNodesVid {
|
||||
allChallengeNode(sort: { fields: [superOrder, order, challengeOrder] }) {
|
||||
edges {
|
||||
node {
|
||||
fields {
|
||||
blockName
|
||||
}
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
const currentBlockIds = edges
|
||||
.filter(edge => edge.node.fields.blockName === blockName)
|
||||
.map(edge => edge.node.id);
|
||||
return currentBlockIds;
|
||||
};
|
||||
|
||||
const CompletionModal = props => {
|
||||
const currentBlockIds = useCurrentBlockIds(props.blockName || '');
|
||||
return <CompletionModalInner currentBlockIds={currentBlockIds} {...props} />;
|
||||
};
|
||||
|
||||
CompletionModal.displayName = 'CompletionModal';
|
||||
CompletionModal.propTypes = propTypes;
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(CompletionModal);
|
19
client/src/templates/Challenges/components/SanitizedSpan.js
Normal file
19
client/src/templates/Challenges/components/SanitizedSpan.js
Normal file
@ -0,0 +1,19 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import sanitizeHtml from 'sanitize-html';
|
||||
|
||||
const propTypes = {
|
||||
text: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
function SanitizedSpan({ text = '' }) {
|
||||
const sanitizedText = sanitizeHtml(text, {
|
||||
allowedTags: ['b', 'i', 'em', 'strong', 'code', 'wbr', 'br', 'pre']
|
||||
});
|
||||
return <span dangerouslySetInnerHTML={{ __html: sanitizedText }} />;
|
||||
}
|
||||
|
||||
SanitizedSpan.displayName = 'SanitizedSpan';
|
||||
SanitizedSpan.propTypes = propTypes;
|
||||
|
||||
export default SanitizedSpan;
|
@ -0,0 +1,41 @@
|
||||
/* global expect */
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import SanitizedSpan from './SanitizedSpan';
|
||||
|
||||
describe('<SanitizedSpan />', () => {
|
||||
it('matches the snapshot', () => {
|
||||
const { container } = render(
|
||||
<SanitizedSpan
|
||||
text={`some text <script>dangerous code</script>
|
||||
more <wbr>text <br> <img alt='danger' src='https://attack.com'>`}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('removes scripts, images, etc', () => {
|
||||
const { queryByAltText, queryByText } = render(
|
||||
<SanitizedSpan
|
||||
text={`some text <script>dangerous code</script>
|
||||
more text <img alt='danger' src='https://attack.com'>`}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(queryByText('dangerous code', { ignore: false })).toBeNull();
|
||||
expect(queryByAltText('danger')).toBeNull();
|
||||
});
|
||||
|
||||
it('leaves in line breaks', () => {
|
||||
const { container } = render(
|
||||
<SanitizedSpan
|
||||
text={`some text <br>
|
||||
more text`}
|
||||
/>
|
||||
);
|
||||
expect(container.querySelector('br')).not.toBeNull();
|
||||
});
|
||||
});
|
@ -0,0 +1,14 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<SanitizedSpan /> matches the snapshot 1`] = `
|
||||
<div>
|
||||
<span>
|
||||
some text
|
||||
more
|
||||
<wbr />
|
||||
text
|
||||
<br />
|
||||
|
||||
</span>
|
||||
</div>
|
||||
`;
|
@ -11,6 +11,14 @@
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.video-modal-body {
|
||||
min-height: 400px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
.completion-challenge-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
205
client/src/templates/Challenges/video/Show.js
Normal file
205
client/src/templates/Challenges/video/Show.js
Normal file
@ -0,0 +1,205 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Grid, Col, Row } from '@freecodecamp/react-bootstrap';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { graphql } from 'gatsby';
|
||||
import Helmet from 'react-helmet';
|
||||
import YouTube from 'react-youtube';
|
||||
|
||||
import { ChallengeNode } from '../../../redux/propTypes';
|
||||
import {
|
||||
challengeMounted,
|
||||
updateChallengeMeta,
|
||||
openModal,
|
||||
updateProjectFormValues
|
||||
} from '../redux';
|
||||
|
||||
import LearnLayout from '../../../components/layouts/Learn';
|
||||
import ChallengeTitle from '../components/Challenge-Title';
|
||||
import ChallengeDescription from '../components/Challenge-Description';
|
||||
import Spacer from '../../../components/helpers/Spacer';
|
||||
import CompletionVideoModal from '../components/CompletionVideoModal';
|
||||
import HelpModal from '../components/HelpModal';
|
||||
import Hotkeys from '../components/Hotkeys';
|
||||
|
||||
const mapStateToProps = () => ({});
|
||||
const mapDispatchToProps = dispatch =>
|
||||
bindActionCreators(
|
||||
{
|
||||
updateChallengeMeta,
|
||||
challengeMounted,
|
||||
updateProjectFormValues,
|
||||
openCompletionModal: () => openModal('completion')
|
||||
},
|
||||
dispatch
|
||||
);
|
||||
|
||||
const propTypes = {
|
||||
challengeMounted: PropTypes.func.isRequired,
|
||||
data: PropTypes.shape({
|
||||
challengeNode: ChallengeNode
|
||||
}),
|
||||
description: PropTypes.string,
|
||||
openCompletionModal: PropTypes.func.isRequired,
|
||||
pageContext: PropTypes.shape({
|
||||
challengeMeta: PropTypes.object
|
||||
}),
|
||||
updateChallengeMeta: PropTypes.func.isRequired,
|
||||
updateProjectFormValues: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export class Project extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
subtitles: ''
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
challengeMounted,
|
||||
data: {
|
||||
challengeNode: { title, challengeType }
|
||||
},
|
||||
pageContext: { challengeMeta },
|
||||
updateChallengeMeta
|
||||
} = this.props;
|
||||
updateChallengeMeta({ ...challengeMeta, title, challengeType });
|
||||
challengeMounted(challengeMeta.id);
|
||||
this._container.focus();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
data: {
|
||||
challengeNode: { title: prevTitle }
|
||||
}
|
||||
} = prevProps;
|
||||
const {
|
||||
challengeMounted,
|
||||
data: {
|
||||
challengeNode: { title: currentTitle, challengeType }
|
||||
},
|
||||
pageContext: { challengeMeta },
|
||||
updateChallengeMeta
|
||||
} = this.props;
|
||||
if (prevTitle !== currentTitle) {
|
||||
updateChallengeMeta({
|
||||
...challengeMeta,
|
||||
title: currentTitle,
|
||||
challengeType
|
||||
});
|
||||
challengeMounted(challengeMeta.id);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
data: {
|
||||
challengeNode: {
|
||||
fields: { blockName },
|
||||
title,
|
||||
description,
|
||||
videoId,
|
||||
question: { text, answers, solution }
|
||||
}
|
||||
},
|
||||
openCompletionModal,
|
||||
pageContext: {
|
||||
challengeMeta: { introPath, nextChallengePath, prevChallengePath }
|
||||
}
|
||||
} = this.props;
|
||||
const blockNameTitle = `${blockName} - ${title}`;
|
||||
|
||||
return (
|
||||
<Hotkeys
|
||||
innerRef={c => (this._container = c)}
|
||||
introPath={introPath}
|
||||
nextChallengePath={nextChallengePath}
|
||||
prevChallengePath={prevChallengePath}
|
||||
>
|
||||
<LearnLayout>
|
||||
<Helmet title={`${blockNameTitle} | Learn | freeCodeCamp.org`} />
|
||||
<Grid>
|
||||
<Row>
|
||||
<Col md={8} mdOffset={2} sm={10} smOffset={1} xs={12}>
|
||||
<Spacer />
|
||||
<ChallengeTitle>{blockNameTitle}</ChallengeTitle>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<YouTube
|
||||
onEnd={openCompletionModal}
|
||||
opts={{ rel: 0 }}
|
||||
videoId={videoId}
|
||||
/>
|
||||
<i>
|
||||
<a
|
||||
href={
|
||||
'https://www.youtube.com/timedtext_editor?action_mde_edit_form=1&v=' +
|
||||
videoId +
|
||||
'&lang=en&bl=watch&ui=hd&ref=wt&tab=captions'
|
||||
}
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
Help improve or add subtitles
|
||||
</a>
|
||||
.
|
||||
</i>
|
||||
</div>
|
||||
<Spacer />
|
||||
<ChallengeDescription description={description} />
|
||||
|
||||
<Button
|
||||
block={true}
|
||||
bsSize='large'
|
||||
bsStyle='primary'
|
||||
onClick={openCompletionModal}
|
||||
>
|
||||
Complete
|
||||
</Button>
|
||||
<Spacer />
|
||||
</Col>
|
||||
<CompletionVideoModal
|
||||
answers={answers}
|
||||
blockName={blockName}
|
||||
question={text}
|
||||
solution={solution}
|
||||
/>
|
||||
<HelpModal />
|
||||
</Row>
|
||||
</Grid>
|
||||
</LearnLayout>
|
||||
</Hotkeys>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Project.displayName = 'Project';
|
||||
Project.propTypes = propTypes;
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Project);
|
||||
|
||||
export const query = graphql`
|
||||
query VideoChallenge($slug: String!) {
|
||||
challengeNode(fields: { slug: { eq: $slug } }) {
|
||||
videoId
|
||||
title
|
||||
description
|
||||
challengeType
|
||||
fields {
|
||||
blockName
|
||||
slug
|
||||
}
|
||||
question {
|
||||
text
|
||||
answers
|
||||
solution
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
@ -14,13 +14,12 @@ const preFormattedBlockNames = {
|
||||
'apis-and-microservices': 'APIs and Microservices',
|
||||
'apis-and-microservices-projects': 'APIs and Microservices Projects',
|
||||
'scientific-computing-with-python': 'Scientific Computing with Python',
|
||||
'scientific-computing-with-python-projects':
|
||||
'Scientific Computing with Python Projects',
|
||||
'scientific-computing-with-python-projects': 'Certification Projects',
|
||||
'data-analysis-with-python': 'Data Analysis with Python',
|
||||
'data-analysis-with-python-projects': 'Data Analysis with Python Projects',
|
||||
'data-analysis-with-python-projects': 'Certification Projects',
|
||||
'machine-learning-with-python': 'Machine Learning with Python',
|
||||
'machine-learning-with-python-projects':
|
||||
'Machine Learning with Python Projects'
|
||||
'machine-learning-with-python-projects': 'Certification Projects',
|
||||
'information-security-projects': 'Certification Projects'
|
||||
};
|
||||
|
||||
const noFormatting = ['and', 'for', 'of', 'the', 'up', 'with'];
|
||||
|
@ -10,6 +10,7 @@ const step = 7;
|
||||
const quiz = 8;
|
||||
const invalid = 9;
|
||||
const pythonProject = 10;
|
||||
const video = 11;
|
||||
|
||||
// individual exports
|
||||
exports.backend = backend;
|
||||
@ -29,7 +30,8 @@ exports.challengeTypes = {
|
||||
modern,
|
||||
step,
|
||||
quiz,
|
||||
invalid
|
||||
invalid,
|
||||
video
|
||||
};
|
||||
|
||||
// turn challengeType to file ext
|
||||
@ -45,11 +47,12 @@ exports.viewTypes = {
|
||||
[bonfire]: 'classic',
|
||||
[frontEndProject]: 'frontend',
|
||||
[backEndProject]: 'backend',
|
||||
[pythonProject]: 'backend',
|
||||
[pythonProject]: 'frontend',
|
||||
[modern]: 'modern',
|
||||
[step]: 'step',
|
||||
[quiz]: 'quiz',
|
||||
[backend]: 'backend'
|
||||
[backend]: 'backend',
|
||||
[video]: 'video'
|
||||
};
|
||||
|
||||
// determine the type of submit function to use for the challenge on completion
|
||||
@ -68,7 +71,8 @@ exports.submitTypes = {
|
||||
[step]: 'step',
|
||||
[quiz]: 'quiz',
|
||||
[backend]: 'backend',
|
||||
[modern]: 'tests'
|
||||
[modern]: 'tests',
|
||||
[video]: 'tests'
|
||||
};
|
||||
|
||||
// determine which help forum questions should be posted to
|
||||
@ -109,8 +113,8 @@ exports.helpCategory = {
|
||||
'information-security-with-helmetjs': 'JavaScript',
|
||||
'quality-assurance-and-testing-with-chai': 'JavaScript',
|
||||
'advanced-node-and-express': 'JavaScript',
|
||||
'information-security-and-quality-assurance-projects':
|
||||
'Certification Projects',
|
||||
'quality-assurance-projects': 'Certification Projects',
|
||||
'information-security-projects': 'Certification Projects',
|
||||
algorithms: 'JavaScript',
|
||||
'data-structures': 'JavaScript',
|
||||
'take-home-projects': 'Certification Projects',
|
||||
|
@ -23,12 +23,17 @@ const superBlockIntro = path.resolve(
|
||||
__dirname,
|
||||
'../../src/templates/Introduction/SuperBlockIntro.js'
|
||||
);
|
||||
const video = path.resolve(
|
||||
__dirname,
|
||||
'../../src/templates/Challenges/video/Show.js'
|
||||
);
|
||||
|
||||
const views = {
|
||||
backend,
|
||||
classic,
|
||||
modern: classic,
|
||||
frontend
|
||||
frontend,
|
||||
video
|
||||
// quiz: Quiz
|
||||
};
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "Advanced Node and Express",
|
||||
"dashedName": "advanced-node-and-express",
|
||||
"order": 3,
|
||||
"order": 2,
|
||||
"time": "5 hours",
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "information-security-and-quality-assurance",
|
||||
"superBlock": "quality-assurance",
|
||||
"superOrder": 6,
|
||||
"challengeOrder": [
|
||||
[
|
||||
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "coding-interview-prep",
|
||||
"superOrder": 10,
|
||||
"superOrder": 11,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"a3f503de51cf954ede28891d",
|
||||
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "certificates",
|
||||
"superOrder": 11,
|
||||
"superOrder": 12,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"561add10cb82ac38a17523bc",
|
||||
@ -14,5 +14,5 @@
|
||||
]
|
||||
],
|
||||
"isPrivate": true,
|
||||
"fileName": "11-certificates/apis-and-microservices-certificate.json"
|
||||
"fileName": "12-certificates/apis-and-microservices-certificate.json"
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "certificates",
|
||||
"superOrder": 11,
|
||||
"superOrder": 12,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"5e46fc95ac417301a38fb934",
|
||||
@ -14,5 +14,5 @@
|
||||
]
|
||||
],
|
||||
"isPrivate": true,
|
||||
"fileName": "11-certificates/data-analysis-with-python-certificate.json"
|
||||
"fileName": "12-certificates/data-analysis-with-python-certificate.json"
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "coding-interview-prep",
|
||||
"superOrder": 10,
|
||||
"superOrder": 11,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"587d8253367417b2b2512c6a",
|
||||
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "certificates",
|
||||
"superOrder": 10,
|
||||
"superOrder": 12,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"5a553ca864b52e1d8bceea14",
|
||||
@ -14,5 +14,5 @@
|
||||
]
|
||||
],
|
||||
"isPrivate": true,
|
||||
"fileName": "11-certificates/data-visualization-certificate.json"
|
||||
"fileName": "12-certificates/data-visualization-certificate.json"
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "certificates",
|
||||
"superOrder": 11,
|
||||
"superOrder": 12,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"561acd10cb82ac38a17513bc",
|
||||
@ -14,5 +14,5 @@
|
||||
]
|
||||
],
|
||||
"isPrivate": true,
|
||||
"fileName": "11-certificates/front-end-libraries-certificate.json"
|
||||
"fileName": "12-certificates/front-end-libraries-certificate.json"
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "Information Security and Quality Assurance Projects",
|
||||
"dashedName": "information-security-and-quality-assurance-projects",
|
||||
"order": 4,
|
||||
"order": 0,
|
||||
"time": "150 hours",
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "information-security-and-quality-assurance",
|
||||
"superOrder": 6,
|
||||
"superOrder": 13,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"587d8249367417b2b2512c41",
|
||||
@ -27,16 +27,8 @@
|
||||
[
|
||||
"587d824a367417b2b2512c45",
|
||||
"Anonymous Message Board"
|
||||
],
|
||||
[
|
||||
"5e46f979ac417301a38fb932",
|
||||
"Port Scanner"
|
||||
],
|
||||
[
|
||||
"5e46f983ac417301a38fb933",
|
||||
"SHA-1 Password Cracker"
|
||||
]
|
||||
],
|
||||
"helpRoom": "HelpBackend",
|
||||
"fileName": "06-information-security-and-quality-assurance/quality-assurance-and-information-security-projects.json"
|
||||
"fileName": "12-information-security-and-quality-assurance/quality-assurance-and-information-security-projects.json"
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "Information Security Certificate",
|
||||
"dashedName": "information-security-certificate",
|
||||
"order": 9,
|
||||
"time": "",
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "certificates",
|
||||
"superOrder": 12,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"5e6021435ac9d0ecd8b94b00",
|
||||
"Information Security Certificate"
|
||||
]
|
||||
],
|
||||
"isPrivate": true,
|
||||
"fileName": "12-certificates/information-security-certificate.json"
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "Information Security Projects",
|
||||
"dashedName": "information-security-projects",
|
||||
"order": 2,
|
||||
"time": "150 hours",
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "information-security",
|
||||
"superOrder": 9,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"587d824a367417b2b2512c44",
|
||||
"Stock Price Checker"
|
||||
],
|
||||
[
|
||||
"587d824a367417b2b2512c45",
|
||||
"Anonymous Message Board"
|
||||
],
|
||||
[
|
||||
"5e601c775ac9d0ecd8b94aff",
|
||||
"Real Time Multiplayer Game"
|
||||
],
|
||||
[
|
||||
"5e46f979ac417301a38fb932",
|
||||
"Port Scanner"
|
||||
],
|
||||
[
|
||||
"5e46f983ac417301a38fb933",
|
||||
"SHA-1 Password Cracker"
|
||||
]
|
||||
],
|
||||
"helpRoom": "HelpBackend",
|
||||
"fileName": "09-information-security/information-security-projects.json"
|
||||
}
|
@ -5,8 +5,8 @@
|
||||
"time": "5 hours",
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "information-security-and-quality-assurance",
|
||||
"superOrder": 6,
|
||||
"superBlock": "information-security",
|
||||
"superOrder": 9,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"587d8247367417b2b2512c36",
|
||||
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "certificates",
|
||||
"superOrder": 11,
|
||||
"superOrder": 12,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"561add10cb82ac38a17213bc",
|
||||
@ -14,5 +14,5 @@
|
||||
]
|
||||
],
|
||||
"isPrivate": true,
|
||||
"fileName": "11-certificates/information-security-and-quality-assurance-certificate.json"
|
||||
"fileName": "12-certificates/information-security-and-quality-assurance-certificate.json"
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "certificates",
|
||||
"superOrder": 11,
|
||||
"superOrder": 12,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"561abd10cb81ac38a17513bc",
|
||||
@ -14,5 +14,5 @@
|
||||
]
|
||||
],
|
||||
"isPrivate": true,
|
||||
"fileName": "11-certificates/javascript-algorithms-and-data-structures-certificate.json"
|
||||
"fileName": "12-certificates/javascript-algorithms-and-data-structures-certificate.json"
|
||||
}
|
@ -0,0 +1,262 @@
|
||||
{
|
||||
"name": "Python for Everybody",
|
||||
"dashedName": "lectures-python-for-everybody",
|
||||
"order": 1,
|
||||
"time": "15 hours",
|
||||
"superBlock": "scientific-computing-with-python",
|
||||
"superOrder": 7,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"5e6a54a558d3af90110a60a0",
|
||||
"Introduction A"
|
||||
],
|
||||
[
|
||||
"5e6a54af58d3af90110a60a1",
|
||||
"Introduction B"
|
||||
],
|
||||
[
|
||||
"5e6a54ba58d3af90110a60a2",
|
||||
"Introduction C"
|
||||
],
|
||||
[
|
||||
"5e6a54c358d3af90110a60a3",
|
||||
"Introduction D"
|
||||
],
|
||||
[
|
||||
"5e7b9f050b6c005b0e76f056",
|
||||
"Expressions A"
|
||||
],
|
||||
[
|
||||
"5e7b9f050b6c005b0e76f057",
|
||||
"Expressions B"
|
||||
],
|
||||
[
|
||||
"5e7b9f050b6c005b0e76f058",
|
||||
"Conditional A"
|
||||
],
|
||||
[
|
||||
"5e7b9f060b6c005b0e76f059",
|
||||
"Conditional B"
|
||||
],
|
||||
[
|
||||
"5e7b9f060b6c005b0e76f05a",
|
||||
"Functions A"
|
||||
],
|
||||
[
|
||||
"5e7b9f060b6c005b0e76f05b",
|
||||
"Functions B"
|
||||
],
|
||||
[
|
||||
"5e7b9f060b6c005b0e76f05c",
|
||||
"Iterations A"
|
||||
],
|
||||
[
|
||||
"5e7b9f070b6c005b0e76f05d",
|
||||
"Iterations B"
|
||||
],
|
||||
[
|
||||
"5e7b9f070b6c005b0e76f05e",
|
||||
"Iterations C"
|
||||
],
|
||||
[
|
||||
"5e7b9f070b6c005b0e76f05f",
|
||||
"Iterations D"
|
||||
],
|
||||
[
|
||||
"5e7b9f070b6c005b0e76f060",
|
||||
"Strings A"
|
||||
],
|
||||
[
|
||||
"5e7b9f070b6c005b0e76f061",
|
||||
"Strings B"
|
||||
],
|
||||
[
|
||||
"5e7b9f080b6c005b0e76f062",
|
||||
"Files A"
|
||||
],
|
||||
[
|
||||
"5e7b9f080b6c005b0e76f063",
|
||||
"Files B"
|
||||
],
|
||||
[
|
||||
"5e7b9f080b6c005b0e76f064",
|
||||
"Lists A"
|
||||
],
|
||||
[
|
||||
"5e7b9f090b6c005b0e76f065",
|
||||
"Lists B"
|
||||
],
|
||||
[
|
||||
"5e7b9f090b6c005b0e76f066",
|
||||
"Lists C"
|
||||
],
|
||||
[
|
||||
"5e7b9f090b6c005b0e76f067",
|
||||
"Dictionaries A"
|
||||
],
|
||||
[
|
||||
"5e7b9f090b6c005b0e76f068",
|
||||
"Dictionaries B"
|
||||
],
|
||||
[
|
||||
"5e7b9f0a0b6c005b0e76f069",
|
||||
"Dictionaries C"
|
||||
],
|
||||
[
|
||||
"5e7b9f0a0b6c005b0e76f06c",
|
||||
"Tuples A"
|
||||
],
|
||||
[
|
||||
"5e7b9f0b0b6c005b0e76f06d",
|
||||
"Tuples B"
|
||||
],
|
||||
[
|
||||
"5e7b9f0b0b6c005b0e76f06e",
|
||||
"RegEx A"
|
||||
],
|
||||
[
|
||||
"5e7b9f0b0b6c005b0e76f06f",
|
||||
"RegEx B"
|
||||
],
|
||||
[
|
||||
"5e7b9f0b0b6c005b0e76f070",
|
||||
"RegEx C"
|
||||
],
|
||||
[
|
||||
"5e7b9f0c0b6c005b0e76f071",
|
||||
"HTTP A"
|
||||
],
|
||||
[
|
||||
"5e7b9f0c0b6c005b0e76f072",
|
||||
"HTTP B"
|
||||
],
|
||||
[
|
||||
"5e7b9f0c0b6c005b0e76f073",
|
||||
"HTTP C"
|
||||
],
|
||||
[
|
||||
"5e7b9f0c0b6c005b0e76f074",
|
||||
"HTTP D"
|
||||
],
|
||||
[
|
||||
"5e7b9f0d0b6c005b0e76f075",
|
||||
"HTTP E"
|
||||
],
|
||||
[
|
||||
"5e7b9f0d0b6c005b0e76f076",
|
||||
"HTTP F"
|
||||
],
|
||||
[
|
||||
"5e7b9f0e0b6c005b0e76f07a",
|
||||
"Web Services A"
|
||||
],
|
||||
[
|
||||
"5e7b9f0e0b6c005b0e76f07b",
|
||||
"Web Services B"
|
||||
],
|
||||
[
|
||||
"5e7b9f0e0b6c005b0e76f07c",
|
||||
"Web Services C"
|
||||
],
|
||||
[
|
||||
"5e7b9f140b6c005b0e76f07d",
|
||||
"Web Services D"
|
||||
],
|
||||
[
|
||||
"5e7b9f140b6c005b0e76f07e",
|
||||
"Web Services E"
|
||||
],
|
||||
[
|
||||
"5e7b9f150b6c005b0e76f07f",
|
||||
"Web Services F"
|
||||
],
|
||||
[
|
||||
"5e7b9f150b6c005b0e76f080",
|
||||
"Web Services G"
|
||||
],
|
||||
[
|
||||
"5e7b9f160b6c005b0e76f085",
|
||||
"Objects A"
|
||||
],
|
||||
[
|
||||
"5e7b9f160b6c005b0e76f086",
|
||||
"Objects B"
|
||||
],
|
||||
[
|
||||
"5e7b9f170b6c005b0e76f087",
|
||||
"Objects C"
|
||||
],
|
||||
[
|
||||
"5e7b9f170b6c005b0e76f088",
|
||||
"Objects D"
|
||||
],
|
||||
[
|
||||
"5e7b9f170b6c005b0e76f08a",
|
||||
"Databases A"
|
||||
],
|
||||
[
|
||||
"5e7b9f170b6c005b0e76f08b",
|
||||
"Databases B"
|
||||
],
|
||||
[
|
||||
"5e7b9f180b6c005b0e76f08c",
|
||||
"Databases C"
|
||||
],
|
||||
[
|
||||
"5e7b9f180b6c005b0e76f08d",
|
||||
"Databases D"
|
||||
],
|
||||
[
|
||||
"5e7b9f180b6c005b0e76f08e",
|
||||
"Databases E"
|
||||
],
|
||||
[
|
||||
"5e7b9f180b6c005b0e76f08f",
|
||||
"Databases F"
|
||||
],
|
||||
[
|
||||
"5e7b9f190b6c005b0e76f090",
|
||||
"Databases G"
|
||||
],
|
||||
[
|
||||
"5e7b9f690b6c005b0e76f095",
|
||||
"Viz A"
|
||||
],
|
||||
[
|
||||
"5e7b9f6a0b6c005b0e76f096",
|
||||
"Viz B"
|
||||
],
|
||||
[
|
||||
"5e7b9f6a0b6c005b0e76f097",
|
||||
"Viz C"
|
||||
],
|
||||
[
|
||||
"5e7b9f6a0b6c005b0e76f098",
|
||||
"Viz Geodata"
|
||||
],
|
||||
[
|
||||
"5e7b9f6a0b6c005b0e76f099",
|
||||
"Viz Gmane Model"
|
||||
],
|
||||
[
|
||||
"5e7b9f6b0b6c005b0e76f09a",
|
||||
"Viz Gmane Spider"
|
||||
],
|
||||
[
|
||||
"5e7b9f6b0b6c005b0e76f09b",
|
||||
"Viz Gmane Viz"
|
||||
],
|
||||
[
|
||||
"5e7b9f6b0b6c005b0e76f09c",
|
||||
"Viz Page Rank"
|
||||
],
|
||||
[
|
||||
"5e7b9f6b0b6c005b0e76f09d",
|
||||
"Viz Page Spider"
|
||||
],
|
||||
[
|
||||
"5e7b9f6c0b6c005b0e76f09e",
|
||||
"Viz Page Viz"
|
||||
]
|
||||
]
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "certificates",
|
||||
"superOrder": 11,
|
||||
"superOrder": 12,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"660add10cb82ac38a17513be",
|
||||
@ -14,5 +14,5 @@
|
||||
]
|
||||
],
|
||||
"isPrivate": true,
|
||||
"fileName": "11-certificates/legacy-back-end-certificate.json"
|
||||
"fileName": "12-certificates/legacy-back-end-certificate.json"
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "certificates",
|
||||
"superOrder": 11,
|
||||
"superOrder": 12,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"561add10cb82ac39a17513bc",
|
||||
@ -14,5 +14,5 @@
|
||||
]
|
||||
],
|
||||
"isPrivate": true,
|
||||
"fileName": "11-certificates/legacy-data-visualization-certificate.json"
|
||||
"fileName": "12-certificates/legacy-data-visualization-certificate.json"
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "certificates",
|
||||
"superOrder": 11,
|
||||
"superOrder": 12,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"561add10cb82ac38a17513be",
|
||||
@ -14,5 +14,5 @@
|
||||
]
|
||||
],
|
||||
"isPrivate": true,
|
||||
"fileName": "11-certificates/legacy-front-end-certificate.json"
|
||||
"fileName": "12-certificates/legacy-front-end-certificate.json"
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "Machine Learning with Python Certificate",
|
||||
"dashedName": "machine-learning-with-python-certificate",
|
||||
"order": 9,
|
||||
"order": 10,
|
||||
"time": "",
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "certificates",
|
||||
"superOrder": 11,
|
||||
"superOrder": 12,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"5e46fc95ac417301a38fb935",
|
||||
@ -14,5 +14,5 @@
|
||||
]
|
||||
],
|
||||
"isPrivate": true,
|
||||
"fileName": "11-certificates/machine-learning-with-python-certificate.json"
|
||||
"fileName": "12-certificates/machine-learning-with-python-certificate.json"
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
"order": 1,
|
||||
"time": "150 hours",
|
||||
"superBlock": "machine-learning-with-python",
|
||||
"superOrder": 9,
|
||||
"superOrder": 10,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"5e46f8d6ac417301a38fb92d",
|
||||
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "coding-interview-prep",
|
||||
"superOrder": 10,
|
||||
"superOrder": 11,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"5900f36e1000cf542c50fe80",
|
||||
|
@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "Quality Assurance and Testing with Chai",
|
||||
"dashedName": "quality-assurance-and-testing-with-chai",
|
||||
"order": 2,
|
||||
"order": 1,
|
||||
"time": "5 hours",
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "information-security-and-quality-assurance",
|
||||
"superBlock": "quality-assurance",
|
||||
"superOrder": 6,
|
||||
"challengeOrder": [
|
||||
[
|
||||
@ -106,5 +106,5 @@
|
||||
]
|
||||
],
|
||||
"helpRoom": "Help",
|
||||
"fileName": "06-information-security-and-quality-assurance/testing-with-chai.json"
|
||||
"fileName": "06-quality-assurance/quality-assurance-and-testing-with-chai.json"
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "Quality Assurance Certificate",
|
||||
"dashedName": "quality-assurance-certificate",
|
||||
"order": 6,
|
||||
"time": "",
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "certificates",
|
||||
"superOrder": 12,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"5e611829481575a52dc59c0e",
|
||||
"Quality Assurance Certificate"
|
||||
]
|
||||
],
|
||||
"isPrivate": true,
|
||||
"fileName": "12-certificates/quality-assurance-certificate.json"
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "Quality Assurance Projects",
|
||||
"dashedName": "quality-assurance-projects",
|
||||
"order": 3,
|
||||
"time": "150 hours",
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "quality-assurance",
|
||||
"superOrder": 6,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"587d8249367417b2b2512c41",
|
||||
"Metric-Imperial Converter"
|
||||
],
|
||||
[
|
||||
"587d8249367417b2b2512c42",
|
||||
"Issue Tracker"
|
||||
],
|
||||
[
|
||||
"587d824a367417b2b2512c43",
|
||||
"Personal Library"
|
||||
],
|
||||
[
|
||||
"5e601bf95ac9d0ecd8b94afd",
|
||||
"Sudoku Solver"
|
||||
],
|
||||
[
|
||||
"5e601c0d5ac9d0ecd8b94afe",
|
||||
"American British Translator"
|
||||
]
|
||||
],
|
||||
"helpRoom": "HelpBackend",
|
||||
"fileName": "06-quality-assurance/quality-assurance-projects.json"
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "certificates",
|
||||
"superOrder": 11,
|
||||
"superOrder": 12,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"561add10cb82ac38a17513bc",
|
||||
@ -14,5 +14,5 @@
|
||||
]
|
||||
],
|
||||
"isPrivate": true,
|
||||
"fileName": "11-certificates/responsive-web-design-certificate.json"
|
||||
"fileName": "12-certificates/responsive-web-design-certificate.json"
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "coding-interview-prep",
|
||||
"superOrder": 10,
|
||||
"superOrder": 11,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"594810f028c0303b75339acb",
|
||||
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "certificates",
|
||||
"superOrder": 11,
|
||||
"superOrder": 12,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"5e44431b903586ffb414c951",
|
||||
@ -14,5 +14,5 @@
|
||||
]
|
||||
],
|
||||
"isPrivate": true,
|
||||
"fileName": "11-certificates/scientific-computing-with-python-certificate.json"
|
||||
"fileName": "12-certificates/scientific-computing-with-python-certificate.json"
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Scientific Computing with Python Projects",
|
||||
"dashedName": "scientific-computing-with-python-projects",
|
||||
"order": 1,
|
||||
"order": 2,
|
||||
"time": "150 hours",
|
||||
"superBlock": "scientific-computing-with-python",
|
||||
"superOrder": 7,
|
||||
|
@ -6,7 +6,7 @@
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "coding-interview-prep",
|
||||
"superOrder": 10,
|
||||
"superOrder": 11,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"bd7158d8c442eddfaeb5bd10",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user