Skip to content

Commit 95cc4a2

Browse files
Merge pull request #728 from freeCodeCamp/main
Create a new pull request by comparing changes across two branches
2 parents 9147889 + dc4c919 commit 95cc4a2

File tree

776 files changed

+27618
-7001
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

776 files changed

+27618
-7001
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Checklist:
55
- [ ] I have read and followed the [contribution guidelines](https://contribute.freecodecamp.org).
66
- [ ] I have read and followed the [how to open a pull request guide](https://contribute.freecodecamp.org/how-to-open-a-pull-request/).
77
- [ ] My pull request targets the `main` branch of freeCodeCamp.
8-
- [ ] I have tested these changes either locally on my machine, or GitPod.
8+
- [ ] I have tested these changes either locally on my machine, or Gitpod.
99

1010
<!--If your pull request closes a GitHub issue, replace the XXXXX below with the issue number.-->
1111

.github/workflows/build-images.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
matrix:
1111
node-version: [20.x]
1212
apps: [api]
13-
site_tlds: [dev]
13+
site_tlds: [dev, org]
1414
fail-fast: false
1515

1616
steps:

.gitpod.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ tasks:
3535
export API_LOCATION=$(gp url 3000)
3636
export CHALLENGE_EDITOR_API_LOCATION=$(gp url 3200)
3737
export CHALLENGE_EDITOR_CLIENT_LOCATION=$(gp url 3300)
38+
export CHALLENGE_EDITOR_LEARN_CLIENT_LOCATION=$(gp url 8000)
3839
' >> ~/.bashrc;
3940
exit;
4041

.lintstagedrc.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ module.exports = {
2525
];
2626
}
2727
},
28-
'*.!(js|ts|tsx)': files => {
28+
'*.!(js|ts|tsx|css)': files => {
2929
if (completedStages.has('not-js')) return [];
3030

3131
if (files.length > 10) {
@@ -49,5 +49,16 @@ module.exports = {
4949
filename => `node ./tools/scripts/lint/index.js '${filename}'`
5050
);
5151
}
52+
},
53+
54+
'*.css': files => {
55+
if (completedStages.has('css')) return [];
56+
57+
if (files.length > 10) {
58+
completedStages.add('css');
59+
return 'pnpm run stylelint --fix .';
60+
} else {
61+
return files.map(filename => `stylelint '${filename}'`);
62+
}
5263
}
5364
};

api-server/src/common/utils/constantStrings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"aboutUrl": "https://www.freecodecamp.org/about",
3-
"defaultProfileImage": "https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png",
3+
"defaultProfileImage": "https://cdn.freecodecamp.org/platform/universal/camper-image-placeholder.png",
44
"donateUrl": "https://www.freecodecamp.org/donate",
55
"forumUrl": "https://forum.freecodecamp.org",
66
"githubUrl": "https://github.com/freecodecamp/freecodecamp",

api/__mocks__/env-exam.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,8 @@ export const exam: EnvExam = {
339339
id: examId,
340340
config,
341341
questionSets,
342-
prerequisites: ['67112fe1c994faa2c26d0b1d']
342+
prerequisites: ['67112fe1c994faa2c26d0b1d'],
343+
deprecated: false
343344
};
344345

345346
export async function seedEnvExam() {
@@ -379,3 +380,9 @@ export async function seedEnvExamAttempt() {
379380
data: examAttempt
380381
});
381382
}
383+
384+
export async function seedExamEnvExamAuthToken() {
385+
return fastifyTestInstance.prisma.examEnvironmentAuthorizationToken.create({
386+
data: { userId: defaultUserId, expireAt: new Date(Date.now() + 60000) }
387+
});
388+
}

api/jest.utils.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -127,16 +127,6 @@ const indexData: IndexData[] = [
127127
collection: 'Survey',
128128
indexes: [{ key: { userId: 1 }, name: 'userId_1' }]
129129
},
130-
{
131-
collection: 'UserRateLimit',
132-
indexes: [
133-
{
134-
key: { expirationDate: 1 },
135-
name: 'expirationDate_1',
136-
expireAfterSeconds: 0
137-
}
138-
]
139-
},
140130
{
141131
collection: 'UserToken',
142132
indexes: [{ key: { userId: 1 }, name: 'userId_1' }]

api/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
"@fastify/cookie": "9.4.0",
1010
"@fastify/csrf-protection": "6.4.1",
1111
"@fastify/oauth2": "7.8.1",
12-
"@fastify/rate-limit": "9.1.0",
1312
"@fastify/swagger": "8.14.0",
1413
"@fastify/swagger-ui": "1.10.2",
1514
"@fastify/type-provider-typebox": "3.6.0",
15+
"@growthbook/growthbook": "1.3.1",
1616
"@immobiliarelabs/fastify-sentry": "7.1.1",
1717
"@prisma/client": "5.5.2",
1818
"ajv": "8.12.0",
@@ -32,7 +32,6 @@
3232
"nodemon": "2.0.22",
3333
"pino-pretty": "10.2.3",
3434
"query-string": "7.1.3",
35-
"rate-limit-mongo": "^2.3.2",
3635
"stripe": "16.0.0",
3736
"validator": "13.11.0"
3837
},
@@ -80,8 +79,9 @@
8079
"test": "jest --force-exit",
8180
"prisma": "dotenv -e ../.env prisma",
8281
"postinstall": "prisma generate",
83-
"lint": "cd .. && eslint api/src --max-warnings 0",
8482
"generate-exams": "tsx src/exam-environment/generate/index.ts",
83+
"deprecate-exam": "tsx src/exam-environment/generate/deprecate.ts",
84+
"insert-exam": "tsx src/exam-environment/generate/insert.ts",
8585
"seed:env-exam": "tsx src/exam-environment/seed/index.ts"
8686
},
8787
"version": "0.0.1"

api/prisma/schema.prisma

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ model EnvExam {
166166
config EnvConfig
167167
/// ObjectIds for required challenges/blocks to take the exam
168168
prerequisites String[] @db.ObjectId
169+
/// If `deprecated`, the exam should no longer be considered for users
170+
deprecated Boolean
169171
170172
// Relations
171173
generatedExams EnvGeneratedExam[]
@@ -365,14 +367,6 @@ model Donation {
365367
@@index([userId], map: "userId_1")
366368
}
367369

368-
model UserRateLimit {
369-
id String @id @map("_id")
370-
counter Int
371-
expirationDate DateTime @db.Date
372-
373-
@@index([expirationDate], map: "expirationDate_1")
374-
}
375-
376370
model UserToken {
377371
id String @id @map("_id")
378372
created DateTime @db.Date
@@ -390,7 +384,7 @@ model ExamEnvironmentAuthorizationToken {
390384
userId String @unique @db.ObjectId
391385
392386
// Relations
393-
user user @relation(fields: [userId], references: [id])
387+
user user @relation(fields: [userId], references: [id], onDelete: Cascade)
394388
}
395389

396390
model sessions {

api/src/app.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import fastifyAccepts from '@fastify/accepts';
22
import fastifySwagger from '@fastify/swagger';
33
import fastifySwaggerUI from '@fastify/swagger-ui';
44
import type { TypeBoxTypeProvider } from '@fastify/type-provider-typebox';
5+
import { GrowthBook } from '@growthbook/growthbook';
56
import Ajv from 'ajv';
67
import addFormats from 'ajv-formats';
78
import uriResolver from 'fast-uri';
@@ -28,6 +29,7 @@ import errorHandling from './plugins/error-handling';
2829
import csrf from './plugins/csrf';
2930
import notFound from './plugins/not-found';
3031
import shadowCapture from './plugins/shadow-capture';
32+
import growthBook from './plugins/growth-book';
3133

3234
import * as publicRoutes from './routes/public';
3335
import * as protectedRoutes from './routes/protected';
@@ -39,7 +41,9 @@ import {
3941
FCC_ENABLE_SWAGGER_UI,
4042
FCC_ENABLE_SHADOW_CAPTURE,
4143
FCC_ENABLE_EXAM_ENVIRONMENT,
42-
FCC_ENABLE_SENTRY_ROUTES
44+
FCC_ENABLE_SENTRY_ROUTES,
45+
GROWTHBOOK_FASTIFY_API_HOST,
46+
GROWTHBOOK_FASTIFY_CLIENT_KEY
4347
} from './utils/env';
4448
import { isObjectID } from './utils/validation';
4549
import {
@@ -55,6 +59,12 @@ type FastifyInstanceWithTypeProvider = FastifyInstance<
5559
TypeBoxTypeProvider
5660
>;
5761

62+
declare module 'fastify' {
63+
interface FastifyInstance {
64+
gb: GrowthBook;
65+
}
66+
}
67+
5868
// Options that fastify uses
5969
const ajv = new Ajv({
6070
coerceTypes: 'array', // change data type of data to match type keyword
@@ -99,12 +109,17 @@ export const build = async (
99109
await fastify.register(cookies);
100110
await fastify.register(csrf);
101111

112+
await fastify.register(growthBook, {
113+
apiHost: GROWTHBOOK_FASTIFY_API_HOST,
114+
clientKey: GROWTHBOOK_FASTIFY_CLIENT_KEY
115+
});
116+
102117
const provider =
103118
EMAIL_PROVIDER === 'ses' ? new SESProvider() : new NodemailerProvider();
104119
void fastify.register(mailer, { provider });
105120

106121
// Swagger plugin
107-
if (FCC_ENABLE_SWAGGER_UI) {
122+
if (FCC_ENABLE_SWAGGER_UI ?? fastify.gb.isOn('swagger-ui')) {
108123
void fastify.register(fastifySwagger, {
109124
openapi: {
110125
openapi: '3.1.0',
@@ -132,7 +147,7 @@ export const build = async (
132147
fastify.log.info(`Swagger UI available at ${API_LOCATION}/documentation`);
133148
}
134149

135-
if (FCC_ENABLE_SHADOW_CAPTURE) {
150+
if (FCC_ENABLE_SHADOW_CAPTURE ?? fastify.gb.isOn('shadow-capture')) {
136151
void fastify.register(shadowCapture);
137152
}
138153

@@ -189,7 +204,7 @@ export const build = async (
189204
}
190205
});
191206

192-
if (FCC_ENABLE_EXAM_ENVIRONMENT) {
207+
if (FCC_ENABLE_EXAM_ENVIRONMENT ?? fastify.gb.isOn('exam-environment')) {
193208
void fastify.register(function (fastify, _opts, done) {
194209
fastify.addHook('onRequest', fastify.authorizeExamEnvironmentToken);
195210

@@ -199,7 +214,7 @@ export const build = async (
199214
void fastify.register(examEnvironmentOpenRoutes);
200215
}
201216

202-
if (FCC_ENABLE_SENTRY_ROUTES) {
217+
if (FCC_ENABLE_SENTRY_ROUTES ?? fastify.gb.isOn('sentry-routes')) {
203218
void fastify.register(publicRoutes.sentryRoutes);
204219
}
205220

0 commit comments

Comments
 (0)