Skip to content

Commit

Permalink
Merge branch 'freeCodeCamp:main' into update-step74-of-spreadsheet-pr…
Browse files Browse the repository at this point in the history
…oject
  • Loading branch information
sanskriti2005 committed Apr 28, 2024
2 parents 184f9a0 + 5cbe0b7 commit a8aef9a
Show file tree
Hide file tree
Showing 10,352 changed files with 196,700 additions and 30,027 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
7 changes: 7 additions & 0 deletions .github/workflows/e2e-playwright.yml
Expand Up @@ -143,3 +143,10 @@ jobs:
pnpm run start-ci &
sleep 10
npx playwright test --project=${{ matrix.browsers }}
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report-${{ matrix.browsers }}
path: playwright/reporter
retention-days: 30
4 changes: 0 additions & 4 deletions api-server/src/common/models/challenge.json
Expand Up @@ -29,10 +29,6 @@
"checksum": {
"type": "number"
},
"isBeta": {
"type": "boolean",
"description": "Show only during dev or on beta site. Completely omitted otherwise"
},
"isComingSoon": {
"type": "boolean",
"description": "Challenge shows in production, but is unreachable and disabled. Is reachable in beta/dev only if isBeta flag is set"
Expand Down
12 changes: 7 additions & 5 deletions api-server/src/common/models/user.js
Expand Up @@ -526,15 +526,17 @@ export default function initializeUser(User) {
Observable.fromPromise(userUpdate)
);
})
.map(
() =>
'Check your email and click the link we sent you to confirm' +
' your new email address.'
);
.map({
type: 'info',
message: dedent`Check your email and click the link we sent you to confirm your new email address.`
});
}

User.prototype.requestAuthEmail = requestAuthEmail;

/**
* @param {String} requestedEmail
*/
function requestUpdateEmail(requestedEmail) {
const newEmail = ensureLowerCaseString(requestedEmail);
const currentEmail = ensureLowerCaseString(this.email);
Expand Down
5 changes: 4 additions & 1 deletion api-server/src/server/boot/settings.js
Expand Up @@ -95,7 +95,10 @@ function updateMyEmail(req, res, next) {
} = req;
return user
.requestUpdateEmail(email)
.subscribe(message => res.json({ message }), next);
.subscribe(
message => res.json({ type: message.type, message: message.message }),
next
);
}

// Re-enable once we can handle the traffic
Expand Down
2 changes: 1 addition & 1 deletion api-server/src/server/middlewares/csurf.js
@@ -1,7 +1,7 @@
import csurf from 'csurf';

export const csrfOptions = {
domain: process.env.COOKIE_DOMAIN || 'localhost',
domain: process.env.COOKIE_DOMAIN,
sameSite: 'strict',
secure: process.env.FREECODECAMP_NODE_ENV === 'production'
};
Expand Down
2 changes: 1 addition & 1 deletion api-server/src/server/utils/getSetAccessToken.js
Expand Up @@ -8,7 +8,7 @@ export const jwtCookieNS = 'jwt_access_token';
export function createCookieConfig(req) {
return {
signed: !!req.signedCookies,
domain: process.env.COOKIE_DOMAIN || 'localhost'
domain: process.env.COOKIE_DOMAIN
};
}

Expand Down
15 changes: 14 additions & 1 deletion api-server/src/server/utils/getSetAccessToken.test.js
Expand Up @@ -12,14 +12,27 @@ describe('getSetAccessToken', () => {
const invalidJWTSecret = 'This is not correct secret';
const now = new Date(Date.now());
const theBeginningOfTime = new Date(0);
const domain = process.env.COOKIE_DOMAIN || 'localhost';
const domain = 'www.example.com';
const accessToken = {
id: '123abc',
userId: '456def',
ttl: 60000,
created: now
};

// https://stackoverflow.com/questions/48033841/test-process-env-with-jest
const OLD_ENV = process.env;

beforeEach(() => {
jest.resetModules(); // process is implicitly cached by Jest, so hence the reset
process.env = { ...OLD_ENV }; // Shallow clone that we can modify
process.env.COOKIE_DOMAIN = domain;
});

afterAll(() => {
process.env = OLD_ENV;
});

describe('getAccessTokenFromRequest', () => {
it('return `no token` error if no token is found', () => {
const req = mockReq({ headers: {}, cookie: {} });
Expand Down
19 changes: 19 additions & 0 deletions api/src/routes/certificate.test.ts
Expand Up @@ -627,6 +627,25 @@ describe('certificate routes', () => {
});
expect(response.status).toBe(200);
});

test('should return cert-not-found if there is no cert with that slug', async () => {
const response = await superRequest(
'/certificate/showCert/foobar/not-a-valid-cert-slug',
{
method: 'GET'
}
);
expect(response.body).toEqual({
messages: [
{
type: 'info',
message: 'flash.cert-not-found',
variables: { certSlug: 'not-a-valid-cert-slug' }
}
]
});
expect(response.status).toBe(404);
});
});
});
});
Expand Down
21 changes: 8 additions & 13 deletions api/src/routes/certificate.ts
Expand Up @@ -19,7 +19,6 @@ import {
} from '../../../shared/config/certification-settings';
import { normalizeChallenges, removeNulls } from '../utils/normalize';
import { SHOW_UPCOMING_CHANGES } from '../utils/env';
import { formatCertificationValidation } from '../utils/error-formatting';

const {
legacyFrontEndChallengeId,
Expand Down Expand Up @@ -287,15 +286,7 @@ export const unprotectedCertificateRoutes: FastifyPluginCallbackTypebox = (
fastify.get(
'/certificate/showCert/:username/:certSlug',
{
schema: schemas.certSlug,
errorHandler(error, request, reply) {
if (error.validation) {
void reply.code(400);
return formatCertificationValidation(error.validation);
} else {
fastify.errorHandler(error, request, reply);
}
}
schema: schemas.certSlug
},
async (req, reply) => {
try {
Expand All @@ -307,9 +298,13 @@ export const unprotectedCertificateRoutes: FastifyPluginCallbackTypebox = (
if (!isKnownCertSlug(certSlug)) {
void reply.code(404);
return reply.send({
type: 'info',
message: 'flash.cert-not-found',
variables: { certSlug }
messages: [
{
type: 'info',
message: 'flash.cert-not-found',
variables: { certSlug }
}
]
});
}

Expand Down
83 changes: 74 additions & 9 deletions api/src/routes/donate.test.ts
@@ -1,10 +1,12 @@
/* eslint-disable @typescript-eslint/naming-convention */
import type { Prisma } from '@prisma/client';
import {
createSuperRequest,
devLogin,
setupServer,
superRequest
superRequest,
defaultUserEmail
} from '../../jest.utils';
import { createUserInput } from '../utils/create-user';

const chargeStripeCardReqBody = {
paymentMethodId: 'UID',
Expand Down Expand Up @@ -45,6 +47,39 @@ jest.mock('stripe', () => {
});
});

const userWithoutProgress: Prisma.userCreateInput =
createUserInput(defaultUserEmail);

const userWithProgress: Prisma.userCreateInput = {
...createUserInput(defaultUserEmail),
completedChallenges: [
{
id: 'a6b0bb188d873cb2c8729495',
completedDate: 1520002973119,
solution: null,
challengeType: 5
},
{
id: '33b0bb188d873cb2c8729433',
completedDate: 4420002973122,
solution: null,
challengeType: 5
},
{
id: 'a5229172f011153519423690',
completedDate: 1520440323273,
solution: null,
challengeType: 5
},
{
id: 'a5229172f011153519423692',
completedDate: 1520440323274,
githubLink: '',
challengeType: 5
}
]
};

describe('Donate', () => {
setupServer();

Expand All @@ -54,6 +89,10 @@ describe('Donate', () => {
beforeEach(async () => {
const setCookies = await devLogin();
superPost = createSuperRequest({ method: 'POST', setCookies });
await fastifyTestInstance.prisma.user.updateMany({
where: { email: userWithProgress.email },
data: userWithProgress
});
});

describe('POST /donate/charge-stripe-card', () => {
Expand All @@ -77,9 +116,11 @@ describe('Donate', () => {
);

expect(response.body).toEqual({
type: 'UserActionRequired',
message: 'Payment requires user action',
client_secret: 'superSecret'
error: {
type: 'UserActionRequired',
message: 'Payment requires user action',
client_secret: 'superSecret'
}
});
expect(response.status).toBe(402);
});
Expand All @@ -93,8 +134,10 @@ describe('Donate', () => {
);

expect(response.body).toEqual({
type: 'PaymentMethodRequired',
message: 'Card has been declined'
error: {
type: 'PaymentMethodRequired',
message: 'Card has been declined'
}
});
expect(response.status).toBe(402);
});
Expand All @@ -111,6 +154,12 @@ describe('Donate', () => {
const failResponse = await superPost('/donate/charge-stripe-card').send(
chargeStripeCardReqBody
);
expect(failResponse.body).toEqual({
error: {
type: 'AlreadyDonatingError',
message: 'User is already donating.'
}
});
expect(failResponse.status).toBe(400);
});

Expand All @@ -121,10 +170,26 @@ describe('Donate', () => {
);
expect(response.status).toBe(500);
expect(response.body).toEqual({
type: 'danger',
message: 'Donation failed due to a server error.'
error: 'Donation failed due to a server error.'
});
});

it('should return 400 if user has not completed challenges', async () => {
await fastifyTestInstance.prisma.user.updateMany({
where: { email: userWithProgress.email },
data: userWithoutProgress
});
const failResponse = await superPost('/donate/charge-stripe-card').send(
chargeStripeCardReqBody
);
expect(failResponse.body).toEqual({
error: {
type: 'MethodRestrictionError',
message: `Donate using another method`
}
});
expect(failResponse.status).toBe(400);
});
});

describe('POST /donate/add-donation', () => {
Expand Down

0 comments on commit a8aef9a

Please sign in to comment.