diff --git a/api-server/src/server/boot/certificate.js b/api-server/src/server/boot/certificate.js index 67c0c4d650..1bc230b3c4 100644 --- a/api-server/src/server/boot/certificate.js +++ b/api-server/src/server/boot/certificate.js @@ -157,7 +157,8 @@ function sendCertifiedEmail( isInfosecCertV7, isSciCompPyCertV7, isDataAnalysisPyCertV7, - isMachineLearningPyCertV7 + isMachineLearningPyCertV7, + isRelationalDatabaseCertV8 }, send$ ) { @@ -172,7 +173,8 @@ function sendCertifiedEmail( !isInfosecCertV7 || !isSciCompPyCertV7 || !isDataAnalysisPyCertV7 || - !isMachineLearningPyCertV7 + !isMachineLearningPyCertV7 || + !isRelationalDatabaseCertV8 ) { return Observable.just(false); } diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json index eeb98b70f4..18450ad6f2 100644 --- a/client/i18n/locales/english/intro.json +++ b/client/i18n/locales/english/intro.json @@ -767,6 +767,7 @@ "legacy-desc": "These courses are no longer part of the certification path, but are still available for you to further your learning.", "viewing-upcoming-change": "You are looking at a beta page. ", "go-back-to-learn": "Go back to the stable version of the curriculum.", - "read-database-cert-article": "Please read this forum post before proceeding." + "read-database-cert-article": "Please read this forum post before proceeding.", + "english-only": "The courses in this section are only available in English. We are only able to translate the titles and introductions at the moment, not the lessons themselves." } } diff --git a/client/src/resources/cert-and-project-map.ts b/client/src/resources/cert-and-project-map.ts index c76fb09b45..f351749c79 100644 --- a/client/src/resources/cert-and-project-map.ts +++ b/client/src/resources/cert-and-project-map.ts @@ -1,7 +1,7 @@ import { SuperBlocks } from '../../../config/certification-settings'; import envData from '../../../config/env.json'; -const { deploymentEnv, showNewCurriculum, showUpcomingChanges } = envData; +const { showNewCurriculum, showUpcomingChanges } = envData; const responsiveWebBase = '/learn/responsive-web-design/responsive-web-design-projects'; @@ -455,44 +455,6 @@ const certMap = [ } ] }, - { - id: '606243f50267e718b1e755f4', - title: 'Relational Database', - certSlug: 'relational-database-v8', - flag: 'isRelationalDatabaseCertV8', - projects: [ - { - id: '5f1a4ef5d5d6b5ab580fc6ae', - title: 'Celestial Bodies Database', - link: `${relationalDatabaseBase}/build-a-celestial-bodies-database-project/build-a-celestial-bodies-database`, - certSlug: 'relational-database-v8' - }, - { - id: '5f9771307d4d22b9d2b75a94', - title: 'World Cup Database', - link: `${relationalDatabaseBase}/build-a-world-cup-database-project/build-a-world-cup-database`, - certSlug: 'relational-database-v8' - }, - { - id: '5f87ac112ae598023a42df1a', - title: 'Salon Appointment Scheduler', - link: `${relationalDatabaseBase}/build-a-salon-appointment-scheduler-project/build-a-salon-appointment-scheduler`, - certSlug: 'relational-database-v8' - }, - { - id: '602d9ff222201c65d2a019f2', - title: 'Periodic Table Database', - link: `${relationalDatabaseBase}/build-a-periodic-table-database-project/build-a-periodic-table-database`, - certSlug: 'relational-database-v8' - }, - { - id: '602da04c22201c65d2a019f4', - title: 'Number Guessing Game', - link: `${relationalDatabaseBase}/build-a-number-guessing-game-project/build-a-number-guessing-game`, - certSlug: 'relational-database-v8' - } - ] - }, { id: '561add10cb82ac38a17523bc', title: 'Back End Development and APIs', @@ -721,6 +683,44 @@ const certMap = [ certSlug: 'machine-learning-with-python-v7' } ] + }, + { + id: '606243f50267e718b1e755f4', + title: 'Relational Database', + certSlug: 'relational-database-v8', + flag: 'isRelationalDatabaseCertV8', + projects: [ + { + id: '5f1a4ef5d5d6b5ab580fc6ae', + title: 'Celestial Bodies Database', + link: `${relationalDatabaseBase}/build-a-celestial-bodies-database-project/build-a-celestial-bodies-database`, + certSlug: 'relational-database-v8' + }, + { + id: '5f9771307d4d22b9d2b75a94', + title: 'World Cup Database', + link: `${relationalDatabaseBase}/build-a-world-cup-database-project/build-a-world-cup-database`, + certSlug: 'relational-database-v8' + }, + { + id: '5f87ac112ae598023a42df1a', + title: 'Salon Appointment Scheduler', + link: `${relationalDatabaseBase}/build-a-salon-appointment-scheduler-project/build-a-salon-appointment-scheduler`, + certSlug: 'relational-database-v8' + }, + { + id: '602d9ff222201c65d2a019f2', + title: 'Periodic Table Database', + link: `${relationalDatabaseBase}/build-a-periodic-table-database-project/build-a-periodic-table-database`, + certSlug: 'relational-database-v8' + }, + { + id: '602da04c22201c65d2a019f4', + title: 'Number Guessing Game', + link: `${relationalDatabaseBase}/build-a-number-guessing-game-project/build-a-number-guessing-game`, + certSlug: 'relational-database-v8' + } + ] } ] as const; @@ -745,12 +745,7 @@ certMap.forEach(cert => { if (cert.title !== 'Legacy Full Stack') { if (cert.title.startsWith('Legacy')) { legacyProjectMap[cert.title] = cert.projects; - } else if ( - cert.title.startsWith('Relational') && - deploymentEnv == 'staging' - ) { - projectMap[cert.title] = cert.projects; - } else if (!cert.title.startsWith('Relational')) { + } else { projectMap[cert.title] = cert.projects; } } diff --git a/client/src/templates/Challenges/codeally/show.tsx b/client/src/templates/Challenges/codeally/show.tsx index 3c796abbc5..64a1786c33 100644 --- a/client/src/templates/Challenges/codeally/show.tsx +++ b/client/src/templates/Challenges/codeally/show.tsx @@ -256,7 +256,7 @@ class ShowCodeAlly extends Component {
{ : 'https://replit.com/@camperbot/hello'); break; + case codeAllyCert: + formFields = solutionField; + options.isEditorLinkAllowed = true; + solutionLink = solutionLink + 'https://your-git-repo.url/files'; + break; + default: formFields = solutionField; solutionLink = diff --git a/client/src/templates/Introduction/components/legacy-links.tsx b/client/src/templates/Introduction/components/legacy-links.tsx index f0f6c3c87b..e420715600 100644 --- a/client/src/templates/Introduction/components/legacy-links.tsx +++ b/client/src/templates/Introduction/components/legacy-links.tsx @@ -4,6 +4,9 @@ import { Alert } from '@freecodecamp/react-bootstrap'; import { SuperBlocks } from '../../../../../config/certification-settings'; import { isNewRespCert, isRelationalDbCert } from '../../../utils/is-a-cert'; import { Link } from '../../../components/helpers'; +import envData from '../../../../../config/env.json'; + +const { clientLocale } = envData; interface LegacyLinksProps { superBlock: SuperBlocks; @@ -28,6 +31,11 @@ function LegacyLinks({ superBlock }: LegacyLinksProps): JSX.Element { else if (isRelationalDbCert(superBlock)) return ( <> + {clientLocale != 'english' && ( + +

{t('intro:misc-text.english-only')}

+
+ )}

{t('intro:misc-text.viewing-upcoming-change')}{' '} diff --git a/client/utils/build-challenges.js b/client/utils/build-challenges.js index b3d5f2dc6e..06d8bb882d 100644 --- a/client/utils/build-challenges.js +++ b/client/utils/build-challenges.js @@ -10,7 +10,7 @@ const { getChallengesDirForLang } = require('../../curriculum/getChallenges'); -const { curriculumLocale, deploymentEnv } = envData; +const { curriculumLocale } = envData; exports.localeChallengesRootDir = getChallengesDirForLang(curriculumLocale); @@ -38,12 +38,6 @@ exports.replaceChallengeNode = () => { exports.buildChallenges = async function buildChallenges() { const curriculum = await getChallengesForLang(curriculumLocale); - - // temp removal of rdbms from production - if (deploymentEnv !== 'staging') { - delete curriculum['relational-database']; - } - const superBlocks = Object.keys(curriculum); const blocks = superBlocks .map(superBlock => curriculum[superBlock].blocks) diff --git a/client/utils/challenge-types.js b/client/utils/challenge-types.js index fdc283bad6..23f32bc1da 100644 --- a/client/utils/challenge-types.js +++ b/client/utils/challenge-types.js @@ -20,6 +20,7 @@ exports.backend = backend; exports.frontEndProject = frontEndProject; exports.backEndProject = backEndProject; exports.pythonProject = pythonProject; +exports.codeAllyCert = codeAllyCert; exports.challengeTypes = { html, diff --git a/curriculum/utils.js b/curriculum/utils.js index c1029d0232..f4bc649296 100644 --- a/curriculum/utils.js +++ b/curriculum/utils.js @@ -25,19 +25,19 @@ const superBlockToOrder = { 'javascript-algorithms-and-data-structures': 1, 'front-end-development-libraries': 2, 'data-visualization': 3, - 'relational-database': 4, - 'back-end-development-and-apis': 5, - 'quality-assurance': 6, - 'scientific-computing-with-python': 7, - 'data-analysis-with-python': 8, - 'information-security': 9, - 'machine-learning-with-python': 10, - 'coding-interview-prep': 11 + 'back-end-development-and-apis': 4, + 'quality-assurance': 5, + 'scientific-computing-with-python': 6, + 'data-analysis-with-python': 7, + 'information-security': 8, + 'machine-learning-with-python': 9, + 'coding-interview-prep': 10, + 'relational-database': 12 }; const superBlockToNewOrder = { ...superBlockToOrder, - '2022/responsive-web-design': 12 + '2022/responsive-web-design': 11 }; function getSuperOrder( diff --git a/curriculum/utils.test.ts b/curriculum/utils.test.ts index 5f3cd2657c..dd5ace9d9a 100644 --- a/curriculum/utils.test.ts +++ b/curriculum/utils.test.ts @@ -31,14 +31,14 @@ describe('getSuperOrder', () => { expect(getSuperOrder('javascript-algorithms-and-data-structures')).toBe(1); expect(getSuperOrder('front-end-development-libraries')).toBe(2); expect(getSuperOrder('data-visualization')).toBe(3); - expect(getSuperOrder('relational-database')).toBe(4); - expect(getSuperOrder('back-end-development-and-apis')).toBe(5); - expect(getSuperOrder('quality-assurance')).toBe(6); - expect(getSuperOrder('scientific-computing-with-python')).toBe(7); - expect(getSuperOrder('data-analysis-with-python')).toBe(8); - expect(getSuperOrder('information-security')).toBe(9); - expect(getSuperOrder('machine-learning-with-python')).toBe(10); - expect(getSuperOrder('coding-interview-prep')).toBe(11); + expect(getSuperOrder('back-end-development-and-apis')).toBe(4); + expect(getSuperOrder('quality-assurance')).toBe(5); + expect(getSuperOrder('scientific-computing-with-python')).toBe(6); + expect(getSuperOrder('data-analysis-with-python')).toBe(7); + expect(getSuperOrder('information-security')).toBe(8); + expect(getSuperOrder('machine-learning-with-python')).toBe(9); + expect(getSuperOrder('coding-interview-prep')).toBe(10); + expect(getSuperOrder('relational-database')).toBe(12); }); it('returns a different order if passed the option showNewCurriculum: true', () => { @@ -59,36 +59,36 @@ describe('getSuperOrder', () => { expect( getSuperOrder('data-visualization', { showNewCurriculum: true }) ).toBe(3); - expect( - getSuperOrder('relational-database', { showNewCurriculum: true }) - ).toBe(4); expect( getSuperOrder('back-end-development-and-apis', { showNewCurriculum: true }) - ).toBe(5); + ).toBe(4); expect( getSuperOrder('quality-assurance', { showNewCurriculum: true }) - ).toBe(6); + ).toBe(5); expect( getSuperOrder('scientific-computing-with-python', { showNewCurriculum: true }) - ).toBe(7); + ).toBe(6); expect( getSuperOrder('data-analysis-with-python', { showNewCurriculum: true }) - ).toBe(8); + ).toBe(7); expect( getSuperOrder('information-security', { showNewCurriculum: true }) - ).toBe(9); + ).toBe(8); expect( getSuperOrder('machine-learning-with-python', { showNewCurriculum: true }) - ).toBe(10); + ).toBe(9); expect( getSuperOrder('coding-interview-prep', { showNewCurriculum: true }) - ).toBe(11); + ).toBe(10); expect( getSuperOrder('2022/responsive-web-design', { showNewCurriculum: true }) + ).toBe(11); + expect( + getSuperOrder('relational-database', { showNewCurriculum: true }) ).toBe(12); }); }); diff --git a/cypress/integration/landing.js b/cypress/integration/landing.js index ebeb2b1b48..2c44af30a3 100644 --- a/cypress/integration/landing.js +++ b/cypress/integration/landing.js @@ -17,7 +17,8 @@ const certifications = [ 'Data Analysis with Python', 'Information Security', 'Machine Learning with Python', - 'Responsive Web Design (Beta)' + 'Responsive Web Design (Beta)', + 'Relational Database (Beta)' ]; describe('Landing page', () => { diff --git a/cypress/integration/learn/challenges/codeally.js b/cypress/integration/learn/challenges/codeally.js new file mode 100644 index 0000000000..32140cbea5 --- /dev/null +++ b/cypress/integration/learn/challenges/codeally.js @@ -0,0 +1,35 @@ +describe('CodeAlly cert challenge', function () { + describe('before completing the project', function () { + before(() => { + cy.exec('npm run seed'); + cy.login(); + cy.visit( + '/learn/relational-database/build-a-celestial-bodies-database-project/build-a-celestial-bodies-database' + ); + }); + + it('should not allow you to submit a URL', function () { + cy.get('input[name="solution"]') + .type('https://example.com') + .type('{enter}'); + cy.contains('You must complete the project first.'); + }); + }); + + describe('after completing the project', function () { + before(() => { + cy.exec('npm run seed:certified-user'); + cy.login(); + cy.visit( + '/learn/relational-database/build-a-celestial-bodies-database-project/build-a-celestial-bodies-database' + ); + }); + + it('should allow you to submit a URL', function () { + cy.get('input[name="solution"]') + .type('https://example.com') + .type('{enter}'); + cy.get('.completion-modal-body'); + }); + }); +}); diff --git a/cypress/integration/learn/index.js b/cypress/integration/learn/index.js index 7e01f69121..b4737ae123 100644 --- a/cypress/integration/learn/index.js +++ b/cypress/integration/learn/index.js @@ -11,7 +11,6 @@ const superBlockNames = [ 'JavaScript Algorithms and Data Structures Certification', 'Front End Development Libraries Certification', 'Data Visualization Certification', - 'Relational Database (Beta) Certification', 'Back End Development and APIs Certification', 'Quality Assurance Certification', 'Scientific Computing with Python Certification', @@ -19,7 +18,8 @@ const superBlockNames = [ 'Information Security Certification', 'Machine Learning with Python Certification', 'Coding Interview Prep (Thousands of hours of challenges)', - 'Responsive Web Design (Beta) Certification' + 'Responsive Web Design (Beta) Certification', + 'Relational Database (Beta) Certification' ]; describe('Learn Landing page (not logged in)', () => {