fix: add cert claim logic for legacy cert
This commit is contained in:
committed by
Mrugesh Mohapatra
parent
c2ffd6471b
commit
bc099d4971
@ -51,7 +51,12 @@ export function DynamicForm({
|
|||||||
onSubmit={handleSubmit(submit)}
|
onSubmit={handleSubmit(submit)}
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
>
|
>
|
||||||
<FormFields errors={errors} fields={fields} options={options} />
|
<FormFields
|
||||||
|
errors={errors}
|
||||||
|
fields={fields}
|
||||||
|
formId={id}
|
||||||
|
options={options}
|
||||||
|
/>
|
||||||
<BlockSaveWrapper>
|
<BlockSaveWrapper>
|
||||||
{hideButton ? null : (
|
{hideButton ? null : (
|
||||||
<BlockSaveButton
|
<BlockSaveButton
|
||||||
|
@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { find, first } from 'lodash';
|
import { find, first, values, isString } from 'lodash';
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
Button,
|
Button,
|
||||||
@ -13,7 +13,7 @@ import {
|
|||||||
import { Link, navigate } from 'gatsby';
|
import { Link, navigate } from 'gatsby';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
import { updateLegacyCertificate } from '../../redux/settings';
|
import { updateLegacyCert } from '../../redux/settings';
|
||||||
import { projectMap, legacyProjectMap } from '../../resources/certProjectMap';
|
import { projectMap, legacyProjectMap } from '../../resources/certProjectMap';
|
||||||
|
|
||||||
import SectionHeader from './SectionHeader';
|
import SectionHeader from './SectionHeader';
|
||||||
@ -22,11 +22,12 @@ import { FullWidthRow, Spacer } from '../helpers';
|
|||||||
import { Form } from '../formHelpers';
|
import { Form } from '../formHelpers';
|
||||||
|
|
||||||
import { maybeUrlRE } from '../../utils';
|
import { maybeUrlRE } from '../../utils';
|
||||||
|
import reallyWeirdErrorMessage from '../../utils/reallyWeirdErrorMessage';
|
||||||
|
|
||||||
import './certification.css';
|
import './certification.css';
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch =>
|
const mapDispatchToProps = dispatch =>
|
||||||
bindActionCreators({ updateLegacyCertificate }, dispatch);
|
bindActionCreators({ updateLegacyCert }, dispatch);
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
completedChallenges: PropTypes.arrayOf(
|
completedChallenges: PropTypes.arrayOf(
|
||||||
@ -51,7 +52,7 @@ const propTypes = {
|
|||||||
isInfosecQaCert: PropTypes.bool,
|
isInfosecQaCert: PropTypes.bool,
|
||||||
isJsAlgoDataStructCert: PropTypes.bool,
|
isJsAlgoDataStructCert: PropTypes.bool,
|
||||||
isRespWebDesignCert: PropTypes.bool,
|
isRespWebDesignCert: PropTypes.bool,
|
||||||
updateLegacyCertificate: PropTypes.func.isRequired,
|
updateLegacyCert: PropTypes.func.isRequired,
|
||||||
username: PropTypes.string,
|
username: PropTypes.string,
|
||||||
verifyCert: PropTypes.func.isRequired
|
verifyCert: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
@ -107,6 +108,13 @@ const isCertMapSelector = createSelector(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const honestyInfoMessage = {
|
||||||
|
type: 'info',
|
||||||
|
message:
|
||||||
|
'To claim a certification, you must first accept our academic ' +
|
||||||
|
'honesty policy'
|
||||||
|
};
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
solutionViewer: {
|
solutionViewer: {
|
||||||
projectTitle: '',
|
projectTitle: '',
|
||||||
@ -249,12 +257,7 @@ class CertificationSettings extends Component {
|
|||||||
}
|
}
|
||||||
return isHonest
|
return isHonest
|
||||||
? verifyCert(superBlock)
|
? verifyCert(superBlock)
|
||||||
: createFlashMessage({
|
: createFlashMessage(honestyInfoMessage);
|
||||||
type: 'info',
|
|
||||||
message:
|
|
||||||
'To claim a certification, you must first accept our academic ' +
|
|
||||||
'honesty policy'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
return projectMap[certName]
|
return projectMap[certName]
|
||||||
.map(({ link, title, id }) => (
|
.map(({ link, title, id }) => (
|
||||||
@ -284,18 +287,83 @@ class CertificationSettings extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// legacy projects rendering
|
// legacy projects rendering
|
||||||
|
handleSubmit(formChalObj) {
|
||||||
|
const {
|
||||||
|
isHonest,
|
||||||
|
createFlashMessage,
|
||||||
|
verifyCert,
|
||||||
|
updateLegacyCert
|
||||||
|
} = this.props;
|
||||||
|
let legacyTitle;
|
||||||
|
let superBlock;
|
||||||
|
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;
|
||||||
|
loopBreak = true;
|
||||||
|
legacyTitle = certTitle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (loopBreak) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleSubmit(values) {
|
// make an object with keys as challenge ids and values as solutions
|
||||||
const { updateLegacyCertificate } = this.props;
|
let idsToSolutions = {};
|
||||||
updateLegacyCertificate(values);
|
for (let i of Object.keys(formChalObj)) {
|
||||||
|
for (let j of legacyProjectMap[legacyTitle]) {
|
||||||
|
if (i === j.title) {
|
||||||
|
idsToSolutions[j.id] = formChalObj[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter the new solutions that need to be updated
|
||||||
|
const completedChallenges = this.props.completedChallenges;
|
||||||
|
let challengesToUpdate = {};
|
||||||
|
let newChalleneFound = true;
|
||||||
|
let oldSubmissions = 0;
|
||||||
|
for (let submittedChal of Object.keys(idsToSolutions)) {
|
||||||
|
for (let i of completedChallenges) {
|
||||||
|
if (i.id === submittedChal) {
|
||||||
|
if (idsToSolutions[submittedChal] !== i.solution) {
|
||||||
|
challengesToUpdate[submittedChal] = idsToSolutions[submittedChal];
|
||||||
|
}
|
||||||
|
oldSubmissions++;
|
||||||
|
newChalleneFound = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newChalleneFound && idsToSolutions[submittedChal] !== '') {
|
||||||
|
challengesToUpdate[submittedChal] = idsToSolutions[submittedChal];
|
||||||
|
}
|
||||||
|
newChalleneFound = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const valuesSaved = values(formChalObj)
|
||||||
|
.filter(Boolean)
|
||||||
|
.filter(isString);
|
||||||
|
|
||||||
|
const isProjectSectionComplete = valuesSaved.length === oldSubmissions;
|
||||||
|
|
||||||
|
if (isProjectSectionComplete) {
|
||||||
|
return isHonest
|
||||||
|
? verifyCert(superBlock)
|
||||||
|
: createFlashMessage(honestyInfoMessage);
|
||||||
|
}
|
||||||
|
return updateLegacyCert({ challengesToUpdate, superBlock });
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLegacyCertifications = certName => {
|
renderLegacyCertifications = certName => {
|
||||||
const { username, isHonest, createFlashMessage, verifyCert } = this.props;
|
const { username, createFlashMessage, completedChallenges } = this.props;
|
||||||
const { superBlock } = first(legacyProjectMap[certName]);
|
const { superBlock } = first(legacyProjectMap[certName]);
|
||||||
const certLocation = `/certification/${username}/${superBlock}`;
|
const certLocation = `/certification/${username}/${superBlock}`;
|
||||||
const challengeTitles = legacyProjectMap[certName].map(item => item.title);
|
const challengeTitles = legacyProjectMap[certName].map(item => item.title);
|
||||||
const { completedChallenges } = this.props;
|
|
||||||
const isCertClaimed = this.getUserIsCertMap()[certName];
|
const isCertClaimed = this.getUserIsCertMap()[certName];
|
||||||
const initialObject = {};
|
const initialObject = {};
|
||||||
let filledforms = 0;
|
let filledforms = 0;
|
||||||
@ -321,19 +389,12 @@ class CertificationSettings extends Component {
|
|||||||
|
|
||||||
const fullForm = filledforms === challengeTitles.length;
|
const fullForm = filledforms === challengeTitles.length;
|
||||||
|
|
||||||
const createClickHandler = superBlock => e => {
|
const createClickHandler = certLocation => e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (isCertClaimed) {
|
if (isCertClaimed) {
|
||||||
return navigate(certLocation);
|
return navigate(certLocation);
|
||||||
}
|
}
|
||||||
return isHonest
|
return createFlashMessage(reallyWeirdErrorMessage);
|
||||||
? verifyCert(superBlock)
|
|
||||||
: createFlashMessage({
|
|
||||||
type: 'info',
|
|
||||||
message:
|
|
||||||
'To claim a certification, you must first accept our academic ' +
|
|
||||||
'honesty policy'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const buttonStyle = {
|
const buttonStyle = {
|
||||||
@ -341,7 +402,7 @@ class CertificationSettings extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FullWidthRow key={certName}>
|
<FullWidthRow key={superBlock}>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<h3>{certName}</h3>
|
<h3>{certName}</h3>
|
||||||
<Form
|
<Form
|
||||||
@ -349,7 +410,7 @@ class CertificationSettings extends Component {
|
|||||||
enableSubmit={fullForm}
|
enableSubmit={fullForm}
|
||||||
formFields={challengeTitles}
|
formFields={challengeTitles}
|
||||||
hideButton={isCertClaimed}
|
hideButton={isCertClaimed}
|
||||||
id={certName}
|
id={superBlock}
|
||||||
initialValues={{
|
initialValues={{
|
||||||
...initialObject
|
...initialObject
|
||||||
}}
|
}}
|
||||||
@ -363,7 +424,7 @@ class CertificationSettings extends Component {
|
|||||||
bsStyle='primary'
|
bsStyle='primary'
|
||||||
className={'col-xs-12'}
|
className={'col-xs-12'}
|
||||||
href={certLocation}
|
href={certLocation}
|
||||||
onClick={createClickHandler(superBlock)}
|
onClick={createClickHandler(certLocation)}
|
||||||
style={buttonStyle}
|
style={buttonStyle}
|
||||||
target='_blank'
|
target='_blank'
|
||||||
>
|
>
|
||||||
|
@ -316,7 +316,7 @@ export const reducer = handleActions(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[settingsTypes.updateLegacyCertificateComplete]: (state, { payload }) => {
|
[settingsTypes.updateLegacyCertComplete]: (state, { payload }) => {
|
||||||
const { appUsername } = state;
|
const { appUsername } = state;
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
@ -6,7 +6,7 @@ import { createSettingsSagas } from './settings-sagas';
|
|||||||
import { createUpdateMyEmailSaga } from './update-email-saga';
|
import { createUpdateMyEmailSaga } from './update-email-saga';
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
import { createUpdateLegacyCertificateSaga } from
|
import { createUpdateLegacyCertSaga } from
|
||||||
'./update-legacy-certificate-saga';
|
'./update-legacy-certificate-saga';
|
||||||
|
|
||||||
export const ns = 'settings';
|
export const ns = 'settings';
|
||||||
@ -31,7 +31,7 @@ export const types = createTypes(
|
|||||||
...createAsyncTypes('submitNewAbout'),
|
...createAsyncTypes('submitNewAbout'),
|
||||||
...createAsyncTypes('submitNewUsername'),
|
...createAsyncTypes('submitNewUsername'),
|
||||||
...createAsyncTypes('updateMyEmail'),
|
...createAsyncTypes('updateMyEmail'),
|
||||||
...createAsyncTypes('updateLegacyCertificate'),
|
...createAsyncTypes('updateLegacyCert'),
|
||||||
...createAsyncTypes('updateUserFlag'),
|
...createAsyncTypes('updateUserFlag'),
|
||||||
...createAsyncTypes('submitProfileUI'),
|
...createAsyncTypes('submitProfileUI'),
|
||||||
...createAsyncTypes('verifyCert'),
|
...createAsyncTypes('verifyCert'),
|
||||||
@ -45,7 +45,7 @@ export const sagas = [
|
|||||||
...createSettingsSagas(types),
|
...createSettingsSagas(types),
|
||||||
...createUpdateMyEmailSaga(types),
|
...createUpdateMyEmailSaga(types),
|
||||||
...createDangerZoneSaga(types),
|
...createDangerZoneSaga(types),
|
||||||
...createUpdateLegacyCertificateSaga(types)
|
...createUpdateLegacyCertSaga(types)
|
||||||
];
|
];
|
||||||
|
|
||||||
const checkForSuccessPayload = ({ type, payload }) =>
|
const checkForSuccessPayload = ({ type, payload }) =>
|
||||||
@ -78,15 +78,11 @@ export const updateMyEmail = createAction(types.updateMyEmail);
|
|||||||
export const updateMyEmailComplete = createAction(types.updateMyEmailComplete);
|
export const updateMyEmailComplete = createAction(types.updateMyEmailComplete);
|
||||||
export const updateMyEmailError = createAction(types.updateMyEmailError);
|
export const updateMyEmailError = createAction(types.updateMyEmailError);
|
||||||
|
|
||||||
export const updateLegacyCertificate = createAction(
|
export const updateLegacyCert = createAction(types.updateLegacyCert);
|
||||||
types.updateLegacyCertificate
|
export const updateLegacyCertComplete = createAction(
|
||||||
);
|
types.updateLegacyCertComplete
|
||||||
export const updateLegacyCertificateComplete = createAction(
|
|
||||||
types.updateLegacyCertificateComplete
|
|
||||||
);
|
|
||||||
export const updateLegacyCertificateError = createAction(
|
|
||||||
types.updateLegacyCertificateError
|
|
||||||
);
|
);
|
||||||
|
export const updateLegacyCertError = createAction(types.updateLegacyCertError);
|
||||||
|
|
||||||
export const updateUserFlag = createAction(types.updateUserFlag);
|
export const updateUserFlag = createAction(types.updateUserFlag);
|
||||||
export const updateUserFlagComplete = createAction(
|
export const updateUserFlagComplete = createAction(
|
||||||
|
@ -1,73 +1,21 @@
|
|||||||
import { takeEvery, select, call, put } from 'redux-saga/effects';
|
import { takeEvery, call, put } from 'redux-saga/effects';
|
||||||
|
|
||||||
import { putUpdateLegacyCertificate } from '../../utils/ajax';
|
import { putUpdateLegacyCert } from '../../utils/ajax';
|
||||||
import { completedChallengesSelector, submitComplete } from '../';
|
import { submitComplete } from '../';
|
||||||
import { legacyProjectMap } from '../../resources/certProjectMap';
|
|
||||||
import { createFlashMessage } from '../../components/Flash/redux';
|
import { createFlashMessage } from '../../components/Flash/redux';
|
||||||
import standardErrorMessage from '../../utils/reallyWeirdErrorMessage';
|
import reallyWeirdErrorMessage from '../../utils/reallyWeirdErrorMessage';
|
||||||
import { updateLegacyCertificateError } from './';
|
import { updateLegacyCertError } from './';
|
||||||
|
|
||||||
const completedChallenges = state => completedChallengesSelector(state);
|
|
||||||
|
|
||||||
function* updateLegacyCertificateSaga({ payload }) {
|
|
||||||
// find which certificate the challenges belong to
|
|
||||||
let legacyCert;
|
|
||||||
let certs = Object.keys(legacyProjectMap);
|
|
||||||
let loopBreak = false;
|
|
||||||
for (let i of certs) {
|
|
||||||
for (let j of legacyProjectMap[i]) {
|
|
||||||
if (j.title === Object.keys(payload)[0]) {
|
|
||||||
console.log(j.title);
|
|
||||||
loopBreak = true;
|
|
||||||
legacyCert = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (loopBreak) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// make an object with keys as challenge ids and values as solutions
|
|
||||||
let idsToSolutions = {};
|
|
||||||
for (let i of Object.keys(payload)) {
|
|
||||||
for (let j of legacyProjectMap[legacyCert]) {
|
|
||||||
if (i === j.title) {
|
|
||||||
console.log(payload[i]);
|
|
||||||
idsToSolutions[j.id] = payload[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// find how many challnegs have been updated and how many are new
|
|
||||||
let completed = yield select(completedChallenges);
|
|
||||||
let challengesToUpdate = {};
|
|
||||||
let newChalleneFound = true;
|
|
||||||
for (let j of Object.keys(idsToSolutions)) {
|
|
||||||
for (let i of completed) {
|
|
||||||
if (i.id === j) {
|
|
||||||
if (idsToSolutions[j] !== i.solution) {
|
|
||||||
challengesToUpdate[j] = idsToSolutions[j];
|
|
||||||
}
|
|
||||||
newChalleneFound = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (newChalleneFound && idsToSolutions[j] !== '') {
|
|
||||||
challengesToUpdate[j] = idsToSolutions[j];
|
|
||||||
}
|
|
||||||
newChalleneFound = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
function* updateLegacyCertSaga({
|
||||||
|
payload: { superBlock, challengesToUpdate }
|
||||||
|
}) {
|
||||||
// shape the body of the http call so it is consumable by api
|
// shape the body of the http call so it is consumable by api
|
||||||
const body = {
|
const body = {
|
||||||
projects: {
|
projects: {
|
||||||
[legacyCert]: challengesToUpdate
|
[superBlock]: challengesToUpdate
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// shape to update completed challenges in redux store
|
||||||
// shape to update completed challenges
|
|
||||||
let reduxShape = [];
|
let reduxShape = [];
|
||||||
for (let obj in challengesToUpdate) {
|
for (let obj in challengesToUpdate) {
|
||||||
if (challengesToUpdate.hasOwnProperty(obj)) {
|
if (challengesToUpdate.hasOwnProperty(obj)) {
|
||||||
@ -76,17 +24,16 @@ function* updateLegacyCertificateSaga({ payload }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data: response } = yield call(putUpdateLegacyCertificate, body);
|
const { data: response } = yield call(putUpdateLegacyCert, body);
|
||||||
yield put(submitComplete({ challArray: reduxShape }));
|
yield put(submitComplete({ challArray: reduxShape }));
|
||||||
yield put(createFlashMessage(response));
|
yield put(createFlashMessage(response));
|
||||||
|
console.log(response);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
yield put(updateLegacyCertificateError(e));
|
yield put(updateLegacyCertError(e));
|
||||||
yield put(createFlashMessage(standardErrorMessage));
|
yield put(createFlashMessage(reallyWeirdErrorMessage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createUpdateLegacyCertificateSaga(types) {
|
export function createUpdateLegacyCertSaga(types) {
|
||||||
return [
|
return [takeEvery(types.updateLegacyCert, updateLegacyCertSaga)];
|
||||||
takeEvery(types.updateLegacyCertificate, updateLegacyCertificateSaga)
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ export function getArticleById(shortId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** POST **/
|
/** POST **/
|
||||||
export function putUpdateLegacyCertificate(body) {
|
export function putUpdateLegacyCert(body) {
|
||||||
return post('/update-my-projects', body);
|
return post('/update-my-projects', body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user