Skip to content

PROD-2741 Topcoder Academy MVP -> prod #41

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 53 commits into from
Aug 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
83b6a11
PROD-2033 #comment turn off ssr on dev #time 1h
brooketopcoder Jul 15, 2022
4801cb6
Merge pull request #26 from topcoder-platform/PROD-2033_hosted-api
brooketopcoder Jul 15, 2022
91f10c5
Merge branch 'dev' of github.com:topcoder-platform/freeCodeCamp into dev
testflyjets Jul 15, 2022
d398d32
PROD-2023 reenable SSR
testflyjets Jul 15, 2022
f7c71f4
PROD-2381 - remove the acceptedPrivacyTerms check and redirect
vas3a Jul 15, 2022
aef9419
PROD-2382 - replace mobile tabs with dropdown pane picker
vas3a Jul 18, 2022
aa7b208
turn off SSR
brooketopcoder Jul 18, 2022
c399a64
PROD-2492 #comment add ssr back #time 3h
brooketopcoder Jul 18, 2022
f96d06e
PROD-2492 #comment add logging of slugs that are created
brooketopcoder Jul 18, 2022
ea28cb5
PROD-2492 #comment layout selector logging #time 15
brooketopcoder Jul 18, 2022
cdf3828
PROD-2492 #comment more path logging #time 5m
brooketopcoder Jul 18, 2022
d9b3a9c
PROd-2492 #comment improve logging #time 10m
brooketopcoder Jul 18, 2022
6d2f376
PROD-2492 #comment add logging pathname on render body; remove obsole…
brooketopcoder Jul 18, 2022
b285137
PROD-2492 #comment use gatsby s3 plugin #time 1h
brooketopcoder Jul 18, 2022
8805020
PROD-2492 #comment use npx for gatsby s3 plugin #time 5m
brooketopcoder Jul 18, 2022
2a87e80
PROD-2492 #comment try doing build in same step as deploy #time 30m
brooketopcoder Jul 18, 2022
21b2329
PROD-2492 #comment remove some logging to trigger build #time 15m
brooketopcoder Jul 18, 2022
fc4d059
PROD-2492 #comment add S3 #time 5m
brooketopcoder Jul 19, 2022
a49fb93
PROD-2492 #comment add gatsby config
brooketopcoder Jul 19, 2022
6087cf9
PROD-2492 #comment add s3.params.json #time 30m
brooketopcoder Jul 19, 2022
3f1aa7b
PROD-2492 #comment add s3.routingRules.json
brooketopcoder Jul 19, 2022
9a7fdc5
PROD-2492 #comment revert gatsby deploy #time 15m
brooketopcoder Jul 19, 2022
dd3e251
Merge branch 'PROD-2382_tca-mobile-learn-lesson-view' into dev
vas3a Jul 19, 2022
ecf9579
Merge branch 'PROD-2381_remove-academic-honesty-policy-modal' into dev
vas3a Jul 19, 2022
bdc0833
PROD-2492 #comment roll back debugging code; remove -mfe from environ…
brooketopcoder Jul 19, 2022
c90ce00
Merge branch 'temp-dev' into dev
brooketopcoder Jul 19, 2022
a872f45
remove lessons and modules from responsive web design course for testing
brooketopcoder Jul 20, 2022
46a102a
Merge pull request #29 from topcoder-platform/remove-lessons-for-qa
brooketopcoder Jul 20, 2022
386867d
PROD-2553 fix color for primary button on focus
vas3a Jul 21, 2022
f0659eb
Merge pull request #30 from topcoder-platform/PROD-2553_button-color-…
brooketopcoder Jul 21, 2022
00093d0
PROD-2560 - fix issue where hints flash when you resubmit
vas3a Jul 22, 2022
73e980b
Merge pull request #31 from topcoder-platform/PROD-2560_check_submit_…
brooketopcoder Jul 22, 2022
6ecc2e0
PROD-2456 #comment add original course back; add QA shortened course;…
brooketopcoder Jul 22, 2022
bd46454
PROD-2456 clean up
brooketopcoder Jul 22, 2022
86a30a2
Merge pull request #32 from topcoder-platform/PROD-2456_orig-course
brooketopcoder Jul 22, 2022
fdd5407
PROD-2562 - prevent editor from navigating away on last step of the c…
vas3a Jul 25, 2022
209db3a
lint
vas3a Jul 25, 2022
c8c9b72
remove console.log
vas3a Jul 25, 2022
52f5f76
PROD-2585 - Fix issue with fcc reserved & get help link
vas3a Jul 25, 2022
594238f
PROD-2606 - fix height of preview iframe
vas3a Jul 25, 2022
6902061
PROD-2456 configure shortened course #time 3h
brooketopcoder Jul 25, 2022
91fa535
Merge pull request #36 from topcoder-platform/PROD-2456_orig-course
brooketopcoder Jul 25, 2022
cb6d7d6
Merge pull request #33 from topcoder-platform/PROD-2562_certification…
vas3a Jul 26, 2022
752e119
Merge pull request #34 from topcoder-platform/PROD-2585_ui-assessment…
vas3a Jul 26, 2022
c208bab
Merge pull request #35 from topcoder-platform/PROD-2606_preview-heigh…
vas3a Jul 26, 2022
304c826
PROD-2504 - prevent FCC donate modal
vas3a Jul 26, 2022
1cbf552
PROd-2456 #comment fix padding on checkmark on challenge description …
brooketopcoder Jul 26, 2022
9a09040
Adds new Topcoder README to describe the application
testflyjets Jul 26, 2022
cb29c19
Merge pull request #37 from topcoder-platform/PROD-2504_prevent-donat…
vas3a Jul 26, 2022
058bfc2
Merge pull request #38 from topcoder-platform/PROD-2456_orig-course
brooketopcoder Jul 26, 2022
6511a4a
Merge pull request #39 from topcoder-platform/PROD-2652-mongodb-vpc-p…
testflyjets Jul 26, 2022
fb93fdc
PROD-2649 - handle mobile fixes
vas3a Aug 1, 2022
b34b5a6
Merge pull request #40 from topcoder-platform/PROD-2649_mobile-fixes
vas3a Aug 1, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// Define Application name
def APPNAME = "freecodecamp-mfe"
def APPNAME = "freecodecamp"

// Define which branch build and deploy need to run in the below array

def branchfilter = ['dev', 'prod']

if (!branchfilter.contains(env.BRANCH_NAME)) {
Expand All @@ -13,7 +12,7 @@ if (!branchfilter.contains(env.BRANCH_NAME)) {
return
}

//Define branch specific var
// Define branch specific vars
if (env.BRANCH_NAME == 'dev') {
DEPLOY_ENV = 'DEV'
LOGICAL_ENV = 'dev'
Expand All @@ -24,7 +23,6 @@ if (env.BRANCH_NAME == 'dev') {
ENABLE_CACHE = false
}

// NOTE: main/prod is not supported yet
if (env.BRANCH_NAME == 'prod') {
DEPLOY_ENV = 'PROD'
LOGICAL_ENV = 'prod'
Expand Down Expand Up @@ -126,7 +124,7 @@ pipeline {
"""
}
}
stage('appdeploy')
stage('appdeploy')
{
//Deploying app
when { expression { IS_APP_DEPLOY } }
Expand All @@ -137,10 +135,10 @@ pipeline {
sh """
#!/bin/bash
./master_deploy.sh -d CFRONT -e $DEPLOY_ENV -c $ENABLE_CACHE
"""
"""
}
}
stage('apideploy')
stage('apideploy')
{
//Deploying app
when { expression { IS_API_DEPLOY } }
Expand All @@ -153,7 +151,7 @@ pipeline {
sed -i '/node_modules/d' ./.dockerignore
docker build -f docker/api/ECSDockerfile -t $APPNAME-api:latest .
./master_deploy.sh -d ECS -e $DEPLOY_ENV -t latest -s ${LOGICAL_ENV}-${APPNAME}-appvar -i ${APPNAME}-api
"""
"""
}
}
}
Expand Down
54 changes: 54 additions & 0 deletions README-TOPCODER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
## Topcoder freeCodeCamp modifications README

This file describes the modifications Topcoder made to the freeCodeCamp.org application to support providing FCC course content within the Topcoder Academy and Learning Paths effort. It also provides details about how the application is deployed and hosted in our AWS cloud environment.

## Table of Contents

- [Learning Platform](#the-learning-platform)
- [Learning Platform API](#the-learning-platform-api)
- [MongoDB Configuration](#mongodb-configuration)
- [CI/CD Configuration](#cicd-configuration)

### The Learning Platform

The freeCodeCamp application is hosted in the [platform-ui](https://github.com/topcoder-platform/platform-ui) application, within the [Learn tool](https://github.com/topcoder-platform/platform-ui/tree/dev/src-ts/tools/learn). The Learn application uses the [learning-paths-api](https://github.com/topcoder-platform/learning-paths-api) to manage and display course metadata, such as the certifications and courses available, and to track user course progress independently of the progress tracking performed by the hosted freeCodeCamp application.

The freeCodeCamp code editors and course material viewing tools are hosted inside an iframe and communicate with the parent platform-ui application via messages, which in turn trigger calls to the learning paths API. For example, when a user completes a course, a course completion message is sent to from the freeCodeCamp application to the parent platform-ui app, which then makes an API call to record the event in the Topcoder Academy datastore.

#### Build and Deploy Process

The freeCodeCamp application is statically built during deployment and hosted in AWS S3 via a Cloudfront distribution. The S3 bucket had to be specially configured to support this type of deployment, in particular to allow the correct URLs to be used by the platform-ui and the embedded freeCodeCamp application.

#### Authentication

The application natively uses Auth0 authentication, which we had to modify to use Topcoder's login and authentication process. (details)

(TODO - more detail here on the major things we did)

### The Learning Platform API

The freeCodeCamp API, which is responsible for managing user progress and sessions in MongoDB, was modified to support Topcoder Auth0 authentication and to reflect the path at which the API was deployed in AWS.

#### Build and Deploy Process

The API is deployed via AWS Elastic Container Service. See the [api/ECSDockerfile](./docker/api/ECSDockerfile) for details of this configuration. A key thing to note is that the freeCodeCamp application and API rely in the presence of a .env file that contains all of the required environment variables.

Topcoder's standard deployment process is to store sensitive deployment variables (include API keys, secrets, tokens, etc.) in an S3 bucket and to programmatically retrieve them and inject those values as environment variables into the Docker container at build time. However, this approach does not work for freeCodeCamp due to the reliance on the existence of the .env file in the project root. We modified the build and deploy process to include a copy of the .env file in S3 that is copied into the project root and available for the application when it is started.

### MongoDB Configuration

The freeCodeCamp application natively uses MongoDB to track user sessions and course progress. To support our deployment of freeCodeCamp, an instance of MongoDB's cloud [Atlas](https://www.mongodb.com/atlas) service was stood-up. Key things to note about this:

- This instance was configured via the [AWS Marketplace](https://aws.amazon.com/marketplace/pp/prodview-pp445qepfdy34?ref_=aws-mp-console-subscription-detail) so that the Atlas instance billing would flow to the associated AWS account.
- An initial attempt was made to use an Atlas "pay as you go" serverless instance of MongoDB since costs would be very low. However, two issues arose that prevented this:
- The MongoDB version that Atlas serverless uses was incompatible with freeCodeCamp's NodeJS mongodb driver package
- AWS VPC peering cannot be used with a serverless instance
- As a result of these issues we settled on an M10 clustered instance of MongoDB.

In order to connect the [freeCodeCamp API](#learning-platform-api) to the MongoDB Atlas instance, VPC peering was established between the AWS VPC into which the freeCodeCamp API was deployed and the Atlas instance's VPC. The [VPC peering documentation](https://www.mongodb.com/docs/atlas/security-vpc-peering/) on their website is comprehensive and accurate. We followed this process to establish a secure connection from the API to the database.

### CI/CD Configuration

We initially attempted to deploy the freeCodeCamp application and API via our standard CircleCI system, however we were never able to get this to work properly. The application build failed repeatedly at various points and was never successful.

Our DevOps team stood-up a new Jenkins CI/CD system in an AWS EC2 instance (see the [Jenkinsfile](./Jenkinsfile) in the project root for details) and this was successful. However, the build and deployment of the application and API currently takes over 20 minutes. We have an outstanding request with the DevOps team to address this.
1 change: 0 additions & 1 deletion api-server/src/server/middlewares/request-authorization.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ export default function getRequestAuthorisation({
const { origin } = getRedirectParams(req);
const { path } = req;
if (!isAllowedPath(path)) {
console.log('##### path:', path);
const { accessToken, error, jwt } = getAccessTokenFromRequest(
req,
jwtSecret
Expand Down
10 changes: 9 additions & 1 deletion client/gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ module.exports = {
icon: 'src/assets/images/square_puck.png'
}
},
'gatsby-plugin-remove-serviceworker'
'gatsby-plugin-remove-serviceworker',
{
resolve: `gatsby-plugin-s3`,
options: {
bucketName: 'freecodecamp-mfe.topcoder-dev.com',
hostname: 'freecodecamp-mfe.topcoder-dev.com',
protocol: 'https'
}
}
]
};
83 changes: 65 additions & 18 deletions client/i18n/locales/english/intro.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,31 +80,36 @@
"intro": [
"This is one of the required projects to earn your certification.",
"For this project, you will build a tribute page for a subject of your choosing, fictional or real."
] },
]
},
"build-a-personal-portfolio-webpage-project": {
"title": "Personal Portfolio Webpage",
"intro": [
"This is one of the required projects to earn your certification.",
"For this project, you will build your own personal portfolio page."
] },
]
},
"build-a-product-landing-page-project": {
"title": "Product Landing Page",
"intro": [
"This is one of the required projects to earn your certification.",
"For this project, you will build a product landing page to market a product of your choice."
] },
]
},
"build-a-survey-form-project": {
"title": "Survey Form",
"intro": [
"This is one of the required projects to earn your certification.",
"For this project, you will build a survey form to collect data from your users."
] },
]
},
"build-a-technical-documentation-page-project": {
"title": "Technical Documentation Page",
"intro": [
"This is one of the required projects to earn your certification.",
"For this project, you will build a technical documentation page to serve as instruction or reference for a topic."
] },
]
},
"learn-html-by-building-a-cat-photo-app": {
"title": "Learn HTML by Building a Cat Photo App",
"intro": [
Expand Down Expand Up @@ -181,24 +186,66 @@
"In this course, you'll use typography to build a nutrition label webpage. You'll learn how to style text, adjust line height, and position your text using CSS."
]
},
"learn-css-transforms-by-building-a-penguin": { "title": "Learn CSS Transforms by Building a Penguin", "intro": [
"You can transform HTML elements to create appealing designs that draw your reader's eye. You can use transforms to rotate elements, scale them, and more.",
"In this course, you'll build a penguin. You'll use CSS transforms to position and resize the parts of your penguin, create a background, and animate your work."
] },
"learn-css-animation-by-building-a-ferris-wheel": { "title": "Learn CSS Animation by Building a Ferris Wheel", "intro": [
"You can use CSS animation to draw attention to specific sections of your webpage and make it more engaging.",
"In this course, you'll build a Ferris wheel. You'll learn how to use CSS to animate elements, transform them, and adjust their speed."
] },
"learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet": { "title": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet", "intro": [
"You can use CSS pseudo selectors to change specific HTML elements.",
"In this course, you'll build a balance sheet using pseudo selectors. You'll learn how to change the style of an element when you hover over it with your mouse, and trigger other events on your webpage."
] },
"learn-css-transforms-by-building-a-penguin": {
"title": "Learn CSS Transforms by Building a Penguin",
"intro": [
"You can transform HTML elements to create appealing designs that draw your reader's eye. You can use transforms to rotate elements, scale them, and more.",
"In this course, you'll build a penguin. You'll use CSS transforms to position and resize the parts of your penguin, create a background, and animate your work."
]
},
"learn-css-animation-by-building-a-ferris-wheel": {
"title": "Learn CSS Animation by Building a Ferris Wheel",
"intro": [
"You can use CSS animation to draw attention to specific sections of your webpage and make it more engaging.",
"In this course, you'll build a Ferris wheel. You'll learn how to use CSS to animate elements, transform them, and adjust their speed."
]
},
"learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet": {
"title": "Learn More About CSS Pseudo Selectors By Building A Balance Sheet",
"intro": [
"You can use CSS pseudo selectors to change specific HTML elements.",
"In this course, you'll build a balance sheet using pseudo selectors. You'll learn how to change the style of an element when you hover over it with your mouse, and trigger other events on your webpage."
]
},
"learn-css-colors-by-building-a-set-of-colored-markers": {
"title": "Learn CSS Colors by Building a Set of Colored Markers",
"intro": [
"Selecting the correct colors for your webpage can greatly improve the aesthetic appeal to your readers.",
"In this course, you'll build a set of colored markers. You'll learn different ways to set color values and how to pair colors with each other."
] }
]
}
}
},
"2022/responsive-web-design-qa": {
"title": "(New) Responsive Web Design QA",
"intro": [
"In this Responsive Web Design Certification, you'll learn the languages that developers use to build webpages: HTML (Hypertext Markup Language) for content, and CSS (Cascading Style Sheets) for design.",
"First, you'll build a cat photo app to learn the basics of HTML and CSS. Later, you'll learn modern techniques like CSS variables by building a penguin, and best practices for accessibility by building a web form.",
"Finally, you'll learn how to make webpages that respond to different screen sizes by building a Twitter card with Flexbox, and a complex blog layout with CSS Grid."
],
"note": "Note: Some browser extensions, such as ad-blockers and dark mode extensions can interfere with the tests. If you face issues, we recommend disabling extensions that modify the content or layout of pages, while taking the course.",
"blocks": {
"build-a-personal-portfolio-webpage-project-qa": {
"title": "Personal Portfolio Webpage QA",
"intro": [
"This is one of the required projects to earn your certification.",
"For this project, you will build your own personal portfolio page."
]
},
"learn-html-by-building-a-cat-photo-app-qa": {
"title": "Learn HTML by Building a Cat Photo App QA",
"intro": [
"HTML tags give a webpage its structure. You can use HTML tags to add photos, buttons, and other elements to your webpage.",
"In this course, you'll learn the most common HTML tags by building your own cat photo app."
]
},
"learn-basic-css-by-building-a-cafe-menu-qa": {
"title": "Learn Basic CSS by Building a Cafe Menu QA",
"intro": [
"CSS tells the browser how to display your webpage. You can use CSS to set the color, font, size, and other aspects of HTML elements.",
"In this course, you'll learn CSS by designing a menu page for a cafe webpage."
]
}
}
},
"javascript-algorithms-and-data-structures": {
Expand Down
36 changes: 36 additions & 0 deletions client/src/assets/icons/chevron-down.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import { useTranslation } from 'react-i18next';

function ExternalLink(
props: JSX.IntrinsicAttributes & React.SVGProps<SVGSVGElement>
): JSX.Element {
const { t } = useTranslation();

return (
<svg
width='16'
height='10'
viewBox='0 0 16 10'
xmlns='http://www.w3.org/2000/svg'
{...props}
>
<title>{t('icons.chevron-down')}</title>
<path
fillRule='evenodd'
clipRule='evenodd'
d={
'M0.292893 0.792893C0.683417 0.402369 1.31658 0.402369 1.70711 0.792893L8 ' +
'7.08579L14.2929 0.792893C14.6834 0.402369 15.3166 0.402369 15.7071 ' +
'0.792893C16.0976 1.18342 16.0976 1.81658 15.7071 2.20711L8.70711 ' +
'9.20711C8.31658 9.59763 7.68342 9.59763 7.29289 9.20711L0.292893 ' +
'2.20711C-0.0976311 1.81658 -0.0976311 1.18342 0.292893 0.792893Z'
}
fill='#137D60'
/>
</svg>
);
}

ExternalLink.displayName = 'ExternalLink';

export default ExternalLink;
4 changes: 3 additions & 1 deletion client/src/assets/icons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ const generateIconComponent = (
className: string
): JSX.Element => {
// fallback in case super block doesn't exist and for tests
const Icon = iconMap[superBlock] ? iconMap[superBlock] : ResponsiveDesign;
const Icon = iconMap[superBlock as keyof typeof iconMap]
? iconMap[superBlock as keyof typeof iconMap]
: ResponsiveDesign;

return <Icon className={className} />;
};
Expand Down
1 change: 1 addition & 0 deletions client/src/components/layouts/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ input[type='submit']:hover,
.btn-primary.focus {
background-color: var(--tc-turq-140);
outline: 0 none;
color: var(--tc-white);
}

.btn-tab-primary:focus,
Expand Down
32 changes: 3 additions & 29 deletions client/src/components/layouts/learn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@ import { Loader } from '../../components/helpers';
import {
userSelector,
userFetchStateSelector,
isSignedInSelector,
tryToShowDonationModal
isSignedInSelector
} from '../../redux';
import DonateModal from '../Donation/donation-modal';
import createRedirect from '../create-redirect';

import './prism.css';
import './prism-night.css';
Expand Down Expand Up @@ -38,32 +35,16 @@ const mapStateToProps = createSelector(
})
);

const mapDispatchToProps = {
tryToShowDonationModal
};

const RedirectEmailSignUp = createRedirect('/email-sign-up');
const mapDispatchToProps = {};

type LearnLayoutProps = {
isSignedIn?: boolean;
fetchState: FetchState;
user: User;
tryToShowDonationModal: () => void;
children?: React.ReactNode;
};

function LearnLayout({
isSignedIn,
fetchState,
user,
tryToShowDonationModal,
children
}: LearnLayoutProps): JSX.Element {
useEffect(() => {
tryToShowDonationModal();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

function LearnLayout({ fetchState, children }: LearnLayoutProps): JSX.Element {
useEffect(() => {
return () => {
const metaTag = document.querySelector(`meta[name="robots"]`);
Expand All @@ -77,19 +58,12 @@ function LearnLayout({
return <Loader fullScreen={true} />;
}

if (isSignedIn && !user.acceptedPrivacyTerms) {
return <RedirectEmailSignUp />;
}

return (
<>
<Helmet>
<meta content='noindex' name='robots' />
</Helmet>
<main id='learn-app-wrapper'>{children}</main>
{/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
/* @ts-ignore */}
<DonateModal />
</>
);
}
Expand Down
3 changes: 3 additions & 0 deletions client/src/components/layouts/variables.css
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@
--tc-link-blue-light: #5fb7ee;
--tc-black: #000;
--tc-black-100: #2a2a2a;
--tc-black-20: #d4d4d4;
--tc-black-10: #e9e9e9;
--tc-black-5: #f4f4f4;
--tc-blue-140: #16679a;
--tc-blue-25: #bae1f9;
--tc-blue-10: #eaf6fd;
}

.dark-palette {
Expand Down
Loading