From d3f59e6d5de17250746938c02c052b89e5cf90b0 Mon Sep 17 00:00:00 2001 From: Shaun Hamilton <51722130+ShaunSHamilton@users.noreply.github.com> Date: Fri, 23 Apr 2021 20:29:17 +0100 Subject: [PATCH] fix(dev): rename superBlock with v7 to certSlug (#41738) * fix(dev): rename superBlock with v7 to slug * improve name slug -> certSlug * superBlockTitle -> superBlock * correct teeny, tiny mistake * fix: correct slug to certSlug in certLocation * refactor currentCerts * rename showCert cert -> certSlug and various --- api-server/src/server/boot/certificate.js | 22 +- client/gatsby-node.js | 1 + .../client-only-routes/ShowCertification.js | 46 ++-- .../client-only-routes/ShowProjectLinks.js | 4 +- .../profile/components/Certifications.js | 15 +- .../src/components/settings/Certification.js | 48 ++--- client/src/pages/certification.js | 2 +- client/src/redux/index.js | 30 +-- client/src/redux/propTypes.js | 8 + client/src/redux/show-cert-saga.js | 4 +- client/src/resources/certAndProjectMap.js | 200 +++++++++--------- .../templates/Introduction/SuperBlockIntro.js | 26 ++- .../Introduction/components/Block.js | 12 +- .../Introduction/components/CertChallenge.js | 55 ++--- client/src/utils/ajax.js | 8 +- config/certification-settings.js | 24 ++- 16 files changed, 251 insertions(+), 254 deletions(-) diff --git a/api-server/src/server/boot/certificate.js b/api-server/src/server/boot/certificate.js index 48e5bac58c..1557ea923c 100644 --- a/api-server/src/server/boot/certificate.js +++ b/api-server/src/server/boot/certificate.js @@ -15,7 +15,7 @@ import { getChallenges } from '../utils/get-curriculum'; import { completionHours, certTypes, - superBlockCertTypeMap, + certSlugTypeMap, certTypeTitleMap, certTypeIdMap, certIds, @@ -51,7 +51,7 @@ export default function bootCertificate(app) { const verifyCert = createVerifyCert(certTypeIds, app); api.put('/certificate/verify', ifNoUser401, ifNoSuperBlock404, verifyCert); - api.get('/certificate/showCert/:username/:cert', showCert); + api.get('/certificate/showCert/:username/:certSlug', showCert); app.use(api); } @@ -66,9 +66,11 @@ export function getFallbackFrontEndDate(completedChallenges, completedDate) { return latestCertDate ? latestCertDate : completedDate; } +const certSlugs = Object.keys(certSlugTypeMap); + function ifNoSuperBlock404(req, res, next) { - const { superBlock } = req.body; - if (superBlock && superBlocks.includes(superBlock)) { + const { certSlug } = req.body; + if (certSlug && certSlugs.includes(certSlug)) { return next(); } return res.status(404).end(); @@ -130,8 +132,6 @@ function getCertById(anId, allChallenges) { }))[0]; } -const superBlocks = Object.keys(superBlockCertTypeMap); - function sendCertifiedEmail( { email = '', @@ -223,11 +223,11 @@ function createVerifyCert(certTypeIds, app) { const { Email } = app.models; return function verifyCert(req, res, next) { const { - body: { superBlock }, + body: { certSlug }, user } = req; - log(superBlock); - let certType = superBlockCertTypeMap[superBlock]; + log(certSlug); + let certType = certSlugTypeMap[certSlug]; log(certType); return Observable.of(certTypeIds[certType]) .flatMap(challenge => { @@ -335,9 +335,9 @@ function createShowCert(app) { } return function showCert(req, res, next) { - let { username, cert } = req.params; + let { username, certSlug } = req.params; username = username.toLowerCase(); - const certType = superBlockCertTypeMap[cert]; + const certType = certSlugTypeMap[certSlug]; const certId = certTypeIdMap[certType]; const certTitle = certTypeTitleMap[certType]; const completionTime = completionHours[certType] || 300; diff --git a/client/gatsby-node.js b/client/gatsby-node.js index f6cf66bf89..133a2a1b1f 100644 --- a/client/gatsby-node.js +++ b/client/gatsby-node.js @@ -132,6 +132,7 @@ exports.createPages = function createPages({ graphql, actions, reporter }) { ); // Create intro pages + // TODO: Remove allMarkdownRemark (populate from elsewhere) result.data.allMarkdownRemark.edges.forEach(edge => { const { node: { frontmatter, fields } diff --git a/client/src/client-only-routes/ShowCertification.js b/client/src/client-only-routes/ShowCertification.js index 56de02be4f..54342fa76f 100644 --- a/client/src/client-only-routes/ShowCertification.js +++ b/client/src/client-only-routes/ShowCertification.js @@ -33,6 +33,7 @@ import envData from '../../../config/env.json'; import RedirectHome from '../components/RedirectHome'; import { Loader, Spacer } from '../components/helpers'; import { isEmpty } from 'lodash'; +import { User } from '../redux/propTypes'; const { clientLocale } = envData; @@ -48,7 +49,7 @@ const propTypes = { date: PropTypes.number }), certDashedName: PropTypes.string, - certName: PropTypes.string, + certSlug: PropTypes.string, createFlashMessage: PropTypes.func.isRequired, executeGA: PropTypes.func, fetchProfileForUser: PropTypes.func, @@ -58,48 +59,27 @@ const propTypes = { errored: PropTypes.bool }), isDonating: PropTypes.bool, + isValidCert: PropTypes.bool, location: PropTypes.shape({ pathname: PropTypes.string }), showCert: PropTypes.func.isRequired, signedInUserName: PropTypes.string, - user: PropTypes.shape({ - completedChallenges: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string, - solution: PropTypes.string, - githubLink: PropTypes.string, - files: PropTypes.arrayOf( - PropTypes.shape({ - contents: PropTypes.string, - ext: PropTypes.string, - key: PropTypes.string, - name: PropTypes.string, - path: PropTypes.string - }) - ) - }) - ), - profileUI: PropTypes.shape({ - showName: PropTypes.bool - }), - username: PropTypes.string - }), + user: User, userFetchState: PropTypes.shape({ complete: PropTypes.bool }), userFullName: PropTypes.string, - username: PropTypes.string, - validCertName: PropTypes.bool + username: PropTypes.string }; const requestedUserSelector = (state, { username = '' }) => userByNameSelector(username.toLowerCase())(state); -const validCertNames = certMap.map(cert => cert.slug); +const validCertSlugs = certMap.map(cert => cert.certSlug); const mapStateToProps = (state, props) => { - const validCertName = validCertNames.some(name => name === props.certName); + const isValidCert = validCertSlugs.some(slug => slug === props.certSlug); return createSelector( showCertSelector, showCertFetchStateSelector, @@ -110,7 +90,7 @@ const mapStateToProps = (state, props) => { (cert, fetchState, signedInUserName, userFetchState, isDonating, user) => ({ cert, fetchState, - validCertName, + isValidCert, signedInUserName, userFetchState, isDonating, @@ -132,9 +112,9 @@ const ShowCertification = props => { const [isDonationClosed, setIsDonationClosed] = useState(false); useEffect(() => { - const { username, certName, validCertName, showCert } = props; - if (validCertName) { - showCert({ username, certName }); + const { username, certSlug, isValidCert, showCert } = props; + if (isValidCert) { + showCert({ username, certSlug }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -208,13 +188,13 @@ const ShowCertification = props => { const { cert, fetchState, - validCertName, + isValidCert, createFlashMessage, signedInUserName, location: { pathname } } = props; - if (!validCertName) { + if (!isValidCert) { createFlashMessage(standardErrorMessage); return ; } diff --git a/client/src/client-only-routes/ShowProjectLinks.js b/client/src/client-only-routes/ShowProjectLinks.js index 7da7dc1248..783cea9666 100644 --- a/client/src/client-only-routes/ShowProjectLinks.js +++ b/client/src/client-only-routes/ShowProjectLinks.js @@ -125,8 +125,8 @@ const ShowProjectLinks = props => { ]; return legacyCerts.map((cert, ind) => { const mapToUse = projectMap[cert.title] || legacyProjectMap[cert.title]; - const { superBlock } = first(mapToUse); - const certLocation = `/certification/${username}/${superBlock}`; + const { certSlug } = first(mapToUse); + const certLocation = `/certification/${username}/${certSlug}`; return (
  • createSelector( @@ -21,19 +22,11 @@ const mapStateToProps = (state, props) => }) )(state, props); -const certArrayTypes = PropTypes.arrayOf( - PropTypes.shape({ - show: PropTypes.bool, - title: PropTypes.string, - showURL: PropTypes.string - }) -); - const propTypes = { - currentCerts: certArrayTypes, + currentCerts: CurrentCertsType, hasLegacyCert: PropTypes.bool, hasModernCert: PropTypes.bool, - legacyCerts: certArrayTypes, + legacyCerts: CurrentCertsType, username: PropTypes.string }; @@ -45,7 +38,7 @@ function renderCertShow(username, cert) { View {cert.title} diff --git a/client/src/components/settings/Certification.js b/client/src/components/settings/Certification.js index e1f2bf57c5..d4fa6f0cef 100644 --- a/client/src/components/settings/Certification.js +++ b/client/src/components/settings/Certification.js @@ -289,15 +289,15 @@ export class CertificationSettings extends Component { t, verifyCert } = this.props; - const { superBlock } = first(projectMap[certName]); - const certLocation = `/certification/${username}/${superBlock}`; - const createClickHandler = superBlock => e => { + const { certSlug } = first(projectMap[certName]); + const certLocation = `/certification/${username}/${certSlug}`; + const createClickHandler = certSlug => e => { e.preventDefault(); if (isCert) { return navigate(certLocation); } return isHonest - ? verifyCert(superBlock) + ? verifyCert(certSlug) : createFlashMessage(honestyInfoMessage); }; return projectMap[certName] @@ -312,13 +312,13 @@ export class CertificationSettings extends Component { )) .concat([ - + @@ -336,13 +336,13 @@ export class CertificationSettings extends Component { updateLegacyCert } = this.props; let legacyTitle; - let superBlock; + let certSlug; let certs = Object.keys(legacyProjectMap); let loopBreak = false; for (let certTitle of certs) { for (let chalTitle of legacyProjectMap[certTitle]) { if (chalTitle.title === Object.keys(formChalObj)[0]) { - superBlock = chalTitle.superBlock; + certSlug = chalTitle.certSlug; loopBreak = true; legacyTitle = certTitle; break; @@ -392,16 +392,16 @@ export class CertificationSettings extends Component { if (isProjectSectionComplete) { return isHonest - ? verifyCert(superBlock) + ? verifyCert(certSlug) : createFlashMessage(honestyInfoMessage); } - return updateLegacyCert({ challengesToUpdate, superBlock }); + return updateLegacyCert({ challengesToUpdate, certSlug }); } renderLegacyCertifications = certName => { const { username, createFlashMessage, completedChallenges, t } = this.props; - const { superBlock } = first(legacyProjectMap[certName]); - const certLocation = `/certification/${username}/${superBlock}`; + const { certSlug } = first(legacyProjectMap[certName]); + const certLocation = `/certification/${username}/${certSlug}`; const challengeTitles = legacyProjectMap[certName].map(item => item.title); const isCertClaimed = this.getUserIsCertMap()[certName]; const initialObject = {}; @@ -446,7 +446,7 @@ export class CertificationSettings extends Component { }; return ( - +

    {certName}

    e => { + const createClickHandler = certSlug => e => { e.preventDefault(); if (isFullStackCert) { return navigate(certLocation); } return isHonest - ? verifyCert(superBlock) + ? verifyCert(certSlug) : createFlashMessage(honestyInfoMessage); }; return ( - +

    Legacy Full Stack Certification

    @@ -554,8 +554,8 @@ export class CertificationSettings extends Component { bsStyle='primary' className={'col-xs-12'} href={certLocation} - id={'button-' + superBlock} - onClick={createClickHandler(superBlock)} + id={'button-' + certSlug} + onClick={createClickHandler(certSlug)} style={buttonStyle} target='_blank' > @@ -569,7 +569,7 @@ export class CertificationSettings extends Component { bsStyle='primary' className={'col-xs-12'} disabled={true} - id={'button-' + superBlock} + id={'button-' + certSlug} style={buttonStyle} target='_blank' > diff --git a/client/src/pages/certification.js b/client/src/pages/certification.js index aa5e62c59b..236a42ee13 100644 --- a/client/src/pages/certification.js +++ b/client/src/pages/certification.js @@ -12,7 +12,7 @@ class Certification extends Component { return ( diff --git a/client/src/redux/index.js b/client/src/redux/index.js index 76d88ac205..a2aefef204 100644 --- a/client/src/redux/index.js +++ b/client/src/redux/index.js @@ -266,81 +266,81 @@ export const certificatesByNameSelector = username => state => { { show: isRespWebDesignCert, title: 'Responsive Web Design Certification', - showURL: 'responsive-web-design' + certSlug: 'responsive-web-design' }, { show: isJsAlgoDataStructCert, title: 'JavaScript Algorithms and Data Structures Certification', - showURL: 'javascript-algorithms-and-data-structures' + certSlug: 'javascript-algorithms-and-data-structures' }, { show: isFrontEndLibsCert, title: 'Front End Libraries Certification', - showURL: 'front-end-libraries' + certSlug: 'front-end-libraries' }, { show: is2018DataVisCert, title: 'Data Visualization Certification', - showURL: 'data-visualization' + certSlug: 'data-visualization' }, { show: isApisMicroservicesCert, title: 'APIs and Microservices Certification', - showURL: 'apis-and-microservices' + certSlug: 'apis-and-microservices' }, { show: isQaCertV7, title: ' Quality Assurance Certification', - showURL: 'quality-assurance-v7' + certSlug: 'quality-assurance-v7' }, { show: isInfosecCertV7, title: 'Information Security Certification', - showURL: 'information-security-v7' + certSlug: 'information-security-v7' }, { show: isSciCompPyCertV7, title: 'Scientific Computing with Python Certification', - showURL: 'scientific-computing-with-python-v7' + certSlug: 'scientific-computing-with-python-v7' }, { show: isDataAnalysisPyCertV7, title: 'Data Analysis with Python Certification', - showURL: 'data-analysis-with-python-v7' + certSlug: 'data-analysis-with-python-v7' }, { show: isMachineLearningPyCertV7, title: 'Machine Learning with Python Certification', - showURL: 'machine-learning-with-python-v7' + certSlug: 'machine-learning-with-python-v7' } ], legacyCerts: [ { show: isFrontEndCert, title: 'Front End Certification', - showURL: 'legacy-front-end' + certSlug: 'legacy-front-end' }, { show: isBackEndCert, title: 'Back End Certification', - showURL: 'legacy-back-end' + certSlug: 'legacy-back-end' }, { show: isDataVisCert, title: 'Data Visualization Certification', - showURL: 'legacy-data-visualization' + certSlug: 'legacy-data-visualization' }, { show: isInfosecQaCert, title: 'Information Security and Quality Assurance Certification', // Keep the current public profile cert slug - showURL: 'information-security-and-quality-assurance' + certSlug: 'information-security-and-quality-assurance' }, { show: isFullStackCert, title: 'Full Stack Certification', // Keep the current public profile cert slug - showURL: 'full-stack' + certSlug: 'full-stack' } ] }; diff --git a/client/src/redux/propTypes.js b/client/src/redux/propTypes.js index 66317e2ed2..79797deb34 100644 --- a/client/src/redux/propTypes.js +++ b/client/src/redux/propTypes.js @@ -124,3 +124,11 @@ export const User = PropTypes.shape({ username: PropTypes.string, website: PropTypes.string }); + +export const CurrentCertsType = PropTypes.arrayOf( + PropTypes.shape({ + show: PropTypes.bool, + title: PropTypes.string, + certSlug: PropTypes.string + }) +); diff --git a/client/src/redux/show-cert-saga.js b/client/src/redux/show-cert-saga.js index 2512377ca1..4358ce5c7a 100644 --- a/client/src/redux/show-cert-saga.js +++ b/client/src/redux/show-cert-saga.js @@ -5,9 +5,9 @@ import { createFlashMessage } from '../components/Flash/redux'; import { getShowCert } from '../utils/ajax'; import { showCertComplete, showCertError } from '.'; -function* getShowCertSaga({ payload: { username, certName: cert } }) { +function* getShowCertSaga({ payload: { username, certSlug } }) { try { - const { data: response } = yield call(getShowCert, username, cert); + const { data: response } = yield call(getShowCert, username, certSlug); const { messages } = response; if (messages && messages.length) { for (let i = 0; i < messages.length; i++) { diff --git a/client/src/resources/certAndProjectMap.js b/client/src/resources/certAndProjectMap.js index 44ad791ee0..b22cb380c4 100644 --- a/client/src/resources/certAndProjectMap.js +++ b/client/src/resources/certAndProjectMap.js @@ -27,143 +27,143 @@ const certMap = [ { id: '561add10cb82ac38a17513be', title: 'Legacy Front End', - slug: 'legacy-front-end', + certSlug: 'legacy-front-end', flag: 'isFrontEndCert', projects: [ { id: 'bd7158d8c242eddfaeb5bd13', title: 'Build a Personal Portfolio Webpage', link: `${legacyFrontEndBase}/build-a-personal-portfolio-webpage`, - superBlock: 'legacy-front-end' + certSlug: 'legacy-front-end' }, { id: 'bd7158d8c442eddfaeb5bd13', title: 'Build a Random Quote Machine', link: `${legacyFrontEndBase}/build-a-random-quote-machine`, - superBlock: 'legacy-front-end' + certSlug: 'legacy-front-end' }, { id: 'bd7158d8c442eddfaeb5bd0f', title: 'Build a 25 + 5 Clock', link: `${legacyFrontEndBase}/build-a-25--5-clock`, - superBlock: 'legacy-front-end' + certSlug: 'legacy-front-end' }, { id: 'bd7158d8c442eddfaeb5bd17', title: 'Build a JavaScript Calculator', link: `${legacyFrontEndBase}/build-a-javascript-calculator`, - superBlock: 'legacy-front-end' + certSlug: 'legacy-front-end' }, { id: 'bd7158d8c442eddfaeb5bd10', title: 'Show the Local Weather', link: `${legacyFrontEndBase}/show-the-local-weather`, - superBlock: 'legacy-front-end' + certSlug: 'legacy-front-end' }, { id: 'bd7158d8c442eddfaeb5bd1f', title: 'Use the TwitchTV JSON API', link: `${legacyFrontEndBase}/use-the-twitchtv-json-api`, - superBlock: 'legacy-front-end' + certSlug: 'legacy-front-end' }, { id: 'bd7158d8c442eddfaeb5bd18', title: 'Stylize Stories on Camper News', link: `${legacyFrontEndBase}/stylize-stories-on-camper-news`, - superBlock: 'legacy-front-end' + certSlug: 'legacy-front-end' }, { id: 'bd7158d8c442eddfaeb5bd19', title: 'Build a Wikipedia Viewer', link: `${legacyFrontEndBase}/build-a-wikipedia-viewer`, - superBlock: 'legacy-front-end' + certSlug: 'legacy-front-end' }, { id: 'bd7158d8c442eedfaeb5bd1c', title: 'Build a Tic Tac Toe Game', link: `${legacyFrontEndBase}/build-a-tic-tac-toe-game`, - superBlock: 'legacy-front-end' + certSlug: 'legacy-front-end' }, { id: 'bd7158d8c442eddfaeb5bd1c', title: 'Build a Simon Game', link: `${legacyFrontEndBase}/build-a-simon-game`, - superBlock: 'legacy-front-end' + certSlug: 'legacy-front-end' } ] }, { id: '660add10cb82ac38a17513be', title: 'Legacy Back End', - slug: 'legacy-back-end', + certSlug: 'legacy-back-end', flag: 'isBackEndCert', projects: [ { id: 'bd7158d8c443edefaeb5bdef', title: 'Timestamp Microservice', link: `${legacyBackEndBase}/timestamp-microservice`, - superBlock: 'legacy-back-end' + certSlug: 'legacy-back-end' }, { id: 'bd7158d8c443edefaeb5bdff', title: 'Request Header Parser Microservice', link: `${legacyBackEndBase}/request-header-parser-microservice`, - superBlock: 'legacy-back-end' + certSlug: 'legacy-back-end' }, { id: 'bd7158d8c443edefaeb5bd0e', title: 'URL Shortener Microservice', link: `${legacyBackEndBase}/url-shortener-microservice`, - superBlock: 'legacy-back-end' + certSlug: 'legacy-back-end' }, { id: 'bd7158d8c443edefaeb5bdee', title: 'Image Search Abstraction Layer', link: `${legacyBackEndBase}/image-search-abstraction-layer`, - superBlock: 'legacy-back-end' + certSlug: 'legacy-back-end' }, { id: 'bd7158d8c443edefaeb5bd0f', title: 'File Metadata Microservice', link: `${legacyBackEndBase}/file-metadata-microservice`, - superBlock: 'legacy-back-end' + certSlug: 'legacy-back-end' }, { id: 'bd7158d8c443eddfaeb5bdef', title: 'Build a Voting App', link: `${legacyBackEndBase}/build-a-voting-app`, - superBlock: 'legacy-back-end' + certSlug: 'legacy-back-end' }, { id: 'bd7158d8c443eddfaeb5bdff', title: 'Build a Nightlife Coordination App', link: `${legacyBackEndBase}/build-a-nightlife-coordination-app`, - superBlock: 'legacy-back-end' + certSlug: 'legacy-back-end' }, { id: 'bd7158d8c443eddfaeb5bd0e', title: 'Chart the Stock Market', link: `${legacyBackEndBase}/chart-the-stock-market`, - superBlock: 'legacy-back-end' + certSlug: 'legacy-back-end' }, { id: 'bd7158d8c443eddfaeb5bd0f', title: 'Manage a Book Trading Club', link: `${legacyBackEndBase}/manage-a-book-trading-club`, - superBlock: 'legacy-back-end' + certSlug: 'legacy-back-end' }, { id: 'bd7158d8c443eddfaeb5bdee', title: 'Build a Pinterest Clone', link: `${legacyBackEndBase}/build-a-pinterest-clone`, - superBlock: 'legacy-back-end' + certSlug: 'legacy-back-end' } ] }, { id: '561add10cb82ac38a17213bd', title: 'Legacy Full Stack', - slug: 'full-stack', + certSlug: 'full-stack', flag: 'isFullStackCert' // Requirements are other certs and is // handled elsewhere @@ -171,68 +171,68 @@ const certMap = [ { id: '561add10cb82ac39a17513bc', title: 'Legacy Data Visualization', - slug: 'legacy-data-visualization', + certSlug: 'legacy-data-visualization', flag: 'isDataVisCert', projects: [ { id: 'bd7157d8c242eddfaeb5bd13', title: 'Build a Markdown Previewer', link: `${legacyDataVisBase}/build-a-markdown-previewer`, - superBlock: 'legacy-data-visualization' + certSlug: 'legacy-data-visualization' }, { id: 'bd7156d8c242eddfaeb5bd13', title: 'Build a Camper Leaderboard', link: `${legacyDataVisBase}/build-a-camper-leaderboard`, - superBlock: 'legacy-data-visualization' + certSlug: 'legacy-data-visualization' }, { id: 'bd7155d8c242eddfaeb5bd13', title: 'Build a Recipe Box', link: `${legacyDataVisBase}/build-a-recipe-box`, - superBlock: 'legacy-data-visualization' + certSlug: 'legacy-data-visualization' }, { id: 'bd7154d8c242eddfaeb5bd13', title: 'Build the Game of Life', link: `${legacyDataVisBase}/build-the-game-of-life`, - superBlock: 'legacy-data-visualization' + certSlug: 'legacy-data-visualization' }, { id: 'bd7153d8c242eddfaeb5bd13', title: 'Build a Roguelike Dungeon Crawler Game', link: `${legacyDataVisBase}/build-a-roguelike-dungeon-crawler-game`, - superBlock: 'legacy-data-visualization' + certSlug: 'legacy-data-visualization' }, { id: 'bd7168d8c242eddfaeb5bd13', title: 'Visualize Data with a Bar Chart', link: `${legacyDataVisBase}/visualize-data-with-a-bar-chart`, - superBlock: 'legacy-data-visualization' + certSlug: 'legacy-data-visualization' }, { id: 'bd7178d8c242eddfaeb5bd13', title: 'Visualize Data with a Scatterplot Graph', link: `${legacyDataVisBase}/visualize-data-with-a-scatterplot-graph`, - superBlock: 'legacy-data-visualization' + certSlug: 'legacy-data-visualization' }, { id: 'bd7188d8c242eddfaeb5bd13', title: 'Visualize Data with a Heat Map', link: `${legacyDataVisBase}/visualize-data-with-a-heat-map`, - superBlock: 'legacy-data-visualization' + certSlug: 'legacy-data-visualization' }, { id: 'bd7198d8c242eddfaeb5bd13', title: 'Show National Contiguity with a Force Directed Graph', link: `${legacyDataVisBase}/show-national-contiguity-with-a-force-directed-graph`, - superBlock: 'legacy-data-visualization' + certSlug: 'legacy-data-visualization' }, { id: 'bd7108d8c242eddfaeb5bd13', title: 'Map Data Across the Globe', link: `${legacyDataVisBase}/map-data-across-the-globe`, - superBlock: 'legacy-data-visualization' + certSlug: 'legacy-data-visualization' } ] }, @@ -240,7 +240,7 @@ const certMap = [ id: '561add10cb82ac38a17213bc', title: 'Legacy Information Security and Quality Assurance', // Keep this as information-security-and-quality-assurance - slug: 'information-security-and-quality-assurance', + certSlug: 'information-security-and-quality-assurance', flag: 'isInfosecQaCert', projects: [ // Keep this as information-security-and-quality-assurance @@ -248,335 +248,335 @@ const certMap = [ id: '587d8249367417b2b2512c41', title: 'Metric-Imperial Converter', link: `${legacyInfosecQaBase}/metric-imperial-converter`, - superBlock: 'information-security-and-quality-assurance' + certSlug: 'information-security-and-quality-assurance' }, { id: '587d8249367417b2b2512c42', title: 'Issue Tracker', link: `${legacyInfosecQaBase}/issue-tracker`, - superBlock: 'information-security-and-quality-assurance' + certSlug: 'information-security-and-quality-assurance' }, { id: '587d824a367417b2b2512c43', title: 'Personal Library', link: `${legacyInfosecQaBase}/personal-library`, - superBlock: 'information-security-and-quality-assurance' + certSlug: 'information-security-and-quality-assurance' }, { id: '587d824a367417b2b2512c44', title: 'Stock Price Checker', link: `${legacyInfosecQaBase}/stock-price-checker`, - superBlock: 'information-security-and-quality-assurance' + certSlug: 'information-security-and-quality-assurance' }, { id: '587d824a367417b2b2512c45', title: 'Anonymous Message Board', link: `${legacyInfosecQaBase}/anonymous-message-board`, - superBlock: 'information-security-and-quality-assurance' + certSlug: 'information-security-and-quality-assurance' } ] }, { id: '561add10cb82ac38a17513bc', title: 'Responsive Web Design', - slug: 'responsive-web-design', + certSlug: 'responsive-web-design', flag: 'isRespWebDesignCert', projects: [ { id: 'bd7158d8c442eddfaeb5bd18', title: 'Build a Tribute Page', link: `${responsiveWebBase}/build-a-tribute-page`, - superBlock: 'responsive-web-design' + certSlug: 'responsive-web-design' }, { id: '587d78af367417b2b2512b03', title: 'Build a Survey Form', link: `${responsiveWebBase}/build-a-survey-form`, - superBlock: 'responsive-web-design' + certSlug: 'responsive-web-design' }, { id: '587d78af367417b2b2512b04', title: 'Build a Product Landing Page', link: `${responsiveWebBase}/build-a-product-landing-page`, - superBlock: 'responsive-web-design' + certSlug: 'responsive-web-design' }, { id: '587d78b0367417b2b2512b05', title: 'Build a Technical Documentation Page', link: `${responsiveWebBase}/build-a-technical-documentation-page`, - superBlock: 'responsive-web-design' + certSlug: 'responsive-web-design' }, { id: 'bd7158d8c242eddfaeb5bd13', title: 'Build a Personal Portfolio Webpage', link: `${responsiveWebBase}/build-a-personal-portfolio-webpage`, - superBlock: 'responsive-web-design' + certSlug: 'responsive-web-design' } ] }, { id: '561abd10cb81ac38a17513bc', title: 'JavaScript Algorithms and Data Structures', - slug: 'javascript-algorithms-and-data-structures', + certSlug: 'javascript-algorithms-and-data-structures', flag: 'isJsAlgoDataStructCert', projects: [ { id: 'aaa48de84e1ecc7c742e1124', title: 'Palindrome Checker', link: `${jsAlgoBase}/palindrome-checker`, - superBlock: 'javascript-algorithms-and-data-structures' + certSlug: 'javascript-algorithms-and-data-structures' }, { id: 'a7f4d8f2483413a6ce226cac', title: 'Roman Numeral Converter', link: `${jsAlgoBase}/roman-numeral-converter`, - superBlock: 'javascript-algorithms-and-data-structures' + certSlug: 'javascript-algorithms-and-data-structures' }, { id: '56533eb9ac21ba0edf2244e2', title: 'Caesars Cipher', link: `${jsAlgoBase}/caesars-cipher`, - superBlock: 'javascript-algorithms-and-data-structures' + certSlug: 'javascript-algorithms-and-data-structures' }, { id: 'aff0395860f5d3034dc0bfc9', title: 'Telephone Number Validator', link: `${jsAlgoBase}/telephone-number-validator`, - superBlock: 'javascript-algorithms-and-data-structures' + certSlug: 'javascript-algorithms-and-data-structures' }, { id: 'aa2e6f85cab2ab736c9a9b24', title: 'Cash Register', link: `${jsAlgoBase}/cash-register`, - superBlock: 'javascript-algorithms-and-data-structures' + certSlug: 'javascript-algorithms-and-data-structures' } ] }, { id: '561acd10cb82ac38a17513bc', title: 'Front End Libraries', - slug: 'front-end-libraries', + certSlug: 'front-end-libraries', flag: 'isFrontEndLibsCert', projects: [ { id: 'bd7158d8c442eddfaeb5bd13', title: 'Build a Random Quote Machine', link: `${feLibsBase}/build-a-random-quote-machine`, - superBlock: 'front-end-libraries' + certSlug: 'front-end-libraries' }, { id: 'bd7157d8c242eddfaeb5bd13', title: 'Build a Markdown Previewer', link: `${feLibsBase}/build-a-markdown-previewer`, - superBlock: 'front-end-libraries' + certSlug: 'front-end-libraries' }, { id: '587d7dbc367417b2b2512bae', title: 'Build a Drum Machine', link: `${feLibsBase}/build-a-drum-machine`, - superBlock: 'front-end-libraries' + certSlug: 'front-end-libraries' }, { id: 'bd7158d8c442eddfaeb5bd17', title: 'Build a JavaScript Calculator', link: `${feLibsBase}/build-a-javascript-calculator`, - superBlock: 'front-end-libraries' + certSlug: 'front-end-libraries' }, { id: 'bd7158d8c442eddfaeb5bd0f', title: 'Build a 25 + 5 Clock', link: `${feLibsBase}/build-a-25--5-clock`, - superBlock: 'front-end-libraries' + certSlug: 'front-end-libraries' } ] }, { id: '5a553ca864b52e1d8bceea14', title: 'Data Visualization', - slug: 'data-visualization', + certSlug: 'data-visualization', flag: 'is2018DataVisCert', projects: [ { id: 'bd7168d8c242eddfaeb5bd13', title: 'Visualize Data with a Bar Chart', link: `${dataVisBase}/visualize-data-with-a-bar-chart`, - superBlock: 'data-visualization' + certSlug: 'data-visualization' }, { id: 'bd7178d8c242eddfaeb5bd13', title: 'Visualize Data with a Scatterplot Graph', link: `${dataVisBase}/visualize-data-with-a-scatterplot-graph`, - superBlock: 'data-visualization' + certSlug: 'data-visualization' }, { id: 'bd7188d8c242eddfaeb5bd13', title: 'Visualize Data with a Heat Map', link: `${dataVisBase}/visualize-data-with-a-heat-map`, - superBlock: 'data-visualization' + certSlug: 'data-visualization' }, { id: '587d7fa6367417b2b2512bbf', title: 'Visualize Data with a Choropleth Map', link: `${dataVisBase}/visualize-data-with-a-choropleth-map`, - superBlock: 'data-visualization' + certSlug: 'data-visualization' }, { id: '587d7fa6367417b2b2512bc0', title: 'Visualize Data with a Treemap Diagram', link: `${dataVisBase}/visualize-data-with-a-treemap-diagram`, - superBlock: 'data-visualization' + certSlug: 'data-visualization' } ] }, { id: '561add10cb82ac38a17523bc', title: 'APIs and Microservices', - slug: 'apis-and-microservices', + certSlug: 'apis-and-microservices', flag: 'isApisMicroservicesCert', projects: [ { id: 'bd7158d8c443edefaeb5bdef', title: 'Timestamp Microservice', link: `${apiMicroBase}/timestamp-microservice`, - superBlock: 'apis-and-microservices' + certSlug: 'apis-and-microservices' }, { id: 'bd7158d8c443edefaeb5bdff', title: 'Request Header Parser Microservice', link: `${apiMicroBase}/request-header-parser-microservice`, - superBlock: 'apis-and-microservices' + certSlug: 'apis-and-microservices' }, { id: 'bd7158d8c443edefaeb5bd0e', title: 'URL Shortener Microservice', link: `${apiMicroBase}/url-shortener-microservice`, - superBlock: 'apis-and-microservices' + certSlug: 'apis-and-microservices' }, { id: '5a8b073d06fa14fcfde687aa', title: 'Exercise Tracker', link: `${apiMicroBase}/exercise-tracker`, - superBlock: 'apis-and-microservices' + certSlug: 'apis-and-microservices' }, { id: 'bd7158d8c443edefaeb5bd0f', title: 'File Metadata Microservice', link: `${apiMicroBase}/file-metadata-microservice`, - superBlock: 'apis-and-microservices' + certSlug: 'apis-and-microservices' } ] }, { id: '5e611829481575a52dc59c0e', title: 'Quality Assurance', - slug: 'quality-assurance-v7', + certSlug: 'quality-assurance-v7', flag: 'isQaCertV7', projects: [ { id: '587d8249367417b2b2512c41', title: 'Metric-Imperial Converter', link: `${qaBase}/metric-imperial-converter`, - superBlock: 'quality-assurance-v7' + certSlug: 'quality-assurance-v7' }, { id: '587d8249367417b2b2512c42', title: 'Issue Tracker', link: `${qaBase}/issue-tracker`, - superBlock: 'quality-assurance-v7' + certSlug: 'quality-assurance-v7' }, { id: '587d824a367417b2b2512c43', title: 'Personal Library', link: `${qaBase}/personal-library`, - superBlock: 'quality-assurance-v7' + certSlug: 'quality-assurance-v7' }, { id: '5e601bf95ac9d0ecd8b94afd', title: 'Sudoku Solver', link: `${qaBase}/sudoku-solver`, - superBlock: 'quality-assurance-v7' + certSlug: 'quality-assurance-v7' }, { id: '5e601c0d5ac9d0ecd8b94afe', title: 'American British Translator', link: `${qaBase}/american-british-translator`, - superBlock: 'quality-assurance-v7' + certSlug: 'quality-assurance-v7' } ] }, { id: '5e44431b903586ffb414c951', title: 'Scientific Computing with Python', - slug: 'scientific-computing-with-python-v7', + certSlug: 'scientific-computing-with-python-v7', flag: 'isSciCompPyCertV7', projects: [ { id: '5e44412c903586ffb414c94c', title: 'Arithmetic Formatter', link: `${sciCompPyBase}/arithmetic-formatter`, - superBlock: 'scientific-computing-with-python-v7' + certSlug: 'scientific-computing-with-python-v7' }, { id: '5e444136903586ffb414c94d', title: 'Time Calculator', link: `${sciCompPyBase}/time-calculator`, - superBlock: 'scientific-computing-with-python-v7' + certSlug: 'scientific-computing-with-python-v7' }, { id: '5e44413e903586ffb414c94e', title: 'Budget App', link: `${sciCompPyBase}/budget-app`, - superBlock: 'scientific-computing-with-python-v7' + certSlug: 'scientific-computing-with-python-v7' }, { id: '5e444147903586ffb414c94f', title: 'Polygon Area Calculator', link: `${sciCompPyBase}/polygon-area-calculator`, - superBlock: 'scientific-computing-with-python-v7' + certSlug: 'scientific-computing-with-python-v7' }, { id: '5e44414f903586ffb414c950', title: 'Probability Calculator', link: `${sciCompPyBase}/probability-calculator`, - superBlock: 'scientific-computing-with-python-v7' + certSlug: 'scientific-computing-with-python-v7' } ] }, { id: '5e46fc95ac417301a38fb934', title: 'Data Analysis with Python', - slug: 'data-analysis-with-python-v7', + certSlug: 'data-analysis-with-python-v7', flag: 'isDataAnalysisPyCertV7', projects: [ { id: '5e46f7e5ac417301a38fb928', title: 'Mean-Variance-Standard Deviation Calculator', link: `${dataAnalysisPyBase}/mean-variance-standard-deviation-calculator`, - superBlock: 'data-analysis-with-python-v7' + certSlug: 'data-analysis-with-python-v7' }, { id: '5e46f7e5ac417301a38fb929', title: 'Demographic Data Analyzer', link: `${dataAnalysisPyBase}/demographic-data-analyzer`, - superBlock: 'data-analysis-with-python-v7' + certSlug: 'data-analysis-with-python-v7' }, { id: '5e46f7f8ac417301a38fb92a', title: 'Medical Data Visualizer', link: `${dataAnalysisPyBase}/medical-data-visualizer`, - superBlock: 'data-analysis-with-python-v7' + certSlug: 'data-analysis-with-python-v7' }, { id: '5e46f802ac417301a38fb92b', title: 'Page View Time Series Visualizer', link: `${dataAnalysisPyBase}/page-view-time-series-visualizer`, - superBlock: 'data-analysis-with-python-v7' + certSlug: 'data-analysis-with-python-v7' }, { id: '5e4f5c4b570f7e3a4949899f', title: 'Sea Level Predictor', link: `${dataAnalysisPyBase}/sea-level-predictor`, - superBlock: 'data-analysis-with-python-v7' + certSlug: 'data-analysis-with-python-v7' } ] }, @@ -584,76 +584,76 @@ const certMap = [ { id: '5e6021435ac9d0ecd8b94b00', title: 'Information Security', - slug: 'information-security-v7', + certSlug: 'information-security-v7', flag: 'isInfosecCertV7', projects: [ { id: '587d824a367417b2b2512c44', title: 'Stock Price Checker', link: `${infoSecBase}/stock-price-checker`, - superBlock: 'information-security-v7' + certSlug: 'information-security-v7' }, { id: '587d824a367417b2b2512c45', title: 'Anonymous Message Board', link: `${infoSecBase}/anonymous-message-board`, - superBlock: 'information-security-v7' + certSlug: 'information-security-v7' }, { id: '5e46f979ac417301a38fb932', title: 'Port Scanner', link: `${infoSecBase}/port-scanner`, - superBlock: 'information-security-v7' + certSlug: 'information-security-v7' }, { id: '5e46f983ac417301a38fb933', title: 'SHA-1 Password Cracker', link: `${infoSecBase}/sha-1-password-cracker`, - superBlock: 'information-security-v7' + certSlug: 'information-security-v7' }, { id: '5e601c775ac9d0ecd8b94aff', title: 'Secure Real Time Multiplayer Game', link: `${infoSecBase}/secure-real-time-multiplayer-game`, - superBlock: 'information-security-v7' + certSlug: 'information-security-v7' } ] }, { id: '5e46fc95ac417301a38fb935', title: 'Machine Learning with Python', - slug: 'machine-learning-with-python-v7', + certSlug: 'machine-learning-with-python-v7', flag: 'isMachineLearningPyCertV7', projects: [ { id: '5e46f8d6ac417301a38fb92d', title: 'Rock Paper Scissors', link: `${machineLearningPyBase}/rock-paper-scissors`, - superBlock: 'machine-learning-with-python-v7' + certSlug: 'machine-learning-with-python-v7' }, { id: '5e46f8dcac417301a38fb92e', title: 'Cat and Dog Image Classifier', link: `${machineLearningPyBase}/cat-and-dog-image-classifier`, - superBlock: 'machine-learning-with-python-v7' + certSlug: 'machine-learning-with-python-v7' }, { id: '5e46f8e3ac417301a38fb92f', title: 'Book Recommendation Engine using KNN', link: `${machineLearningPyBase}/book-recommendation-engine-using-knn`, - superBlock: 'machine-learning-with-python-v7' + certSlug: 'machine-learning-with-python-v7' }, { id: '5e46f8edac417301a38fb930', title: 'Linear Regression Health Costs Calculator', link: `${machineLearningPyBase}/linear-regression-health-costs-calculator`, - superBlock: 'machine-learning-with-python-v7' + certSlug: 'machine-learning-with-python-v7' }, { id: '5e46f8edac417301a38fb931', title: 'Neural Network SMS Text Classifier', link: `${machineLearningPyBase}/neural-network-sms-text-classifier`, - superBlock: 'machine-learning-with-python-v7' + certSlug: 'machine-learning-with-python-v7' } ] } diff --git a/client/src/templates/Introduction/SuperBlockIntro.js b/client/src/templates/Introduction/SuperBlockIntro.js index bd17ed0c4e..bc3fd497bf 100644 --- a/client/src/templates/Introduction/SuperBlockIntro.js +++ b/client/src/templates/Introduction/SuperBlockIntro.js @@ -19,10 +19,11 @@ import { Spacer } from '../../components/helpers'; import { currentChallengeIdSelector, userFetchStateSelector, - isSignedInSelector + isSignedInSelector, + userSelector } from '../../redux'; import { resetExpansion, toggleBlock } from './redux'; -import { MarkdownRemark, AllChallengeNode } from '../../redux/propTypes'; +import { MarkdownRemark, AllChallengeNode, User } from '../../redux/propTypes'; import './intro.css'; @@ -47,7 +48,8 @@ const propTypes = { }), resetExpansion: PropTypes.func, t: PropTypes.func, - toggleBlock: PropTypes.func + toggleBlock: PropTypes.func, + user: User }; configureAnchors({ offset: -40, scrollDuration: 0 }); @@ -57,10 +59,12 @@ const mapStateToProps = state => { currentChallengeIdSelector, isSignedInSelector, userFetchStateSelector, - (currentChallengeId, isSignedIn, fetchState) => ({ + userSelector, + (currentChallengeId, isSignedIn, fetchState, user) => ({ currentChallengeId, isSignedIn, - fetchState + fetchState, + user }) )(state); }; @@ -137,12 +141,12 @@ class SuperBlockIntroductionPage extends Component { allChallengeNode: { edges } }, isSignedIn, - t + t, + user } = this.props; const nodesForSuperBlock = edges.map(({ node }) => node); const blockDashedNames = uniq(nodesForSuperBlock.map(({ block }) => block)); - const i18nSuperBlock = t(`intro:${superBlock}.title`); return ( @@ -168,14 +172,18 @@ class SuperBlockIntroductionPage extends Component { challenges={nodesForSuperBlock.filter( node => node.block === blockDashedName )} - superBlockDashedName={superBlock} + superBlock={superBlock} /> {blockDashedName !== 'project-euler' ? : null} ))} {superBlock !== 'coding-interview-prep' && (
    - +
    )}
    diff --git a/client/src/templates/Introduction/components/Block.js b/client/src/templates/Introduction/components/Block.js index 4b49cb5fc4..5fa04530e2 100644 --- a/client/src/templates/Introduction/components/Block.js +++ b/client/src/templates/Introduction/components/Block.js @@ -40,7 +40,7 @@ const propTypes = { completedChallenges: PropTypes.arrayOf(PropTypes.string), executeGA: PropTypes.func, isExpanded: PropTypes.bool, - superBlockDashedName: PropTypes.string, + superBlock: PropTypes.string, t: PropTypes.func, toggleBlock: PropTypes.func.isRequired }; @@ -90,7 +90,7 @@ export class Block extends Component { completedChallenges, challenges, isExpanded, - superBlockDashedName, + superBlock, t } = this.props; @@ -123,9 +123,7 @@ export class Block extends Component { ); }); - const blockIntroObj = t( - `intro:${superBlockDashedName}.blocks.${blockDashedName}` - ); + const blockIntroObj = t(`intro:${superBlock}.blocks.${blockDashedName}`); const blockTitle = blockIntroObj ? blockIntroObj.title : null; const blockIntroArr = blockIntroObj ? blockIntroObj.intro : []; const { @@ -144,7 +142,7 @@ export class Block extends Component { #
    - {!isAuditedCert(curriculumLocale, superBlockDashedName) && ( + {!isAuditedCert(curriculumLocale, superBlock) && (
    # - {!isAuditedCert(curriculumLocale, superBlockDashedName) && ( + {!isAuditedCert(curriculumLocale, superBlock) && (
    { - return createSelector(userSelector, user => ({ - user - }))(state); +const mapStateToProps = (state, props) => { + return createSelector( + certificatesByNameSelector(props.user.username), + ({ currentCerts }) => ({ + currentCerts + }) + )(state, props); }; export class CertChallenge extends Component { @@ -31,37 +39,16 @@ export class CertChallenge extends Component { superBlock, t, title, - user: { - is2018DataVisCert, - isApisMicroservicesCert, - isFrontEndLibsCert, - isQaCertV7, - isInfosecCertV7, - isJsAlgoDataStructCert, - isRespWebDesignCert, - isSciCompPyCertV7, - isDataAnalysisPyCertV7, - isMachineLearningPyCertV7, - username - } + user: { username }, + currentCerts } = this.props; - const userCertificates = { - 'responsive-web-design': isRespWebDesignCert, - 'javascript-algorithms-and-data-structures': isJsAlgoDataStructCert, - 'front-end-libraries': isFrontEndLibsCert, - 'data-visualization': is2018DataVisCert, - 'apis-and-microservices': isApisMicroservicesCert, - 'quality-assurance': isQaCertV7, - 'information-security': isInfosecCertV7, - 'scientific-computing-with-python': isSciCompPyCertV7, - 'data-analysis-with-python': isDataAnalysisPyCertV7, - 'machine-learning-with-python': isMachineLearningPyCertV7 - }; - const cert = certMap.find(x => x.title === title); - const isCertified = userCertificates[superBlock]; - const certLocation = `/certification/${username}/${cert.slug}`; + const isCertified = currentCerts.find( + cert => + certSlugTypeMap[cert.certSlug] === superBlockCertTypeMap[superBlock] + ).show; + const certLocation = `/certification/${username}/${cert.certSlug}`; const certCheckmarkStyle = { height: '40px', width: '40px' }; const i18nSuperBlock = t(`intro:${superBlock}.title`); const i18nCertText = t(`intro:misc-text.certification`, { diff --git a/client/src/utils/ajax.js b/client/src/utils/ajax.js index fde6346251..1cb9e50172 100644 --- a/client/src/utils/ajax.js +++ b/client/src/utils/ajax.js @@ -47,8 +47,8 @@ export function getUserProfile(username) { return get(`/api/users/get-public-profile?username=${username}`); } -export function getShowCert(username, cert) { - return get(`/certificate/showCert/${username}/${cert}`); +export function getShowCert(username, certSlug) { + return get(`/certificate/showCert/${username}/${certSlug}`); } export function getUsernameExists(username) { @@ -114,8 +114,8 @@ export function putUserUpdateEmail(email) { return put('/update-my-email', { email }); } -export function putVerifyCert(superBlock) { - return put('/certificate/verify', { superBlock }); +export function putVerifyCert(certSlug) { + return put('/certificate/verify', { certSlug }); } /** DELETE **/ diff --git a/config/certification-settings.js b/config/certification-settings.js index 4998a91e12..300706a1bf 100644 --- a/config/certification-settings.js +++ b/config/certification-settings.js @@ -52,7 +52,7 @@ const completionHours = { [certTypes.machineLearningPyV7]: 300 }; -const superBlockCertTypeMap = { +const certSlugTypeMap = { // legacy 'legacy-front-end': certTypes.frontEnd, 'legacy-back-end': certTypes.backEnd, @@ -75,6 +75,27 @@ const superBlockCertTypeMap = { 'machine-learning-with-python-v7': certTypes.machineLearningPyV7 }; +const superBlockCertTypeMap = { + // legacy + 'legacy-front-end': certTypes.frontEnd, + 'legacy-back-end': certTypes.backEnd, + 'legacy-data-visualization': certTypes.dataVis, + 'information-security-and-quality-assurance': certTypes.infosecQa, + 'full-stack': certTypes.fullStack, + + // modern + 'responsive-web-design': certTypes.respWebDesign, + 'javascript-algorithms-and-data-structures': certTypes.jsAlgoDataStruct, + 'front-end-libraries': certTypes.frontEndLibs, + 'data-visualization': certTypes.dataVis2018, + 'apis-and-microservices': certTypes.apisMicroservices, + 'quality-assurance': certTypes.qaV7, + 'information-security': certTypes.infosecV7, + 'scientific-computing-with-python': certTypes.sciCompPyV7, + 'data-analysis-with-python': certTypes.dataAnalysisPyV7, + 'machine-learning-with-python': certTypes.machineLearningPyV7 +}; + const certTypeIdMap = { [certTypes.frontEnd]: certIds.legacyFrontEndChallengeId, [certTypes.backEnd]: certIds.legacyBackEndChallengeId, @@ -115,6 +136,7 @@ exports.oldDataVizId = '561add10cb82ac38a17513b3'; exports.completionHours = completionHours; exports.certTypes = certTypes; exports.superBlockCertTypeMap = superBlockCertTypeMap; +exports.certSlugTypeMap = certSlugTypeMap; exports.certIds = certIds; exports.certTypeIdMap = certTypeIdMap; exports.certTypeTitleMap = certTypeTitleMap;