refactor: use cert as key (#64293)

This commit is contained in:
Oliver Eyton-Williams
2025-12-04 10:21:03 +01:00
committed by GitHub
parent 73ad631dfd
commit 9d8cbcff5a
6 changed files with 64 additions and 45 deletions
+2 -2
View File
@@ -6,7 +6,7 @@ import { getChallenges } from '../../utils/get-challenges.js';
import {
certIds,
certSlugTypeMap,
certTypeTitleMap,
certToTitleMap,
certTypes,
currentCertifications,
legacyCertifications,
@@ -298,7 +298,7 @@ export const protectedCertificateRoutes: FastifyPluginCallbackTypebox = (
}
const certType = certSlugTypeMap[certSlug];
const certName = certTypeTitleMap[certType];
const certName = certToTitleMap[certSlug];
const user = await fastify.prisma.user.findUnique({
where: { id: req.user?.id }
+4 -5
View File
@@ -4,7 +4,7 @@ import { find } from 'lodash-es';
import * as schemas from '../../schemas.js';
import {
certSlugTypeMap,
certTypeTitleMap,
certToTitleMap,
certTypeIdMap,
completionHours,
oldDataVizId
@@ -53,7 +53,7 @@ export const unprotectedCertificateRoutes: FastifyPluginCallbackTypebox = (
const certType = certSlugTypeMap[certSlug];
const certId = certTypeIdMap[certType];
const certTitle = certTypeTitleMap[certType];
const certTitle = certToTitleMap[certSlug];
const completionTime = completionHours[certType] || 300;
const user = await fastify.prisma.user.findFirst({
where: { username },
@@ -180,16 +180,15 @@ export const unprotectedCertificateRoutes: FastifyPluginCallbackTypebox = (
}
if (!user[certType]) {
const cert = certTypeTitleMap[certType];
logger.info(
`User ${username} has not completed the ${cert} certification.`
`User ${username} has not completed the ${certTitle} certification.`
);
return reply.send({
messages: [
{
type: 'info',
message: 'flash.user-not-certified',
variables: { username, cert }
variables: { username, cert: certTitle }
}
]
});
+3 -12
View File
@@ -2,7 +2,7 @@ import { createSelector } from 'reselect';
import { liveCerts } from '../../config/cert-and-project-map';
import {
certTypeIdMap,
certTypeTitleMap
certToTitleMap
} from '../../../shared-dist/config/certification-settings.js';
import { randomBetween } from '../utils/random-between';
@@ -238,18 +238,10 @@ export const claimableCertsSelector = createSelector([userSelector], user => {
},
{}
);
// Invert certTypeIdMap ({[userFlag]: certId} => {[certId]: userFlag}) to get certType from id
const invertedCertTypeIdMap = Object.entries(certTypeIdMap).reduce(
(acc, [userFlag, certId]) => {
acc[certId] = userFlag;
return acc;
},
{}
);
const claimable = [];
for (const { id, projects } of liveCerts) {
for (const { id, projects, certSlug } of liveCerts) {
if (!projects) continue;
if (isClaimedById[id]) continue;
@@ -258,8 +250,7 @@ export const claimableCertsSelector = createSelector([userSelector], user => {
completedChallengeIds.includes(id)
);
const certType = invertedCertTypeIdMap[id];
const certTitle = certTypeTitleMap[certType];
const certTitle = certToTitleMap[certSlug];
if (allProjectsComplete) {
claimable.push({
certTitle
+14 -1
View File
@@ -1,5 +1,9 @@
import { describe, it, expect } from 'vitest';
import { Certification, linkedInCredentialIds } from './certification-settings';
import {
Certification,
linkedInCredentialIds,
certToTitleMap
} from './certification-settings';
describe('linkedInCredentialIds', () => {
it('should contain a value for all certifications', () => {
@@ -9,3 +13,12 @@ describe('linkedInCredentialIds', () => {
expect(linkedInCredentialIdsKeys).toEqual(allCertifications);
});
});
describe('certToTitleMap', () => {
it('should not contain duplicate titles', () => {
const titles = Object.values(certToTitleMap);
const uniqueTitles = Array.from(new Set(titles));
expect(titles.length).toBe(uniqueTitles.length);
});
});
+39 -23
View File
@@ -269,31 +269,47 @@ export const certTypeIdMap = {
[certTypes.a2English]: certIds.a2EnglishId
};
export const certTypeTitleMap = {
[certTypes.frontEnd]: 'Legacy Front End',
[certTypes.backEnd]: 'Legacy Back End',
[certTypes.dataVis]: 'Legacy Data Visualization',
[certTypes.infosecQa]: 'Legacy Information Security and Quality Assurance',
[certTypes.fullStack]: 'Legacy Full Stack',
[certTypes.respWebDesign]: 'Legacy Responsive Web Design V8',
[certTypes.respWebDesignV9]: 'Responsive Web Design',
[certTypes.frontEndDevLibs]: 'Front End Development Libraries V8',
[certTypes.jsAlgoDataStruct]:
// TODO: use i18n keys instead of hardcoded titles
export const certToTitleMap: Record<Certification, string> = {
// Legacy certifications
[Certification.LegacyFrontEnd]: 'Legacy Front End',
[Certification.JsAlgoDataStruct]:
'Legacy JavaScript Algorithms and Data Structures V7',
[certTypes.dataVis2018]: 'Data Visualization V8',
[certTypes.apisMicroservices]: 'Back End Development and APIs V8',
[certTypes.qaV7]: 'Quality Assurance',
[certTypes.infosecV7]: 'Information Security',
[certTypes.sciCompPyV7]: 'Scientific Computing with Python',
[certTypes.dataAnalysisPyV7]: 'Data Analysis with Python',
[certTypes.machineLearningPyV7]: 'Machine Learning with Python',
[certTypes.relationalDatabaseV8]: 'Relational Database V8',
[certTypes.collegeAlgebraPyV8]: 'College Algebra with Python',
[certTypes.foundationalCSharpV8]: 'Foundational C# with Microsoft',
[certTypes.jsAlgoDataStructV8]:
[Certification.LegacyBackEnd]: 'Legacy Back End',
[Certification.LegacyDataVis]: 'Legacy Data Visualization',
[Certification.LegacyInfoSecQa]:
'Legacy Information Security and Quality Assurance',
[Certification.LegacyFullStack]: 'Legacy Full Stack',
// Current certifications
[Certification.RespWebDesign]: 'Legacy Responsive Web Design V8',
[Certification.JsAlgoDataStructNew]:
'Legacy JavaScript Algorithms and Data Structures V8',
[certTypes.javascriptV9]: 'JavaScript',
[certTypes.a2English]: 'A2 English for Developers'
[Certification.FrontEndDevLibs]: 'Front End Development Libraries V8',
[Certification.DataVis]: 'Data Visualization V8',
[Certification.BackEndDevApis]: 'Back End Development and APIs V8',
[Certification.QualityAssurance]: 'Quality Assurance',
[Certification.InfoSec]: 'Information Security',
[Certification.SciCompPy]: 'Scientific Computing with Python',
[Certification.DataAnalysisPy]: 'Data Analysis with Python',
[Certification.MachineLearningPy]: 'Machine Learning with Python',
[Certification.RelationalDb]: 'Relational Database V8',
[Certification.CollegeAlgebraPy]: 'College Algebra with Python',
[Certification.FoundationalCSharp]: 'Foundational C# with Microsoft',
[Certification.A2English]: 'A2 English for Developers',
// Upcoming certifications
[Certification.RespWebDesignV9]: 'Responsive Web Design',
[Certification.JsV9]: 'JavaScript',
[Certification.FrontEndDevLibsV9]: 'Front End Development Libraries',
[Certification.PythonV9]: 'Python',
[Certification.RelationalDbV9]: 'Relational Database',
[Certification.BackEndDevApisV9]: 'Back End Development and APIs',
[Certification.FullStackDeveloperV9]: 'Full Stack Developer',
[Certification.B1English]: 'B1 English for Developers',
[Certification.A2Spanish]: 'A2 Professional Spanish',
[Certification.A2Chinese]: 'A2 Professional Chinese',
[Certification.A1Chinese]: 'A1 Professional Chinese'
};
export const superBlockToCertMap: {
+2 -2
View File
@@ -174,7 +174,7 @@ export const canSaveToDB = (challengeType: number): boolean =>
challengeType === challengeTypes.multifileCertProject ||
challengeType === challengeTypes.multifilePythonCertProject;
export const dailyCodingChallengeTypes = [
const dailyCodingChallengeTypes = [
challengeTypes.dailyChallengeJs,
challengeTypes.dailyChallengePy
];
@@ -182,7 +182,7 @@ export const dailyCodingChallengeTypes = [
export const getIsDailyCodingChallenge = (challengeType: number): boolean =>
dailyCodingChallengeTypes.includes(challengeType);
export const dailyCodingChallengeLanguages = {
const dailyCodingChallengeLanguages = {
[challengeTypes.dailyChallengeJs]: 'javascript',
[challengeTypes.dailyChallengePy]: 'python'
};