feat: split rdbms into individual blocks and two challengeTypes (#44978)

* feat: split english rdbms into individual blocks

fix: stuff

fix: remove from partiallyComplete array on submit

fix: add suggestion

Update client/i18n/locales/english/translations.json

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/i18n/locales/english/intro.json

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/i18n/locales/english/intro.json

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/i18n/locales/english/intro.json

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

* fix: prettier

* fix: style suggestion

* Apply suggestions from code review

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
Tom
2022-02-11 09:39:27 -06:00
committed by GitHub
parent 226a8248b7
commit 57cf47dad4
267 changed files with 3832 additions and 2229 deletions

View File

@@ -13,7 +13,10 @@ import isNumeric from 'validator/lib/isNumeric';
import isURL from 'validator/lib/isURL';
import { environment, deploymentEnv } from '../../../../config/env.json';
import { fixCompletedChallengeItem } from '../../common/utils';
import {
fixCompletedChallengeItem,
fixPartiallyCompletedChallengeItem
} from '../../common/utils';
import { getChallenges } from '../utils/get-curriculum';
import { ifNoUserSend } from '../utils/middleware';
import {
@@ -134,6 +137,10 @@ export function buildUserUpdate(
)
};
updateData.$pull = {
partiallyCompletedChallenges: { id: challengeId }
};
if (
timezone &&
timezone !== 'UTC' &&
@@ -283,6 +290,27 @@ function projectCompleted(req, res, next) {
});
}
// CodeRoad cert project
if (completedChallenge.challengeType === 13) {
const { partiallyCompletedChallenges = [], completedChallenges = [] } =
user;
const isPartiallyCompleted = partiallyCompletedChallenges.some(
challenge => challenge.id === completedChallenge.id
);
const isCompleted = completedChallenges.some(
challenge => challenge.id === completedChallenge.id
);
if (!isPartiallyCompleted && !isCompleted) {
return res.status(403).json({
type: 'error',
message: 'You have to complete the project before you can submit a URL.'
});
}
}
return user
.getCompletedChallenges$()
.flatMap(() => {
@@ -345,6 +373,10 @@ function backendChallengeCompleted(req, res, next) {
.subscribe(() => {}, next);
}
const codeRoadChallenges = getChallenges().filter(
({ challengeType }) => challengeType === 12 || challengeType === 13
);
function createCoderoadChallengeCompleted(app) {
/* Example request coming from CodeRoad:
* req.body: { tutorialId: 'freeCodeCamp/learn-bash-by-building-a-boilerplate:v1.0.0' }
@@ -374,18 +406,14 @@ function createCoderoadChallengeCompleted(app) {
return res.send('Tutorial not hosted on freeCodeCamp GitHub account');
}
const codeRoadChallenges = getChallenges().filter(
challenge => challenge.challengeType === 12
);
// validate tutorial name is in codeRoadChallenges object
const tutorialInfo = codeRoadChallenges.find(tutorial =>
tutorial.url?.includes(tutorialRepoName)
const challenge = codeRoadChallenges.find(challenge =>
challenge.url?.includes(tutorialRepoName)
);
if (!tutorialInfo) return res.send('Tutorial name is not valid');
if (!challenge) return res.send('Tutorial name is not valid');
const tutorialMongoId = tutorialInfo?.id;
const { id: challengeId, challengeType } = challenge;
try {
// check if webhook token is in database
@@ -406,12 +434,43 @@ function createCoderoadChallengeCompleted(app) {
// submit challenge
const completedDate = Date.now();
const { completedChallenges = [], partiallyCompletedChallenges = [] } =
user;
const userUpdateInfo = buildUserUpdate(user, tutorialMongoId, {
id: tutorialMongoId,
completedDate
});
let userUpdateInfo = {};
const isCompleted = completedChallenges.some(
challenge => challenge.id === challengeId
);
// if CodeRoad cert project and not in completedChallenges,
// add to partiallyCompletedChallenges
if (challengeType === 13 && !isCompleted) {
const finalChallenge = {
id: challengeId,
completedDate
};
userUpdateInfo.updateData = {};
userUpdateInfo.updateData.$set = {
partiallyCompletedChallenges: uniqBy(
[
finalChallenge,
...partiallyCompletedChallenges.map(
fixPartiallyCompletedChallengeItem
)
],
'id'
)
};
// else, add to or update completedChallenges
} else {
userUpdateInfo = buildUserUpdate(user, challengeId, {
id: challengeId,
completedDate
});
}
const updatedUser = await user.updateAttributes(
userUpdateInfo?.updateData
);

View File

@@ -4,7 +4,10 @@ import { body } from 'express-validator';
import { pick } from 'lodash';
import { Observable } from 'rx';
import { fixCompletedChallengeItem } from '../../common/utils';
import {
fixCompletedChallengeItem,
fixPartiallyCompletedChallengeItem
} from '../../common/utils';
import { removeCookies } from '../utils/getSetAccessToken';
import { ifNoUser401, ifNoUserRedirectHome } from '../utils/middleware';
import {
@@ -99,11 +102,18 @@ function createReadSessionUser(app) {
queryUser &&
Observable.forkJoin(
queryUser.getCompletedChallenges$(),
queryUser.getPartiallyCompletedChallenges$(),
queryUser.getPoints$(),
Donation.getCurrentActiveDonationCount$(),
(completedChallenges, progressTimestamps, activeDonations) => ({
(
completedChallenges,
partiallyCompletedChallenges,
progressTimestamps,
activeDonations
) => ({
activeDonations,
completedChallenges,
partiallyCompletedChallenges,
progress: getProgress(progressTimestamps, queryUser.timezone)
})
);
@@ -111,16 +121,26 @@ function createReadSessionUser(app) {
() => !queryUser,
Observable.of({ user: {}, result: '' }),
Observable.defer(() => source)
.map(({ activeDonations, completedChallenges, progress }) => ({
user: {
...queryUser.toJSON(),
...progress,
completedChallenges: completedChallenges.map(
fixCompletedChallengeItem
)
},
sessionMeta: { activeDonations }
}))
.map(
({
activeDonations,
completedChallenges,
partiallyCompletedChallenges,
progress
}) => ({
user: {
...queryUser.toJSON(),
...progress,
completedChallenges: completedChallenges.map(
fixCompletedChallengeItem
),
partiallyCompletedChallenges: partiallyCompletedChallenges.map(
fixPartiallyCompletedChallengeItem
)
},
sessionMeta: { activeDonations }
})
)
.map(({ user, sessionMeta }) => ({
user: {
[user.username]: {

View File

@@ -32,6 +32,7 @@ export const publicUserProps = [
'linkedin',
'location',
'name',
'partiallyCompletedChallenges',
'points',
'portfolio',
'profileUI',