fix: add cert claim logic for legacy cert

This commit is contained in:
Ahmad Abdolsaheb
2019-03-28 11:18:26 +03:00
committed by Mrugesh Mohapatra
parent c2ffd6471b
commit bc099d4971
6 changed files with 119 additions and 110 deletions

View File

@ -51,7 +51,12 @@ export function DynamicForm({
onSubmit={handleSubmit(submit)}
style={{ width: '100%' }}
>
<FormFields errors={errors} fields={fields} options={options} />
<FormFields
errors={errors}
fields={fields}
formId={id}
options={options}
/>
<BlockSaveWrapper>
{hideButton ? null : (
<BlockSaveButton

View File

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { find, first } from 'lodash';
import { find, first, values, isString } from 'lodash';
import {
Table,
Button,
@ -13,7 +13,7 @@ import {
import { Link, navigate } from 'gatsby';
import { createSelector } from 'reselect';
import { updateLegacyCertificate } from '../../redux/settings';
import { updateLegacyCert } from '../../redux/settings';
import { projectMap, legacyProjectMap } from '../../resources/certProjectMap';
import SectionHeader from './SectionHeader';
@ -22,11 +22,12 @@ import { FullWidthRow, Spacer } from '../helpers';
import { Form } from '../formHelpers';
import { maybeUrlRE } from '../../utils';
import reallyWeirdErrorMessage from '../../utils/reallyWeirdErrorMessage';
import './certification.css';
const mapDispatchToProps = dispatch =>
bindActionCreators({ updateLegacyCertificate }, dispatch);
bindActionCreators({ updateLegacyCert }, dispatch);
const propTypes = {
completedChallenges: PropTypes.arrayOf(
@ -51,7 +52,7 @@ const propTypes = {
isInfosecQaCert: PropTypes.bool,
isJsAlgoDataStructCert: PropTypes.bool,
isRespWebDesignCert: PropTypes.bool,
updateLegacyCertificate: PropTypes.func.isRequired,
updateLegacyCert: PropTypes.func.isRequired,
username: PropTypes.string,
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 = {
solutionViewer: {
projectTitle: '',
@ -249,12 +257,7 @@ class CertificationSettings extends Component {
}
return isHonest
? verifyCert(superBlock)
: createFlashMessage({
type: 'info',
message:
'To claim a certification, you must first accept our academic ' +
'honesty policy'
});
: createFlashMessage(honestyInfoMessage);
};
return projectMap[certName]
.map(({ link, title, id }) => (
@ -284,18 +287,83 @@ class CertificationSettings extends Component {
};
// 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) {
const { updateLegacyCertificate } = this.props;
updateLegacyCertificate(values);
// make an object with keys as challenge ids and values as solutions
let idsToSolutions = {};
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 => {
const { username, isHonest, createFlashMessage, verifyCert } = this.props;
const { username, createFlashMessage, completedChallenges } = this.props;
const { superBlock } = first(legacyProjectMap[certName]);
const certLocation = `/certification/${username}/${superBlock}`;
const challengeTitles = legacyProjectMap[certName].map(item => item.title);
const { completedChallenges } = this.props;
const isCertClaimed = this.getUserIsCertMap()[certName];
const initialObject = {};
let filledforms = 0;
@ -321,19 +389,12 @@ class CertificationSettings extends Component {
const fullForm = filledforms === challengeTitles.length;
const createClickHandler = superBlock => e => {
const createClickHandler = certLocation => e => {
e.preventDefault();
if (isCertClaimed) {
return navigate(certLocation);
}
return isHonest
? verifyCert(superBlock)
: createFlashMessage({
type: 'info',
message:
'To claim a certification, you must first accept our academic ' +
'honesty policy'
});
return createFlashMessage(reallyWeirdErrorMessage);
};
const buttonStyle = {
@ -341,7 +402,7 @@ class CertificationSettings extends Component {
};
return (
<FullWidthRow key={certName}>
<FullWidthRow key={superBlock}>
<Spacer />
<h3>{certName}</h3>
<Form
@ -349,7 +410,7 @@ class CertificationSettings extends Component {
enableSubmit={fullForm}
formFields={challengeTitles}
hideButton={isCertClaimed}
id={certName}
id={superBlock}
initialValues={{
...initialObject
}}
@ -363,7 +424,7 @@ class CertificationSettings extends Component {
bsStyle='primary'
className={'col-xs-12'}
href={certLocation}
onClick={createClickHandler(superBlock)}
onClick={createClickHandler(certLocation)}
style={buttonStyle}
target='_blank'
>

View File

@ -316,7 +316,7 @@ export const reducer = handleActions(
}
};
},
[settingsTypes.updateLegacyCertificateComplete]: (state, { payload }) => {
[settingsTypes.updateLegacyCertComplete]: (state, { payload }) => {
const { appUsername } = state;
return {
...state,

View File

@ -6,7 +6,7 @@ import { createSettingsSagas } from './settings-sagas';
import { createUpdateMyEmailSaga } from './update-email-saga';
// prettier-ignore
import { createUpdateLegacyCertificateSaga } from
import { createUpdateLegacyCertSaga } from
'./update-legacy-certificate-saga';
export const ns = 'settings';
@ -31,7 +31,7 @@ export const types = createTypes(
...createAsyncTypes('submitNewAbout'),
...createAsyncTypes('submitNewUsername'),
...createAsyncTypes('updateMyEmail'),
...createAsyncTypes('updateLegacyCertificate'),
...createAsyncTypes('updateLegacyCert'),
...createAsyncTypes('updateUserFlag'),
...createAsyncTypes('submitProfileUI'),
...createAsyncTypes('verifyCert'),
@ -45,7 +45,7 @@ export const sagas = [
...createSettingsSagas(types),
...createUpdateMyEmailSaga(types),
...createDangerZoneSaga(types),
...createUpdateLegacyCertificateSaga(types)
...createUpdateLegacyCertSaga(types)
];
const checkForSuccessPayload = ({ type, payload }) =>
@ -78,15 +78,11 @@ export const updateMyEmail = createAction(types.updateMyEmail);
export const updateMyEmailComplete = createAction(types.updateMyEmailComplete);
export const updateMyEmailError = createAction(types.updateMyEmailError);
export const updateLegacyCertificate = createAction(
types.updateLegacyCertificate
);
export const updateLegacyCertificateComplete = createAction(
types.updateLegacyCertificateComplete
);
export const updateLegacyCertificateError = createAction(
types.updateLegacyCertificateError
export const updateLegacyCert = createAction(types.updateLegacyCert);
export const updateLegacyCertComplete = createAction(
types.updateLegacyCertComplete
);
export const updateLegacyCertError = createAction(types.updateLegacyCertError);
export const updateUserFlag = createAction(types.updateUserFlag);
export const updateUserFlagComplete = createAction(

View File

@ -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 { completedChallengesSelector, submitComplete } from '../';
import { legacyProjectMap } from '../../resources/certProjectMap';
import { putUpdateLegacyCert } from '../../utils/ajax';
import { submitComplete } from '../';
import { createFlashMessage } from '../../components/Flash/redux';
import standardErrorMessage from '../../utils/reallyWeirdErrorMessage';
import { updateLegacyCertificateError } 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;
}
import reallyWeirdErrorMessage from '../../utils/reallyWeirdErrorMessage';
import { updateLegacyCertError } from './';
function* updateLegacyCertSaga({
payload: { superBlock, challengesToUpdate }
}) {
// shape the body of the http call so it is consumable by api
const body = {
projects: {
[legacyCert]: challengesToUpdate
[superBlock]: challengesToUpdate
}
};
// shape to update completed challenges
// shape to update completed challenges in redux store
let reduxShape = [];
for (let obj in challengesToUpdate) {
if (challengesToUpdate.hasOwnProperty(obj)) {
@ -76,17 +24,16 @@ function* updateLegacyCertificateSaga({ payload }) {
}
try {
const { data: response } = yield call(putUpdateLegacyCertificate, body);
const { data: response } = yield call(putUpdateLegacyCert, body);
yield put(submitComplete({ challArray: reduxShape }));
yield put(createFlashMessage(response));
console.log(response);
} catch (e) {
yield put(updateLegacyCertificateError(e));
yield put(createFlashMessage(standardErrorMessage));
yield put(updateLegacyCertError(e));
yield put(createFlashMessage(reallyWeirdErrorMessage));
}
}
export function createUpdateLegacyCertificateSaga(types) {
return [
takeEvery(types.updateLegacyCertificate, updateLegacyCertificateSaga)
];
export function createUpdateLegacyCertSaga(types) {
return [takeEvery(types.updateLegacyCert, updateLegacyCertSaga)];
}

View File

@ -45,7 +45,7 @@ export function getArticleById(shortId) {
}
/** POST **/
export function putUpdateLegacyCertificate(body) {
export function putUpdateLegacyCert(body) {
return post('/update-my-projects', body);
}