mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2025-12-23 21:04:36 -05:00
feat(api): migrate to esm (#61915)
This commit is contained in:
committed by
GitHub
parent
68614b43a9
commit
bed3811952
5
.gitignore
vendored
5
.gitignore
vendored
@@ -153,10 +153,6 @@ jspm_packages/
|
||||
|
||||
### Generated config files ###
|
||||
shared/config/curriculum.json
|
||||
shared/config/*.js
|
||||
|
||||
### Generated utils files ###
|
||||
shared/utils/*.js
|
||||
|
||||
### Old Generated files ###
|
||||
# These files are no longer generated by the client, but can
|
||||
@@ -200,6 +196,7 @@ curriculum/curricula.json
|
||||
curriculum/dist
|
||||
curriculum/build
|
||||
curriculum/test/blocks-generated
|
||||
shared-dist
|
||||
|
||||
### Playwright ###
|
||||
|
||||
|
||||
@@ -19,3 +19,4 @@ shared/utils/get-lines.test.js
|
||||
shared/utils/is-audited.js
|
||||
shared/utils/validate.js
|
||||
shared/utils/validate.test.js
|
||||
shared-dist
|
||||
|
||||
@@ -9,8 +9,8 @@ import {
|
||||
ExamEnvironmentChallenge
|
||||
} from '@prisma/client';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import { defaultUserId } from '../vitest.utils';
|
||||
import { examEnvironmentPostExamAttempt } from '../src/exam-environment/schemas';
|
||||
import { defaultUserId } from '../vitest.utils.js';
|
||||
import { examEnvironmentPostExamAttempt } from '../src/exam-environment/schemas/index.js';
|
||||
|
||||
export const oid = () => new ObjectId().toString();
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
"@sentry/node": "9.1.0",
|
||||
"@sinclair/typebox": "^0.34.33",
|
||||
"@types/pino": "^7.0.5",
|
||||
"ajv": "8.12.0",
|
||||
"ajv-formats": "2.1.1",
|
||||
"ajv": "8.17.1",
|
||||
"ajv-formats": "3.0.1",
|
||||
"date-fns": "4.1.0",
|
||||
"date-fns-tz": "3.2.0",
|
||||
"dotenv": "16.4.5",
|
||||
@@ -28,6 +28,7 @@
|
||||
"joi": "17.12.2",
|
||||
"jsonwebtoken": "9.0.2",
|
||||
"lodash": "4.17.21",
|
||||
"lodash-es": "4.17.21",
|
||||
"mongodb": "6.10.0",
|
||||
"nanoid": "3",
|
||||
"no-profanity": "1.5.1",
|
||||
@@ -36,12 +37,13 @@
|
||||
"pino-pretty": "10.2.3",
|
||||
"query-string": "7.1.3",
|
||||
"stripe": "16.0.0",
|
||||
"validator": "13.11.0"
|
||||
"validator": "13.15.15"
|
||||
},
|
||||
"description": "The freeCodeCamp.org open-source codebase and curriculum",
|
||||
"devDependencies": {
|
||||
"@total-typescript/ts-reset": "0.5.1",
|
||||
"@types/jsonwebtoken": "9.0.5",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/nodemailer": "6.4.14",
|
||||
"@types/supertest": "2.0.16",
|
||||
"@types/validator": "13.11.2",
|
||||
@@ -62,6 +64,7 @@
|
||||
"license": "BSD-3-Clause",
|
||||
"main": "none",
|
||||
"name": "@freecodecamp/api",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -3,8 +3,6 @@ import fastifyAccepts from '@fastify/accepts';
|
||||
import fastifySwagger from '@fastify/swagger';
|
||||
import fastifySwaggerUI from '@fastify/swagger-ui';
|
||||
import type { TypeBoxTypeProvider } from '@fastify/type-provider-typebox';
|
||||
import Ajv from 'ajv';
|
||||
import addFormats from 'ajv-formats';
|
||||
import uriResolver from 'fast-uri';
|
||||
import Fastify, {
|
||||
FastifyBaseLogger,
|
||||
@@ -14,25 +12,27 @@ import Fastify, {
|
||||
RawRequestDefaultExpression,
|
||||
RawServerDefault
|
||||
} from 'fastify';
|
||||
import { Ajv } from 'ajv';
|
||||
import addFormats from 'ajv-formats';
|
||||
|
||||
import prismaPlugin from './db/prisma';
|
||||
import cookies from './plugins/cookies';
|
||||
import cors from './plugins/cors';
|
||||
import { NodemailerProvider } from './plugins/mail-providers/nodemailer';
|
||||
import { SESProvider } from './plugins/mail-providers/ses';
|
||||
import mailer from './plugins/mailer';
|
||||
import redirectWithMessage from './plugins/redirect-with-message';
|
||||
import security from './plugins/security';
|
||||
import auth from './plugins/auth';
|
||||
import bouncer from './plugins/bouncer';
|
||||
import errorHandling from './plugins/error-handling';
|
||||
import csrf from './plugins/csrf';
|
||||
import notFound from './plugins/not-found';
|
||||
import shadowCapture from './plugins/shadow-capture';
|
||||
import growthBook from './plugins/growth-book';
|
||||
import prismaPlugin from './db/prisma.js';
|
||||
import cookies from './plugins/cookies.js';
|
||||
import cors from './plugins/cors.js';
|
||||
import { NodemailerProvider } from './plugins/mail-providers/nodemailer.js';
|
||||
import { SESProvider } from './plugins/mail-providers/ses.js';
|
||||
import mailer from './plugins/mailer.js';
|
||||
import redirectWithMessage from './plugins/redirect-with-message.js';
|
||||
import security from './plugins/security.js';
|
||||
import auth from './plugins/auth.js';
|
||||
import bouncer from './plugins/bouncer.js';
|
||||
import errorHandling from './plugins/error-handling.js';
|
||||
import csrf from './plugins/csrf.js';
|
||||
import notFound from './plugins/not-found.js';
|
||||
import shadowCapture from './plugins/shadow-capture.js';
|
||||
import growthBook from './plugins/growth-book.js';
|
||||
|
||||
import * as publicRoutes from './routes/public';
|
||||
import * as protectedRoutes from './routes/protected';
|
||||
import * as publicRoutes from './routes/public/index.js';
|
||||
import * as protectedRoutes from './routes/protected/index.js';
|
||||
|
||||
import {
|
||||
API_LOCATION,
|
||||
@@ -44,14 +44,14 @@ import {
|
||||
FCC_ENABLE_SENTRY_ROUTES,
|
||||
GROWTHBOOK_FASTIFY_API_HOST,
|
||||
GROWTHBOOK_FASTIFY_CLIENT_KEY
|
||||
} from './utils/env';
|
||||
import { isObjectID } from './utils/validation';
|
||||
import { getLogger } from './utils/logger';
|
||||
} from './utils/env.js';
|
||||
import { isObjectID } from './utils/validation.js';
|
||||
import { getLogger } from './utils/logger.js';
|
||||
import {
|
||||
examEnvironmentOpenRoutes,
|
||||
examEnvironmentValidatedTokenRoutes
|
||||
} from './exam-environment/routes/exam-environment';
|
||||
import { dailyCodingChallengeRoutes } from './daily-coding-challenge/routes/daily-coding-challenge';
|
||||
} from './exam-environment/routes/exam-environment.js';
|
||||
import { dailyCodingChallengeRoutes } from './daily-coding-challenge/routes/daily-coding-challenge.js';
|
||||
|
||||
type FastifyInstanceWithTypeProvider = FastifyInstance<
|
||||
RawServerDefault,
|
||||
@@ -74,7 +74,7 @@ const ajv = new Ajv({
|
||||
});
|
||||
|
||||
// add the default formatters from avj-formats
|
||||
addFormats(ajv);
|
||||
addFormats.default(ajv);
|
||||
ajv.addFormat('objectid', {
|
||||
type: 'string',
|
||||
validate: (str: string) => isObjectID(str)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { addDays } from 'date-fns';
|
||||
|
||||
import { setupServer, superRequest } from '../../../vitest.utils';
|
||||
import { getNowUsCentral, getUtcMidnight } from '../utils/helpers';
|
||||
import { setupServer, superRequest } from '../../../vitest.utils.js';
|
||||
import { getNowUsCentral, getUtcMidnight } from '../utils/helpers.js';
|
||||
|
||||
function dateToDateParam(date: Date): string {
|
||||
return date.toISOString().split('T')[0] as string;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
|
||||
import * as schemas from '../schemas';
|
||||
import * as schemas from '../schemas/index.js';
|
||||
import {
|
||||
getNowUsCentral,
|
||||
getUtcMidnight,
|
||||
dateStringToUtcMidnight
|
||||
} from '../utils/helpers';
|
||||
} from '../utils/helpers.js';
|
||||
|
||||
/**
|
||||
* Plugin containing public GET routes for the daily coding challenges.
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { dailyCodingChallenge } from './daily-coding-challenge';
|
||||
export { dailyCodingChallenge } from './daily-coding-challenge.js';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, beforeEach, afterAll } from 'vitest';
|
||||
import { defaultUserEmail, setupServer } from '../../vitest.utils';
|
||||
import { createUserInput } from '../utils/create-user';
|
||||
import { defaultUserEmail, setupServer } from '../../vitest.utils.js';
|
||||
|
||||
import { createUserInput } from '../utils/create-user.js';
|
||||
|
||||
describe('prisma client extensions', () => {
|
||||
setupServer();
|
||||
|
||||
@@ -3,7 +3,7 @@ import { FastifyPluginAsync } from 'fastify';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
// importing MONGOHQ_URL so we can mock it in testing.
|
||||
import { MONGOHQ_URL } from '../utils/env';
|
||||
import { MONGOHQ_URL } from '../utils/env.js';
|
||||
|
||||
declare module 'fastify' {
|
||||
interface FastifyInstance {
|
||||
|
||||
@@ -17,17 +17,17 @@ import {
|
||||
defaultUserId,
|
||||
devLogin,
|
||||
setupServer
|
||||
} from '../../../vitest.utils';
|
||||
} from '../../../vitest.utils.js';
|
||||
import {
|
||||
examEnvironmentPostExamAttempt,
|
||||
examEnvironmentPostExamGeneratedExam
|
||||
} from '../schemas';
|
||||
import * as mock from '../../../__mocks__/exam-environment-exam';
|
||||
import { constructUserExam } from '../utils/exam-environment';
|
||||
import { JWT_SECRET } from '../../utils/env';
|
||||
} from '../schemas/index.js';
|
||||
import * as mock from '../../../__mocks__/exam-environment-exam.js';
|
||||
import { constructUserExam } from '../utils/exam-environment.js';
|
||||
import { JWT_SECRET } from '../../utils/env.js';
|
||||
|
||||
vi.mock('../../utils/env', async importOriginal => {
|
||||
const actual = await importOriginal<typeof import('../../utils/env')>();
|
||||
const actual = await importOriginal<typeof import('../../utils/env.js')>();
|
||||
return {
|
||||
...actual,
|
||||
FCC_ENABLE_EXAM_ENVIRONMENT: 'true',
|
||||
@@ -531,7 +531,10 @@ describe('/exam-environment/', () => {
|
||||
|
||||
it('should unwind (delete) the exam attempt if the user exam cannot be constructed', async () => {
|
||||
const _mockConstructUserExam = vi
|
||||
.spyOn(await import('../utils/exam-environment'), 'constructUserExam')
|
||||
.spyOn(
|
||||
await import('../utils/exam-environment.js'),
|
||||
'constructUserExam'
|
||||
)
|
||||
.mockImplementationOnce(() => {
|
||||
throw new Error('Test error');
|
||||
});
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
/* eslint-disable jsdoc/require-returns, jsdoc/require-param */
|
||||
import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
import { PrismaClientValidationError } from '@prisma/client/runtime/library';
|
||||
import { PrismaClientValidationError } from '@prisma/client/runtime/library.js';
|
||||
import { type FastifyInstance, type FastifyReply } from 'fastify';
|
||||
import { ExamEnvironmentExamModerationStatus } from '@prisma/client';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
import * as schemas from '../schemas';
|
||||
import { mapErr, syncMapErr, UpdateReqType } from '../../utils';
|
||||
import { JWT_SECRET } from '../../utils/env';
|
||||
import * as schemas from '../schemas/index.js';
|
||||
import { mapErr, syncMapErr, UpdateReqType } from '../../utils/index.js';
|
||||
import { JWT_SECRET } from '../../utils/env.js';
|
||||
import {
|
||||
checkPrerequisites,
|
||||
constructEnvExamAttempt,
|
||||
constructUserExam,
|
||||
userAttemptToDatabaseAttemptQuestionSets,
|
||||
validateAttempt
|
||||
} from '../utils/exam-environment';
|
||||
import { ERRORS } from '../utils/errors';
|
||||
import { isObjectID } from '../../utils/validation';
|
||||
} from '../utils/exam-environment.js';
|
||||
import { ERRORS } from '../utils/errors.js';
|
||||
import { isObjectID } from '../../utils/validation.js';
|
||||
|
||||
/**
|
||||
* Wrapper for endpoints related to the exam environment desktop app.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { STANDARD_ERROR } from '../utils/errors';
|
||||
import { STANDARD_ERROR } from '../utils/errors.js';
|
||||
|
||||
export const examEnvironmentPostExamAttempt = {
|
||||
body: Type.Object({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { STANDARD_ERROR } from '../utils/errors';
|
||||
import { STANDARD_ERROR } from '../utils/errors.js';
|
||||
|
||||
export const examEnvironmentPostExamGeneratedExam = {
|
||||
body: Type.Object({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { STANDARD_ERROR } from '../utils/errors';
|
||||
import { STANDARD_ERROR } from '../utils/errors.js';
|
||||
export const examEnvironmentExams = {
|
||||
headers: Type.Object({
|
||||
'exam-environment-authorization-token': Type.String()
|
||||
|
||||
@@ -3,8 +3,8 @@ export {
|
||||
examEnvironmentGetExamAttempts,
|
||||
examEnvironmentGetExamAttempt,
|
||||
examEnvironmentGetExamAttemptsByExamId
|
||||
} from './exam-environment-exam-attempt';
|
||||
export { examEnvironmentPostExamGeneratedExam } from './exam-environment-exam-generated-exam';
|
||||
export { examEnvironmentTokenMeta } from './token-meta';
|
||||
export { examEnvironmentExams } from './exam-environment-exams';
|
||||
export { examEnvironmentGetExamMappingsByChallengeId } from './challenges';
|
||||
} from './exam-environment-exam-attempt.js';
|
||||
export { examEnvironmentPostExamGeneratedExam } from './exam-environment-exam-generated-exam.js';
|
||||
export { examEnvironmentTokenMeta } from './token-meta.js';
|
||||
export { examEnvironmentExams } from './exam-environment-exams.js';
|
||||
export { examEnvironmentGetExamMappingsByChallengeId } from './challenges.js';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { STANDARD_ERROR } from '../utils/errors';
|
||||
import { STANDARD_ERROR } from '../utils/errors.js';
|
||||
|
||||
export const examEnvironmentTokenMeta = {
|
||||
headers: Type.Object({
|
||||
|
||||
@@ -9,9 +9,9 @@ import {
|
||||
examAttempt,
|
||||
generatedExam,
|
||||
oid
|
||||
} from '../../../__mocks__/exam-environment-exam';
|
||||
import * as schemas from '../schemas';
|
||||
import { setupServer } from '../../../vitest.utils';
|
||||
} from '../../../__mocks__/exam-environment-exam.js';
|
||||
import * as schemas from '../schemas/index.js';
|
||||
import { setupServer } from '../../../vitest.utils.js';
|
||||
import {
|
||||
checkAttemptAgainstGeneratedExam,
|
||||
checkPrerequisites,
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
validateAttempt,
|
||||
compareAnswers,
|
||||
shuffleArray
|
||||
} from './exam-environment';
|
||||
} from './exam-environment.js';
|
||||
|
||||
// NOTE: Whilst the tests could be run against a single generation of exam,
|
||||
// it is more useful to run the tests against a new generation each time.
|
||||
|
||||
@@ -16,10 +16,10 @@ import {
|
||||
} from '@prisma/client';
|
||||
import type { FastifyBaseLogger, FastifyInstance } from 'fastify';
|
||||
import { type Static } from '@fastify/type-provider-typebox';
|
||||
import { omit } from 'lodash';
|
||||
import * as schemas from '../schemas';
|
||||
import { mapErr } from '../../utils';
|
||||
import { ERRORS } from './errors';
|
||||
import { omit } from 'lodash-es';
|
||||
import * as schemas from '../schemas/index.js';
|
||||
import { mapErr } from '../../utils/index.js';
|
||||
import { ERRORS } from './errors.js';
|
||||
|
||||
interface CompletedChallengeId {
|
||||
completedChallenges: {
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
DEPLOYMENT_VERSION,
|
||||
SENTRY_DSN,
|
||||
SENTRY_ENVIRONMENT
|
||||
} from './utils/env';
|
||||
} from './utils/env.js';
|
||||
|
||||
const shouldIgnoreError = (error: FastifyError): boolean => {
|
||||
return !!error.statusCode && error.statusCode < 500;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { expect } from 'vitest';
|
||||
|
||||
import { nanoidCharSet } from '../../utils/create-user';
|
||||
import { nanoidCharSet } from '../../utils/create-user.js';
|
||||
|
||||
const uuidRe = /^[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$/;
|
||||
const fccUuidRe = /^fcc-[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$/;
|
||||
const unsubscribeIdRe = new RegExp(`^[${nanoidCharSet}]{21}$`);
|
||||
const mongodbIdRe = /^[a-f0-9]{24}$/;
|
||||
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
||||
export const newUser = (email: string) => ({
|
||||
about: '',
|
||||
@@ -91,5 +90,4 @@ export const newUser = (email: string) => ({
|
||||
verificationToken: null,
|
||||
website: null,
|
||||
yearsTopContributor: []
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
@@ -8,14 +8,14 @@ import {
|
||||
} from 'vitest';
|
||||
import Fastify, { FastifyInstance } from 'fastify';
|
||||
|
||||
import { checkCanConnectToDb, defaultUserEmail } from '../../vitest.utils';
|
||||
import { HOME_LOCATION } from '../utils/env';
|
||||
import { devAuth } from '../plugins/auth-dev';
|
||||
import prismaPlugin from '../db/prisma';
|
||||
import auth from './auth';
|
||||
import cookies from './cookies';
|
||||
import { checkCanConnectToDb, defaultUserEmail } from '../../vitest.utils.js';
|
||||
import { HOME_LOCATION } from '../utils/env.js';
|
||||
import { devAuth } from '../plugins/auth-dev.js';
|
||||
import prismaPlugin from '../db/prisma.js';
|
||||
import auth from './auth.js';
|
||||
import cookies from './cookies.js';
|
||||
|
||||
import { newUser } from './__fixtures__/user';
|
||||
import { newUser } from './__fixtures__/user.js';
|
||||
|
||||
describe('dev login', () => {
|
||||
let fastify: FastifyInstance;
|
||||
|
||||
@@ -4,9 +4,9 @@ import {
|
||||
getRedirectParams,
|
||||
getPrefixedLandingPath,
|
||||
haveSamePath
|
||||
} from '../utils/redirection';
|
||||
import { findOrCreateUser } from '../routes/helpers/auth-helpers';
|
||||
import { createAccessToken } from '../utils/tokens';
|
||||
} from '../utils/redirection.js';
|
||||
import { findOrCreateUser } from '../routes/helpers/auth-helpers.js';
|
||||
import { createAccessToken } from '../utils/tokens.js';
|
||||
|
||||
const trimTrailingSlash = (str: string) =>
|
||||
str.endsWith('/') ? str.slice(0, -1) : str;
|
||||
|
||||
@@ -2,10 +2,13 @@ import { describe, test, expect, beforeEach, afterEach } from 'vitest';
|
||||
import Fastify, { FastifyInstance } from 'fastify';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
import { COOKIE_DOMAIN, JWT_SECRET } from '../utils/env';
|
||||
import { type Token, createAccessToken } from '../utils/tokens';
|
||||
import cookies, { sign as signCookie, unsign as unsignCookie } from './cookies';
|
||||
import auth from './auth';
|
||||
import { COOKIE_DOMAIN, JWT_SECRET } from '../utils/env.js';
|
||||
import { type Token, createAccessToken } from '../utils/tokens.js';
|
||||
import cookies, {
|
||||
sign as signCookie,
|
||||
unsign as unsignCookie
|
||||
} from './cookies.js';
|
||||
import auth from './auth.js';
|
||||
|
||||
async function setupServer() {
|
||||
const fastify = Fastify();
|
||||
|
||||
@@ -3,9 +3,9 @@ import fp from 'fastify-plugin';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { type user } from '@prisma/client';
|
||||
|
||||
import { JWT_SECRET } from '../utils/env';
|
||||
import { type Token, isExpired } from '../utils/tokens';
|
||||
import { ERRORS } from '../exam-environment/utils/errors';
|
||||
import { JWT_SECRET } from '../utils/env.js';
|
||||
import { type Token, isExpired } from '../utils/tokens.js';
|
||||
import { ERRORS } from '../exam-environment/utils/errors.js';
|
||||
|
||||
declare module 'fastify' {
|
||||
interface FastifyReply {
|
||||
|
||||
@@ -11,20 +11,20 @@ import {
|
||||
} from 'vitest';
|
||||
import Fastify, { FastifyInstance } from 'fastify';
|
||||
|
||||
import { createUserInput } from '../utils/create-user';
|
||||
import { AUTH0_DOMAIN, HOME_LOCATION } from '../utils/env';
|
||||
import prismaPlugin from '../db/prisma';
|
||||
import cookies, { sign, unsign } from './cookies';
|
||||
import { auth0Client } from './auth0';
|
||||
import redirectWithMessage, { formatMessage } from './redirect-with-message';
|
||||
import auth from './auth';
|
||||
import bouncer from './bouncer';
|
||||
import { newUser } from './__fixtures__/user';
|
||||
import { createUserInput } from '../utils/create-user.js';
|
||||
import { AUTH0_DOMAIN, HOME_LOCATION } from '../utils/env.js';
|
||||
import prismaPlugin from '../db/prisma.js';
|
||||
import cookies, { sign, unsign } from './cookies.js';
|
||||
import { auth0Client } from './auth0.js';
|
||||
import redirectWithMessage, { formatMessage } from './redirect-with-message.js';
|
||||
import auth from './auth.js';
|
||||
import bouncer from './bouncer.js';
|
||||
import { newUser } from './__fixtures__/user.js';
|
||||
|
||||
const COOKIE_DOMAIN = 'test.com';
|
||||
|
||||
vi.mock('../utils/env', async importOriginal => ({
|
||||
...(await importOriginal<typeof import('../utils/env')>()),
|
||||
...(await importOriginal<typeof import('../utils/env.js')>()),
|
||||
COOKIE_DOMAIN: 'test.com'
|
||||
}));
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Type } from '@sinclair/typebox';
|
||||
import { Value } from '@sinclair/typebox/value';
|
||||
import fp from 'fastify-plugin';
|
||||
|
||||
import { isError } from 'lodash';
|
||||
import { isError } from 'lodash-es';
|
||||
import {
|
||||
API_LOCATION,
|
||||
AUTH0_CLIENT_ID,
|
||||
@@ -12,10 +12,10 @@ import {
|
||||
AUTH0_DOMAIN,
|
||||
COOKIE_DOMAIN,
|
||||
HOME_LOCATION
|
||||
} from '../utils/env';
|
||||
import { findOrCreateUser } from '../routes/helpers/auth-helpers';
|
||||
import { createAccessToken } from '../utils/tokens';
|
||||
import { getLoginRedirectParams } from '../utils/redirection';
|
||||
} from '../utils/env.js';
|
||||
import { findOrCreateUser } from '../routes/helpers/auth-helpers.js';
|
||||
import { createAccessToken } from '../utils/tokens.js';
|
||||
import { getLoginRedirectParams } from '../utils/redirection.js';
|
||||
|
||||
declare module 'fastify' {
|
||||
interface FastifyInstance {
|
||||
|
||||
@@ -11,11 +11,11 @@ import {
|
||||
import Fastify, { type FastifyInstance } from 'fastify';
|
||||
import { type user } from '@prisma/client';
|
||||
|
||||
import { HOME_LOCATION } from '../utils/env';
|
||||
import bouncer from './bouncer';
|
||||
import auth from './auth';
|
||||
import cookies from './cookies';
|
||||
import redirectWithMessage, { formatMessage } from './redirect-with-message';
|
||||
import { HOME_LOCATION } from '../utils/env.js';
|
||||
import bouncer from './bouncer.js';
|
||||
import auth from './auth.js';
|
||||
import cookies from './cookies.js';
|
||||
import redirectWithMessage, { formatMessage } from './redirect-with-message.js';
|
||||
|
||||
let authorizeSpy: MockInstance<FastifyInstance['authorize']>;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import type {
|
||||
FastifyReply
|
||||
} from 'fastify';
|
||||
import fp from 'fastify-plugin';
|
||||
import { getRedirectParams } from '../utils/redirection';
|
||||
import { getRedirectParams } from '../utils/redirection.js';
|
||||
|
||||
declare module 'fastify' {
|
||||
interface FastifyInstance {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||
import Fastify, { FastifyInstance } from 'fastify';
|
||||
import cookies, { type CookieSerializeOptions, sign } from './cookies';
|
||||
import { cookieUpdate } from './cookie-update';
|
||||
import cookies, { type CookieSerializeOptions, sign } from './cookies.js';
|
||||
import { cookieUpdate } from './cookie-update.js';
|
||||
|
||||
vi.mock('../utils/env', async importOriginal => {
|
||||
const actual = await importOriginal<typeof import('../utils/env')>();
|
||||
const actual = await importOriginal<typeof import('../utils/env.js')>();
|
||||
return {
|
||||
...actual,
|
||||
COOKIE_DOMAIN: 'www.example.com',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FastifyPluginCallback } from 'fastify';
|
||||
|
||||
import type { CookieSerializeOptions } from './cookies';
|
||||
import type { CookieSerializeOptions } from './cookies.js';
|
||||
|
||||
type Options = { cookies: string[]; attributes: CookieSerializeOptions };
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@ import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||
import Fastify, { type FastifyInstance } from 'fastify';
|
||||
import fastifyCookie from '@fastify/cookie';
|
||||
|
||||
import { COOKIE_SECRET } from '../utils/env';
|
||||
import cookies from './cookies';
|
||||
import { COOKIE_SECRET } from '../utils/env.js';
|
||||
import cookies from './cookies.js';
|
||||
|
||||
vi.mock('../utils/env', async importOriginal => {
|
||||
const actual = await importOriginal<typeof import('../utils/env')>();
|
||||
const actual = await importOriginal<typeof import('../utils/env.js')>();
|
||||
return {
|
||||
...actual,
|
||||
COOKIE_DOMAIN: 'www.example.com',
|
||||
|
||||
@@ -6,8 +6,8 @@ import {
|
||||
COOKIE_DOMAIN,
|
||||
COOKIE_SECRET,
|
||||
FREECODECAMP_NODE_ENV
|
||||
} from '../utils/env';
|
||||
import { CSRF_COOKIE, CSRF_SECRET_COOKIE } from './csrf';
|
||||
} from '../utils/env.js';
|
||||
import { CSRF_COOKIE, CSRF_SECRET_COOKIE } from './csrf.js';
|
||||
|
||||
export { type CookieSerializeOptions } from '@fastify/cookie';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, test, expect, beforeAll, afterAll, vi } from 'vitest';
|
||||
import Fastify, { FastifyInstance, LogLevel } from 'fastify';
|
||||
import cors from './cors';
|
||||
import cors from './cors.js';
|
||||
|
||||
const NON_DEBUG_LOG_LEVELS: LogLevel[] = [
|
||||
'fatal',
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { FastifyPluginCallback } from 'fastify';
|
||||
import fp from 'fastify-plugin';
|
||||
|
||||
import { HOME_LOCATION } from '../utils/env';
|
||||
import { allowedOrigins } from '../utils/allowed-origins';
|
||||
import { HOME_LOCATION } from '../utils/env.js';
|
||||
import { allowedOrigins } from '../utils/allowed-origins.js';
|
||||
|
||||
const cors: FastifyPluginCallback = (fastify, _options, done) => {
|
||||
fastify.options('*', (_req, reply) => {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { describe, test, expect, beforeEach, vi } from 'vitest';
|
||||
import Fastify, { type FastifyInstance } from 'fastify';
|
||||
|
||||
import { COOKIE_DOMAIN } from '../utils/env';
|
||||
import cookies from './cookies';
|
||||
import csrf, { CSRF_COOKIE, CSRF_SECRET_COOKIE } from './csrf';
|
||||
import { COOKIE_DOMAIN } from '../utils/env.js';
|
||||
import cookies from './cookies.js';
|
||||
import csrf, { CSRF_COOKIE, CSRF_SECRET_COOKIE } from './csrf.js';
|
||||
|
||||
vi.mock('../utils/env', async importOriginal => {
|
||||
const actual = await importOriginal<typeof import('../utils/env')>();
|
||||
const actual = await importOriginal<typeof import('../utils/env.js')>();
|
||||
return {
|
||||
...actual,
|
||||
COOKIE_DOMAIN: 'www.example.com',
|
||||
|
||||
@@ -13,8 +13,8 @@ import accepts from '@fastify/accepts';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
|
||||
vi.mock('../utils/env', async importOriginal => {
|
||||
const actual = await importOriginal<typeof import('../utils/env')>();
|
||||
vi.mock('../utils/env.js', async importOriginal => {
|
||||
const actual = await importOriginal<typeof import('../utils/env.js')>();
|
||||
return {
|
||||
...actual,
|
||||
SENTRY_DSN: 'https://anything@goes/123'
|
||||
@@ -22,8 +22,8 @@ vi.mock('../utils/env', async importOriginal => {
|
||||
});
|
||||
|
||||
import '../instrument';
|
||||
import errorHandling from './error-handling';
|
||||
import redirectWithMessage, { formatMessage } from './redirect-with-message';
|
||||
import errorHandling from './error-handling.js';
|
||||
import redirectWithMessage, { formatMessage } from './redirect-with-message.js';
|
||||
|
||||
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { FastifyPluginCallback } from 'fastify';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import fp from 'fastify-plugin';
|
||||
|
||||
import { getRedirectParams } from '../utils/redirection';
|
||||
import { getRedirectParams } from '../utils/redirection.js';
|
||||
|
||||
declare module 'fastify' {
|
||||
interface FastifyInstance {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { describe, test, expect, beforeAll, afterAll, vi } from 'vitest';
|
||||
import Fastify, { type FastifyInstance } from 'fastify';
|
||||
import growthBook from './growth-book';
|
||||
import growthBook from './growth-book.js';
|
||||
|
||||
vi.mock('../utils/env', async importOriginal => {
|
||||
const actual = await importOriginal<typeof import('../utils/env')>();
|
||||
const actual = await importOriginal<typeof import('../utils/env.js')>();
|
||||
return {
|
||||
...actual,
|
||||
// We're only interested in the production behaviour
|
||||
|
||||
@@ -2,7 +2,7 @@ import { GrowthBook, Options } from '@growthbook/growthbook';
|
||||
import { FastifyPluginAsync } from 'fastify';
|
||||
import fp from 'fastify-plugin';
|
||||
|
||||
import { FREECODECAMP_NODE_ENV } from '../utils/env';
|
||||
import { FREECODECAMP_NODE_ENV } from '../utils/env.js';
|
||||
|
||||
declare module 'fastify' {
|
||||
interface FastifyInstance {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import nodemailer, { Transporter } from 'nodemailer';
|
||||
|
||||
import { MailProvider, SendEmailArgs } from '../mailer';
|
||||
import { MAILHOG_HOST } from '../../utils/env';
|
||||
import { MailProvider, SendEmailArgs } from '../mailer.js';
|
||||
import { MAILHOG_HOST } from '../../utils/env.js';
|
||||
|
||||
/**
|
||||
* NodemailerProvider is a wrapper around nodemailer that provides a clean
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
SendEmailCommand
|
||||
} from '@aws-sdk/client-ses';
|
||||
|
||||
import { MailProvider, SendEmailArgs } from '../mailer';
|
||||
import { SES_ID, SES_SECRET, SES_REGION } from '../../utils/env';
|
||||
import { MailProvider, SendEmailArgs } from '../mailer.js';
|
||||
import { SES_ID, SES_SECRET, SES_REGION } from '../../utils/env.js';
|
||||
|
||||
/**
|
||||
* SESProvider is a wrapper around nodemailer that provides a clean interface
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, test, expect, vi } from 'vitest';
|
||||
import Fastify from 'fastify';
|
||||
|
||||
import mailer from './mailer';
|
||||
import mailer from './mailer.js';
|
||||
|
||||
describe('mailer', () => {
|
||||
test('should send an email via the provider', async () => {
|
||||
|
||||
@@ -2,8 +2,8 @@ import { describe, beforeEach, afterEach, it, expect } from 'vitest';
|
||||
import Fastify, { type FastifyInstance } from 'fastify';
|
||||
import accepts from '@fastify/accepts';
|
||||
|
||||
import notFound from './not-found';
|
||||
import redirectWithMessage, { formatMessage } from './redirect-with-message';
|
||||
import notFound from './not-found.js';
|
||||
import redirectWithMessage, { formatMessage } from './redirect-with-message.js';
|
||||
|
||||
describe('fourOhFour', () => {
|
||||
let fastify: FastifyInstance;
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { FastifyPluginCallback } from 'fastify';
|
||||
|
||||
import fp from 'fastify-plugin';
|
||||
|
||||
import { getRedirectParams } from '../utils/redirection';
|
||||
import { getRedirectParams } from '../utils/redirection.js';
|
||||
|
||||
/**
|
||||
* Plugin for handling missing endpoints.
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, test, expect, beforeEach } from 'vitest';
|
||||
import Fastify, { FastifyInstance } from 'fastify';
|
||||
import qs from 'query-string';
|
||||
|
||||
import redirectWithMessage from './redirect-with-message';
|
||||
import redirectWithMessage from './redirect-with-message.js';
|
||||
|
||||
async function setupServer() {
|
||||
const fastify = Fastify();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FastifyPluginCallback } from 'fastify';
|
||||
import fp from 'fastify-plugin';
|
||||
|
||||
import { FREECODECAMP_NODE_ENV } from '../utils/env';
|
||||
import { FREECODECAMP_NODE_ENV } from '../utils/env.js';
|
||||
|
||||
const securityHeaders: FastifyPluginCallback = (fastify, _options, done) => {
|
||||
// OWASP recommended headers
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { randomUUID } from 'crypto';
|
||||
import { appendFileSync, mkdirSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import type { FastifyPluginCallback } from 'fastify';
|
||||
import type {
|
||||
FastifyPluginCallback,
|
||||
FastifyReply,
|
||||
FastifyRequest
|
||||
} from 'fastify';
|
||||
|
||||
import fp from 'fastify-plugin';
|
||||
import { FastifyReply } from 'fastify/types/reply';
|
||||
import { FastifyRequest } from 'fastify/types/request';
|
||||
|
||||
const LOGS_DIRECTORY = 'logs';
|
||||
const REQUEST_CAPTURE_FILE = 'request-capture.jsonl';
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { describe, test, expect, beforeAll, afterEach, vi } from 'vitest';
|
||||
import Fastify, { FastifyInstance } from 'fastify';
|
||||
|
||||
import db from '../../db/prisma';
|
||||
import { createUserInput } from '../../utils/create-user';
|
||||
import { checkCanConnectToDb } from '../../../vitest.utils';
|
||||
import { findOrCreateUser } from './auth-helpers';
|
||||
import db from '../../db/prisma.js';
|
||||
import { createUserInput } from '../../utils/create-user.js';
|
||||
import { checkCanConnectToDb } from '../../../vitest.utils.js';
|
||||
import { findOrCreateUser } from './auth-helpers.js';
|
||||
|
||||
const captureException = vi.fn();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FastifyInstance } from 'fastify';
|
||||
import { createUserInput } from '../../utils/create-user';
|
||||
import { createUserInput } from '../../utils/create-user.js';
|
||||
|
||||
/**
|
||||
* Finds an existing user with the given email or creates a new user if none exists.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { getFallbackFullStackDate } from './certificate-utils';
|
||||
|
||||
import { getFallbackFullStackDate } from './certificate-utils.js';
|
||||
|
||||
const fullStackChallenges = [
|
||||
{
|
||||
|
||||
@@ -2,8 +2,8 @@ import { Prisma } from '@prisma/client';
|
||||
import {
|
||||
certSlugTypeMap,
|
||||
certIds
|
||||
} from '../../../../shared/config/certification-settings';
|
||||
import { normalizeDate } from '../../utils/normalize';
|
||||
} from '../../../../shared/config/certification-settings.js';
|
||||
import { normalizeDate } from '../../utils/normalize.js';
|
||||
|
||||
const {
|
||||
legacyInfosecQaId,
|
||||
|
||||
@@ -4,14 +4,14 @@ import type {
|
||||
CompletedChallenge
|
||||
} from '@prisma/client';
|
||||
|
||||
import { createFetchMock } from '../../../vitest.utils';
|
||||
import { createFetchMock } from '../../../vitest.utils.js';
|
||||
import {
|
||||
canSubmitCodeRoadCertProject,
|
||||
verifyTrophyWithMicrosoft,
|
||||
decodeFiles,
|
||||
decodeBase64,
|
||||
encodeBase64
|
||||
} from './challenge-helpers';
|
||||
} from './challenge-helpers.js';
|
||||
|
||||
const id = 'abc';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { isProfane } from 'no-profanity';
|
||||
|
||||
import { blocklistedUsernames } from '../../../../shared/config/constants';
|
||||
import { blocklistedUsernames } from '../../../../shared/config/constants.js';
|
||||
|
||||
/**
|
||||
* Checks if a username is restricted (i.e. It's profane or reserved).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import _ from 'lodash';
|
||||
import { pick, omit } from 'lodash-es';
|
||||
|
||||
// user flags that the api-server returns as false if they're missing in the
|
||||
// user document. Since Prisma returns null for missing fields, we need to
|
||||
@@ -45,5 +45,5 @@ type NullableFlags = (typeof nullableFlags)[number];
|
||||
export function splitUser<U extends Record<NullableFlags, unknown>>(
|
||||
user: U
|
||||
): [Pick<U, NullableFlags>, Omit<U, NullableFlags>] {
|
||||
return [_.pick(user, nullableFlags), _.omit(user, nullableFlags)];
|
||||
return [pick(user, nullableFlags), omit(user, nullableFlags)];
|
||||
}
|
||||
|
||||
@@ -7,14 +7,15 @@ import {
|
||||
beforeEach,
|
||||
vi
|
||||
} from 'vitest';
|
||||
import { Certification } from '../../../../shared/config/certification-settings';
|
||||
|
||||
import { Certification } from '../../../../shared/config/certification-settings.js';
|
||||
import {
|
||||
defaultUserEmail,
|
||||
defaultUserId,
|
||||
devLogin,
|
||||
setupServer,
|
||||
superRequest
|
||||
} from '../../../vitest.utils';
|
||||
} from '../../../vitest.utils.js';
|
||||
|
||||
describe('certificate routes', () => {
|
||||
setupServer();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { CompletedChallenge } from '@prisma/client';
|
||||
import isEmail from 'validator/lib/isEmail';
|
||||
import validator from 'validator';
|
||||
import type { FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
|
||||
import { getChallenges } from '../../utils/get-challenges';
|
||||
import { getChallenges } from '../../utils/get-challenges.js';
|
||||
import {
|
||||
certIds,
|
||||
certSlugTypeMap,
|
||||
@@ -12,13 +12,13 @@ import {
|
||||
legacyCertifications,
|
||||
legacyFullStackCertification,
|
||||
upcomingCertifications
|
||||
} from '../../../../shared/config/certification-settings';
|
||||
} from '../../../../shared/config/certification-settings.js';
|
||||
|
||||
import * as schemas from '../../schemas';
|
||||
import { normalizeChallenges, removeNulls } from '../../utils/normalize';
|
||||
import * as schemas from '../../schemas.js';
|
||||
import { normalizeChallenges, removeNulls } from '../../utils/normalize.js';
|
||||
|
||||
import { SHOW_UPCOMING_CHANGES } from '../../utils/env';
|
||||
import { isKnownCertSlug } from '../helpers/certificate-utils';
|
||||
import { SHOW_UPCOMING_CHANGES } from '../../utils/env.js';
|
||||
import { isKnownCertSlug } from '../helpers/certificate-utils.js';
|
||||
|
||||
const {
|
||||
legacyFrontEndChallengeId,
|
||||
@@ -403,7 +403,7 @@ export const protectedCertificateRoutes: FastifyPluginCallbackTypebox = (
|
||||
.map(x => certSlugTypeMap[x])
|
||||
.every(certType => updatedIsCertMap[certType]);
|
||||
const shouldSendCertifiedEmailToCamper =
|
||||
email && isEmail(email) && hasCompletedAllCerts;
|
||||
email && validator.default.isEmail(email) && hasCompletedAllCerts;
|
||||
|
||||
if (shouldSendCertifiedEmailToCamper) {
|
||||
const notifyUser = {
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
|
||||
vi.mock('../helpers/challenge-helpers', async () => {
|
||||
const originalModule = await vi.importActual<
|
||||
typeof import('../helpers/challenge-helpers')
|
||||
typeof import('../helpers/challenge-helpers.js')
|
||||
>('../helpers/challenge-helpers');
|
||||
|
||||
return {
|
||||
@@ -23,12 +23,12 @@ vi.mock('../helpers/challenge-helpers', async () => {
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
import { omit } from 'lodash';
|
||||
import { omit } from 'lodash-es';
|
||||
import { Static } from '@fastify/type-provider-typebox';
|
||||
import { DailyCodingChallengeLanguage } from '@prisma/client';
|
||||
import request from 'supertest';
|
||||
|
||||
import { challengeTypes } from '../../../../shared/config/challenge-types';
|
||||
import { challengeTypes } from '../../../../shared/config/challenge-types.js';
|
||||
import {
|
||||
defaultUserId,
|
||||
devLogin,
|
||||
@@ -38,7 +38,7 @@ import {
|
||||
defaultUserEmail,
|
||||
createSuperRequest,
|
||||
defaultUsername
|
||||
} from '../../../vitest.utils';
|
||||
} from '../../../vitest.utils.js';
|
||||
import {
|
||||
completedExamChallengeOneCorrect,
|
||||
completedExamChallengeTwoCorrect,
|
||||
@@ -53,16 +53,28 @@ import {
|
||||
examWithTwoCorrect,
|
||||
examWithAllCorrect,
|
||||
type ExamSubmission
|
||||
} from '../../../__mocks__/exam';
|
||||
import { Answer } from '../../utils/exam-types';
|
||||
import type { getSessionUser } from '../../schemas/user/get-session-user';
|
||||
import { verifyTrophyWithMicrosoft } from '../helpers/challenge-helpers';
|
||||
} from '../../../__mocks__/exam.js';
|
||||
import { Answer } from '../../utils/exam-types.js';
|
||||
import type { getSessionUser } from '../../schemas/user/get-session-user.js';
|
||||
import { verifyTrophyWithMicrosoft } from '../helpers/challenge-helpers.js';
|
||||
|
||||
const mockVerifyTrophyWithMicrosoft = vi.mocked(verifyTrophyWithMicrosoft);
|
||||
|
||||
const EXISTING_COMPLETED_DATE = new Date('2024-11-08').getTime();
|
||||
const DATE_NOW = Date.now();
|
||||
|
||||
vi.mock('../helpers/challenge-helpers.js', async () => {
|
||||
const originalModule = await vi.importActual<
|
||||
typeof import('../helpers/challenge-helpers.js')
|
||||
>('../helpers/challenge-helpers');
|
||||
|
||||
return {
|
||||
__esModule: true,
|
||||
...originalModule,
|
||||
verifyTrophyWithMicrosoft: vi.fn()
|
||||
};
|
||||
});
|
||||
|
||||
const isValidChallengeCompletionErrorMsg = {
|
||||
type: 'error',
|
||||
message: 'That does not appear to be a valid challenge submission.'
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { uniqBy, matches } from 'lodash';
|
||||
import { CompletedExam, ExamResults, SavedChallengeFile } from '@prisma/client';
|
||||
import isURL from 'validator/lib/isURL';
|
||||
import type { FastifyBaseLogger, FastifyInstance, FastifyReply } from 'fastify';
|
||||
import { uniqBy, matches } from 'lodash-es';
|
||||
|
||||
import { challengeTypes } from '../../../../shared/config/challenge-types';
|
||||
import * as schemas from '../../schemas';
|
||||
import validator from 'validator';
|
||||
|
||||
import { challengeTypes } from '../../../../shared/config/challenge-types.js';
|
||||
import * as schemas from '../../schemas.js';
|
||||
import {
|
||||
jsCertProjectIds,
|
||||
multifileCertProjectIds,
|
||||
@@ -15,28 +16,31 @@ import {
|
||||
type CompletedChallenge,
|
||||
saveUserChallengeData,
|
||||
msTrophyChallenges
|
||||
} from '../../utils/common-challenge-functions';
|
||||
import { JWT_SECRET } from '../../utils/env';
|
||||
} from '../../utils/common-challenge-functions.js';
|
||||
import { JWT_SECRET } from '../../utils/env.js';
|
||||
import {
|
||||
formatCoderoadChallengeCompletedValidation,
|
||||
formatProjectCompletedValidation
|
||||
} from '../../utils/error-formatting';
|
||||
import { getChallenges } from '../../utils/get-challenges';
|
||||
import { ProgressTimestamp, getPoints } from '../../utils/progress';
|
||||
} from '../../utils/error-formatting.js';
|
||||
import { getChallenges } from '../../utils/get-challenges.js';
|
||||
import { ProgressTimestamp, getPoints } from '../../utils/progress.js';
|
||||
import {
|
||||
validateExamFromDbSchema,
|
||||
validateGeneratedExamSchema,
|
||||
validateUserCompletedExamSchema,
|
||||
validateExamResultsSchema
|
||||
} from '../../utils/exam-schemas';
|
||||
import { generateRandomExam, createExamResults } from '../../utils/exam';
|
||||
} from '../../utils/exam-schemas.js';
|
||||
import { generateRandomExam, createExamResults } from '../../utils/exam.js';
|
||||
import {
|
||||
canSubmitCodeRoadCertProject,
|
||||
decodeFiles,
|
||||
verifyTrophyWithMicrosoft
|
||||
} from '../helpers/challenge-helpers';
|
||||
import { UpdateReqType } from '../../utils';
|
||||
import { normalizeChallengeType, normalizeDate } from '../../utils/normalize';
|
||||
} from '../helpers/challenge-helpers.js';
|
||||
import { UpdateReqType } from '../../utils/index.js';
|
||||
import {
|
||||
normalizeChallengeType,
|
||||
normalizeDate
|
||||
} from '../../utils/normalize.js';
|
||||
|
||||
interface JwtPayload {
|
||||
userToken: string;
|
||||
@@ -94,7 +98,7 @@ export const challengeRoutes: FastifyPluginCallbackTypebox = (
|
||||
// - `solution` needs to exist, but does not have to be valid URL
|
||||
// - `githubLink` needs to exist and be valid URL
|
||||
if (challengeType === challengeTypes.backEndProject) {
|
||||
if (!solution || !isURL(githubLink + '')) {
|
||||
if (!solution || !validator.default.isURL(githubLink + '')) {
|
||||
logger.warn(
|
||||
{ solution, githubLink },
|
||||
'Invalid backEndProject submission'
|
||||
@@ -104,7 +108,7 @@ export const challengeRoutes: FastifyPluginCallbackTypebox = (
|
||||
message: 'That does not appear to be a valid challenge submission.'
|
||||
});
|
||||
}
|
||||
} else if (solution && !isURL(solution + '')) {
|
||||
} else if (solution && !validator.default.isURL(solution + '')) {
|
||||
logger.warn({ solution }, 'Invalid solution URL');
|
||||
return void reply.code(403).send({
|
||||
type: 'error',
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
setupServer,
|
||||
defaultUserEmail,
|
||||
defaultUserId
|
||||
} from '../../../vitest.utils';
|
||||
import { createUserInput } from '../../utils/create-user';
|
||||
} from '../../../vitest.utils.js';
|
||||
import { createUserInput } from '../../utils/create-user.js';
|
||||
|
||||
const testEWalletEmail = 'baz@bar.com';
|
||||
const testSubscriptionId = 'sub_test_id';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
import Stripe from 'stripe';
|
||||
|
||||
import * as schemas from '../../schemas';
|
||||
import { donationSubscriptionConfig } from '../../../../shared/config/donation-settings';
|
||||
import { STRIPE_SECRET_KEY, HOME_LOCATION } from '../../utils/env';
|
||||
import * as schemas from '../../schemas.js';
|
||||
import { donationSubscriptionConfig } from '../../../../shared/config/donation-settings.js';
|
||||
import { STRIPE_SECRET_KEY, HOME_LOCATION } from '../../utils/env.js';
|
||||
|
||||
/**
|
||||
* Plugin for the donation endpoints requiring auth.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export * from './certificate';
|
||||
export * from './challenge';
|
||||
export * from './donate';
|
||||
export * from './settings';
|
||||
export * from './user';
|
||||
export * from './certificate.js';
|
||||
export * from './challenge.js';
|
||||
export * from './donate.js';
|
||||
export * from './settings.js';
|
||||
export * from './user.js';
|
||||
|
||||
@@ -16,15 +16,15 @@ import {
|
||||
createSuperRequest,
|
||||
defaultUserId,
|
||||
defaultUserEmail
|
||||
} from '../../../vitest.utils';
|
||||
import { formatMessage } from '../../plugins/redirect-with-message';
|
||||
import { createUserInput } from '../../utils/create-user';
|
||||
import { API_LOCATION, HOME_LOCATION } from '../../utils/env';
|
||||
} from '../../../vitest.utils.js';
|
||||
import { formatMessage } from '../../plugins/redirect-with-message.js';
|
||||
import { createUserInput } from '../../utils/create-user.js';
|
||||
import { API_LOCATION, HOME_LOCATION } from '../../utils/env.js';
|
||||
import {
|
||||
isPictureWithProtocol,
|
||||
getWaitMessage,
|
||||
validateSocialUrl
|
||||
} from './settings';
|
||||
} from './settings.js';
|
||||
|
||||
const baseProfileUI = {
|
||||
isLocked: false,
|
||||
|
||||
@@ -3,14 +3,12 @@ import type { FastifyInstance } from 'fastify';
|
||||
import { differenceInMinutes } from 'date-fns';
|
||||
import validator from 'validator';
|
||||
|
||||
import { isValidUsername } from '../../../../shared/utils/validate';
|
||||
import * as schemas from '../../schemas';
|
||||
import { createAuthToken, isExpired } from '../../utils/tokens';
|
||||
import { API_LOCATION } from '../../utils/env';
|
||||
import { getRedirectParams } from '../../utils/redirection';
|
||||
import { isRestricted } from '../helpers/is-restricted';
|
||||
|
||||
const { isEmail } = validator;
|
||||
import { isValidUsername } from '../../../../shared/utils/validate.js';
|
||||
import * as schemas from '../../schemas.js';
|
||||
import { createAuthToken, isExpired } from '../../utils/tokens.js';
|
||||
import { API_LOCATION } from '../../utils/env.js';
|
||||
import { getRedirectParams } from '../../utils/redirection.js';
|
||||
import { isRestricted } from '../helpers/is-restricted.js';
|
||||
|
||||
type WaitMesssageArgs = {
|
||||
sentAt: Date | null;
|
||||
@@ -768,7 +766,7 @@ export const settingRedirectRoutes: FastifyPluginCallbackTypebox = (
|
||||
const email = Buffer.from(req.query.email, 'base64').toString();
|
||||
|
||||
const { origin } = getRedirectParams(req);
|
||||
if (!isEmail(email)) {
|
||||
if (!validator.default.isEmail(email)) {
|
||||
logger.warn(`Invalid email ${email}`);
|
||||
return reply.redirectWithMessage(origin, redirectMessage);
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ import {
|
||||
import jwt, { JwtPayload } from 'jsonwebtoken';
|
||||
import { DailyCodingChallengeLanguage, type Prisma } from '@prisma/client';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import _ from 'lodash';
|
||||
import { omit } from 'lodash-es';
|
||||
|
||||
import { createUserInput } from '../../utils/create-user';
|
||||
import { createUserInput } from '../../utils/create-user.js';
|
||||
import {
|
||||
defaultUserId,
|
||||
defaultUserEmail,
|
||||
@@ -27,15 +27,15 @@ import {
|
||||
createSuperRequest,
|
||||
defaultUsername,
|
||||
resetDefaultUser
|
||||
} from '../../../vitest.utils';
|
||||
import { JWT_SECRET } from '../../utils/env';
|
||||
} from '../../../vitest.utils.js';
|
||||
import { JWT_SECRET } from '../../utils/env.js';
|
||||
import {
|
||||
clearEnvExam,
|
||||
seedEnvExam,
|
||||
seedEnvExamAttempt,
|
||||
seedExamEnvExamAuthToken
|
||||
} from '../../../__mocks__/exam-environment-exam';
|
||||
import { getMsTranscriptApiUrl } from './user';
|
||||
} from '../../../__mocks__/exam-environment-exam.js';
|
||||
import { getMsTranscriptApiUrl } from './user.js';
|
||||
|
||||
const mockedFetch = vi.fn();
|
||||
vi.spyOn(globalThis, 'fetch').mockImplementation(mockedFetch);
|
||||
@@ -43,7 +43,9 @@ vi.spyOn(globalThis, 'fetch').mockImplementation(mockedFetch);
|
||||
let mockDeploymentEnv = 'staging';
|
||||
vi.mock('../../utils/env', async () => {
|
||||
const actualEnv =
|
||||
await vi.importActual<typeof import('../../utils/env')>('../../utils/env');
|
||||
await vi.importActual<typeof import('../../utils/env.js')>(
|
||||
'../../utils/env'
|
||||
);
|
||||
return {
|
||||
...actualEnv,
|
||||
get DEPLOYMENT_ENV() {
|
||||
@@ -828,7 +830,7 @@ describe('userRoutes', () => {
|
||||
const setCookies = res.get('Set-Cookie');
|
||||
|
||||
const publicUser = {
|
||||
..._.omit(minimalUserData, ['externalId', 'unsubscribeId']),
|
||||
...omit(minimalUserData, ['externalId', 'unsubscribeId']),
|
||||
...computedProperties,
|
||||
id: testUser.id,
|
||||
joinDate: new ObjectId(testUser.id).getTimestamp().toISOString(),
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import type { FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import _ from 'lodash';
|
||||
import { FastifyInstance, FastifyReply } from 'fastify';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library';
|
||||
import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library.js';
|
||||
|
||||
import * as schemas from '../../schemas';
|
||||
import * as examEnvironmentSchemas from '../../exam-environment/schemas';
|
||||
import { createResetProperties } from '../../utils/create-user';
|
||||
import { customNanoid } from '../../utils/ids';
|
||||
import { encodeUserToken } from '../../utils/tokens';
|
||||
import { trimTags } from '../../utils/validation';
|
||||
import { generateReportEmail } from '../../utils/email-templates';
|
||||
import { splitUser } from '../helpers/user-utils';
|
||||
import * as schemas from '../../schemas.js';
|
||||
import * as examEnvironmentSchemas from '../../exam-environment/schemas/index.js';
|
||||
import { createResetProperties } from '../../utils/create-user.js';
|
||||
import { customNanoid } from '../../utils/ids.js';
|
||||
import { encodeUserToken } from '../../utils/tokens.js';
|
||||
import { trimTags } from '../../utils/validation.js';
|
||||
import { generateReportEmail } from '../../utils/email-templates.js';
|
||||
import { splitUser } from '../helpers/user-utils.js';
|
||||
import {
|
||||
normalizeChallenges,
|
||||
normalizeFlags,
|
||||
@@ -20,20 +19,20 @@ import {
|
||||
normalizeSurveys,
|
||||
normalizeTwitter,
|
||||
removeNulls
|
||||
} from '../../utils/normalize';
|
||||
import { mapErr, type UpdateReqType } from '../../utils';
|
||||
} from '../../utils/normalize.js';
|
||||
import { mapErr, type UpdateReqType } from '../../utils/index.js';
|
||||
import {
|
||||
getCalendar,
|
||||
getPoints,
|
||||
ProgressTimestamp
|
||||
} from '../../utils/progress';
|
||||
import { DEPLOYMENT_ENV, JWT_SECRET } from '../../utils/env';
|
||||
} from '../../utils/progress.js';
|
||||
import { DEPLOYMENT_ENV, JWT_SECRET } from '../../utils/env.js';
|
||||
import {
|
||||
getExamAttemptHandler,
|
||||
getExamAttemptsByExamIdHandler,
|
||||
getExamAttemptsHandler
|
||||
} from '../../exam-environment/routes/exam-environment';
|
||||
import { ERRORS } from '../../exam-environment/utils/errors';
|
||||
} from '../../exam-environment/routes/exam-environment.js';
|
||||
import { ERRORS } from '../../exam-environment/utils/errors.js';
|
||||
|
||||
/**
|
||||
* Helper function to get the api url from the shared transcript link.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { FastifyPluginCallback } from 'fastify';
|
||||
|
||||
import { devAuth } from '../../plugins/auth-dev';
|
||||
import { devAuth } from '../../plugins/auth-dev.js';
|
||||
|
||||
/**
|
||||
* Route handler for development login.
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
setupServer,
|
||||
superRequest,
|
||||
createSuperRequest
|
||||
} from '../../../vitest.utils';
|
||||
import { AUTH0_DOMAIN } from '../../utils/env';
|
||||
} from '../../../vitest.utils.js';
|
||||
import { AUTH0_DOMAIN } from '../../utils/env.js';
|
||||
|
||||
const mockedFetch = vi.fn();
|
||||
vi.spyOn(globalThis, 'fetch').mockImplementation(mockedFetch);
|
||||
@@ -28,7 +28,9 @@ const mockAuth0ValidEmail = () => ({
|
||||
|
||||
vi.mock('../../utils/env', async () => {
|
||||
const actual =
|
||||
await vi.importActual<typeof import('../../utils/env')>('../../utils/env');
|
||||
await vi.importActual<typeof import('../../utils/env.js')>(
|
||||
'../../utils/env'
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
FCC_ENABLE_DEV_LOGIN_MODE: false
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { FastifyPluginCallback, FastifyRequest } from 'fastify';
|
||||
import isEmail from 'validator/lib/isEmail';
|
||||
import validator from 'validator';
|
||||
|
||||
import { AUTH0_DOMAIN } from '../../utils/env';
|
||||
import { auth0Client } from '../../plugins/auth0';
|
||||
import { createAccessToken } from '../../utils/tokens';
|
||||
import { findOrCreateUser } from '../helpers/auth-helpers';
|
||||
import { AUTH0_DOMAIN } from '../../utils/env.js';
|
||||
import { auth0Client } from '../../plugins/auth0.js';
|
||||
import { createAccessToken } from '../../utils/tokens.js';
|
||||
import { findOrCreateUser } from '../helpers/auth-helpers.js';
|
||||
|
||||
const getEmailFromAuth0 = async (
|
||||
req: FastifyRequest
|
||||
@@ -55,7 +55,7 @@ export const mobileAuth0Routes: FastifyPluginCallback = (
|
||||
type: 'danger'
|
||||
});
|
||||
}
|
||||
if (!isEmail(email)) {
|
||||
if (!validator.default.isEmail(email)) {
|
||||
logger.error('Email is incorrectly formatted for login');
|
||||
|
||||
return reply.status(400).send({
|
||||
|
||||
@@ -14,8 +14,8 @@ import {
|
||||
resetDefaultUser,
|
||||
setupServer,
|
||||
superRequest
|
||||
} from '../../../vitest.utils';
|
||||
import { getFallbackFullStackDate } from '../helpers/certificate-utils';
|
||||
} from '../../../vitest.utils.js';
|
||||
import { getFallbackFullStackDate } from '../helpers/certificate-utils.js';
|
||||
|
||||
const DATE_NOW = Date.now();
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
|
||||
import { find } from 'lodash';
|
||||
import * as schemas from '../../schemas';
|
||||
import { find } from 'lodash-es';
|
||||
import * as schemas from '../../schemas.js';
|
||||
import {
|
||||
certSlugTypeMap,
|
||||
certTypeTitleMap,
|
||||
certTypeIdMap,
|
||||
completionHours,
|
||||
oldDataVizId
|
||||
} from '../../../../shared/config/certification-settings';
|
||||
} from '../../../../shared/config/certification-settings.js';
|
||||
import {
|
||||
getFallbackFullStackDate,
|
||||
isKnownCertSlug
|
||||
} from '../helpers/certificate-utils';
|
||||
import { normalizeDate } from '../../utils/normalize';
|
||||
} from '../helpers/certificate-utils.js';
|
||||
import { normalizeDate } from '../../utils/normalize.js';
|
||||
|
||||
/**
|
||||
* Plugin for the unprotected certificate endpoints.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import request from 'supertest';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
|
||||
import { setupServer } from '../../../vitest.utils';
|
||||
import { endpoints } from './deprecated-endpoints';
|
||||
import { setupServer } from '../../../vitest.utils.js';
|
||||
import { endpoints } from './deprecated-endpoints.js';
|
||||
|
||||
describe('Deprecated endpoints', () => {
|
||||
setupServer();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
|
||||
import * as schemas from '../../schemas';
|
||||
import * as schemas from '../../schemas.js';
|
||||
|
||||
type Endpoints = [string, 'GET' | 'POST'][];
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { setupServer, superRequest } from '../../../vitest.utils';
|
||||
import { setupServer, superRequest } from '../../../vitest.utils.js';
|
||||
|
||||
import { unsubscribeEndpoints } from './deprecated-unsubscribe';
|
||||
import { unsubscribeEndpoints } from './deprecated-unsubscribe.js';
|
||||
|
||||
const urlEncodedMessage =
|
||||
'?messages=info%5B0%5D%3DWe%2520are%2520no%2520longer%2520able%2520to%2520process%2520this%2520unsubscription%2520request.%2520Please%2520go%2520to%2520your%2520settings%2520to%2520update%2520your%2520email%2520preferences';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
|
||||
import { getRedirectParams } from '../../utils/redirection';
|
||||
import { getRedirectParams } from '../../utils/redirection.js';
|
||||
|
||||
type Endpoint = [string, 'GET' | 'POST'];
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, test, expect, beforeAll, vi } from 'vitest';
|
||||
import { setupServer, superRequest } from '../../../vitest.utils';
|
||||
import { setupServer, superRequest } from '../../../vitest.utils.js';
|
||||
|
||||
const testEWalletEmail = 'baz@bar.com';
|
||||
const testSubscriptionId = 'sub_test_id';
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
import Stripe from 'stripe';
|
||||
|
||||
import { STRIPE_SECRET_KEY } from '../../utils/env';
|
||||
import { STRIPE_SECRET_KEY } from '../../utils/env.js';
|
||||
import {
|
||||
donationSubscriptionConfig,
|
||||
allStripeProductIdsArray
|
||||
} from '../../../../shared/config/donation-settings';
|
||||
import * as schemas from '../../schemas';
|
||||
import { inLastFiveMinutes } from '../../utils/validate-donation';
|
||||
import { findOrCreateUser } from '../helpers/auth-helpers';
|
||||
} from '../../../../shared/config/donation-settings.js';
|
||||
import * as schemas from '../../schemas.js';
|
||||
import { inLastFiveMinutes } from '../../utils/validate-donation.js';
|
||||
import { findOrCreateUser } from '../helpers/auth-helpers.js';
|
||||
|
||||
/**
|
||||
* Plugin for public donation endpoints.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
import type { Prisma } from '@prisma/client';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { setupServer, superRequest } from '../../../vitest.utils';
|
||||
import { HOME_LOCATION } from '../../utils/env';
|
||||
import { createUserInput } from '../../utils/create-user';
|
||||
import { setupServer, superRequest } from '../../../vitest.utils.js';
|
||||
import { HOME_LOCATION } from '../../utils/env.js';
|
||||
import { createUserInput } from '../../utils/create-user.js';
|
||||
|
||||
const urlEncodedInfoMessage1 =
|
||||
'?messages=info%5B0%5D%3DWe%2520could%2520not%2520find%2520an%2520account%2520to%2520unsubscribe.';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
import * as schemas from '../../schemas';
|
||||
import { getRedirectParams } from '../../utils/redirection';
|
||||
import * as schemas from '../../schemas.js';
|
||||
import { getRedirectParams } from '../../utils/redirection.js';
|
||||
|
||||
/**
|
||||
* Endpoints to set 'sendQuincyEmail' to true or false using 'unsubscribeId'.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
export * from './auth-dev';
|
||||
export * from './auth';
|
||||
export * from './certificate';
|
||||
export * from './deprecated-endpoints';
|
||||
export * from './deprecated-unsubscribe';
|
||||
export * from './donate';
|
||||
export * from './email-subscription';
|
||||
export * from './signout';
|
||||
export * from './status';
|
||||
export * from './user';
|
||||
export * from './sentry';
|
||||
export * from './auth-dev.js';
|
||||
export * from './auth.js';
|
||||
export * from './certificate.js';
|
||||
export * from './deprecated-endpoints.js';
|
||||
export * from './deprecated-unsubscribe.js';
|
||||
export * from './donate.js';
|
||||
export * from './email-subscription.js';
|
||||
export * from './signout.js';
|
||||
export * from './status.js';
|
||||
export * from './user.js';
|
||||
export * from './sentry.js';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
import { type FastifyInstance, type FastifyReply } from 'fastify';
|
||||
|
||||
import { UpdateReqType } from '../../utils';
|
||||
import * as schemas from '../../schemas';
|
||||
import { UpdateReqType } from '../../utils/index.js';
|
||||
import * as schemas from '../../schemas.js';
|
||||
|
||||
/**
|
||||
* Plugin for Sentry-related endpoints.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { devLogin, setupServer, superRequest } from '../../../vitest.utils';
|
||||
import { HOME_LOCATION } from '../../utils/env';
|
||||
import { devLogin, setupServer, superRequest } from '../../../vitest.utils.js';
|
||||
import { HOME_LOCATION } from '../../utils/env.js';
|
||||
|
||||
describe('GET /signout', () => {
|
||||
setupServer();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { FastifyPluginCallback } from 'fastify';
|
||||
|
||||
import { getRedirectParams } from '../../utils/redirection';
|
||||
import { getRedirectParams } from '../../utils/redirection.js';
|
||||
|
||||
/**
|
||||
* Route handler for signing out.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { setupServer, superRequest } from '../../../vitest.utils';
|
||||
import { DEPLOYMENT_VERSION } from '../../utils/env';
|
||||
import { setupServer, superRequest } from '../../../vitest.utils.js';
|
||||
import { DEPLOYMENT_VERSION } from '../../utils/env.js';
|
||||
|
||||
describe('/status', () => {
|
||||
setupServer();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
|
||||
import { DEPLOYMENT_VERSION } from '../../utils/env';
|
||||
import { DEPLOYMENT_VERSION } from '../../utils/env.js';
|
||||
|
||||
/**
|
||||
* Plugin for the health check endpoint.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Prisma } from '@prisma/client';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import _ from 'lodash';
|
||||
import { omit } from 'lodash-es';
|
||||
import {
|
||||
describe,
|
||||
it,
|
||||
@@ -12,13 +12,13 @@ import {
|
||||
vi
|
||||
} from 'vitest';
|
||||
|
||||
import { createUserInput } from '../../utils/create-user';
|
||||
import { createUserInput } from '../../utils/create-user.js';
|
||||
import {
|
||||
defaultUserEmail,
|
||||
setupServer,
|
||||
createSuperRequest
|
||||
} from '../../../vitest.utils';
|
||||
import { replacePrivateData } from './user';
|
||||
} from '../../../vitest.utils.js';
|
||||
import { replacePrivateData } from './user.js';
|
||||
|
||||
const mockedFetch = vi.fn();
|
||||
vi.spyOn(globalThis, 'fetch').mockImplementation(mockedFetch);
|
||||
@@ -378,7 +378,7 @@ describe('userRoutes', () => {
|
||||
// it should contain the entire body.
|
||||
const publicUser = {
|
||||
// TODO(Post-MVP, maybe): return completedSurveys?
|
||||
..._.omit(publicUserData, 'completedSurveys'),
|
||||
...omit(publicUserData, 'completedSurveys'),
|
||||
username: publicUsername,
|
||||
joinDate: new ObjectId(testUser.id).getTimestamp().toISOString(),
|
||||
profileUI: unlockedUserProfileUI
|
||||
@@ -592,9 +592,7 @@ describe('get-public-profile helpers', () => {
|
||||
});
|
||||
|
||||
test('returns the expected public user object if all showX flags are true', () => {
|
||||
expect(replacePrivateData(user)).toEqual(
|
||||
_.omit(user, ['id', 'profileUI'])
|
||||
);
|
||||
expect(replacePrivateData(user)).toEqual(omit(user, ['id', 'profileUI']));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Portfolio } from '@prisma/client';
|
||||
import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import _ from 'lodash';
|
||||
import { omit } from 'lodash-es';
|
||||
|
||||
import { isRestricted } from '../helpers/is-restricted';
|
||||
import * as schemas from '../../schemas';
|
||||
import { splitUser } from '../helpers/user-utils';
|
||||
import { isRestricted } from '../helpers/is-restricted.js';
|
||||
import * as schemas from '../../schemas.js';
|
||||
import { splitUser } from '../helpers/user-utils.js';
|
||||
import {
|
||||
normalizeChallenges,
|
||||
NormalizedChallenge,
|
||||
@@ -13,14 +13,14 @@ import {
|
||||
normalizeProfileUI,
|
||||
normalizeTwitter,
|
||||
removeNulls
|
||||
} from '../../utils/normalize';
|
||||
} from '../../utils/normalize.js';
|
||||
import {
|
||||
Calendar,
|
||||
getCalendar,
|
||||
getPoints,
|
||||
ProgressTimestamp
|
||||
} from '../../utils/progress';
|
||||
import { challengeTypes } from '../../../../shared/config/challenge-types';
|
||||
} from '../../utils/progress.js';
|
||||
import { challengeTypes } from '../../../../shared/config/challenge-types.js';
|
||||
|
||||
type ProfileUI = Partial<{
|
||||
isLocked: boolean;
|
||||
@@ -137,7 +137,7 @@ export const userPublicGetRoutes: FastifyPluginCallbackTypebox = (
|
||||
|
||||
const [flags, rest] = splitUser(user);
|
||||
|
||||
const publicUser = _.omit(rest, [
|
||||
const publicUser = omit(rest, [
|
||||
'currentChallengeId',
|
||||
'email',
|
||||
'emailVerified',
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import Ajv from 'ajv';
|
||||
import secureSchema from 'ajv/lib/refs/json-schema-secure.json';
|
||||
import secureSchema from 'ajv/lib/refs/json-schema-secure.json' with { type: 'json' };
|
||||
import { Ajv } from 'ajv';
|
||||
|
||||
import * as schemas from './schemas';
|
||||
import * as schemas from './schemas.js';
|
||||
|
||||
// it's not strict, but that's okay - we're not using it to validate data
|
||||
const ajv = new Ajv({ strictTypes: false });
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
export { getPublicProfile } from './schemas/users/get-public-profile';
|
||||
export { userExists } from './schemas/users/exists';
|
||||
export { certSlug } from './schemas/certificate/cert-slug';
|
||||
export { certificateVerify } from './schemas/certificate/certificate-verify';
|
||||
export { backendChallengeCompleted } from './schemas/challenge/backend-challenge-completed';
|
||||
export { coderoadChallengeCompleted } from './schemas/challenge/coderoad-challenge-completed';
|
||||
export { exam } from './schemas/challenge/exam';
|
||||
export { examChallengeCompleted } from './schemas/challenge/exam-challenge-completed';
|
||||
export { dailyCodingChallengeCompleted } from './schemas/challenge/daily-coding-challenge-completed';
|
||||
export { modernChallengeCompleted } from './schemas/challenge/modern-challenge-completed';
|
||||
export { msTrophyChallengeCompleted } from './schemas/challenge/ms-trophy-challenge-completed';
|
||||
export { projectCompleted } from './schemas/challenge/project-completed';
|
||||
export { saveChallenge } from './schemas/challenge/save-challenge';
|
||||
export { submitQuizAttempt } from './schemas/challenge/submit-quiz-attempt';
|
||||
export { deprecatedEndpoints } from './schemas/deprecated';
|
||||
export { addDonation } from './schemas/donate/add-donation';
|
||||
export { chargeStripeCard } from './schemas/donate/charge-stripe-card';
|
||||
export { chargeStripe } from './schemas/donate/charge-stripe';
|
||||
export { createStripePaymentIntent } from './schemas/donate/create-stripe-payment-intent';
|
||||
export { updateStripeCard } from './schemas/donate/update-stripe-card';
|
||||
export { resubscribe } from './schemas/email-subscription/resubscribe';
|
||||
export { unsubscribe } from './schemas/email-subscription/unsubscribe';
|
||||
export { updateMyAbout } from './schemas/settings/update-my-about';
|
||||
export { confirmEmail } from './schemas/settings/confirm-email';
|
||||
export { updateMyClassroomMode } from './schemas/settings/update-my-classroom-mode';
|
||||
export { updateMyEmail } from './schemas/settings/update-my-email';
|
||||
export { updateMyHonesty } from './schemas/settings/update-my-honesty';
|
||||
export { updateMyKeyboardShortcuts } from './schemas/settings/update-my-keyboard-shortcuts';
|
||||
export { updateMyPortfolio } from './schemas/settings/update-my-portfolio';
|
||||
export { updateMyPrivacyTerms } from './schemas/settings/update-my-privacy-terms';
|
||||
export { updateMyProfileUI } from './schemas/settings/update-my-profile-ui';
|
||||
export { updateMyQuincyEmail } from './schemas/settings/update-my-quincy-email';
|
||||
export { updateMySocials } from './schemas/settings/update-my-socials';
|
||||
export { updateMyTheme } from './schemas/settings/update-my-theme';
|
||||
export { updateMyUsername } from './schemas/settings/update-my-username';
|
||||
export { deleteMsUsername } from './schemas/user/delete-ms-username';
|
||||
export { deleteMyAccount } from './schemas/user/delete-my-account';
|
||||
export { deleteUserToken } from './schemas/user/delete-user-token';
|
||||
export { getSessionUser } from './schemas/user/get-session-user';
|
||||
export { postMsUsername } from './schemas/user/post-ms-username';
|
||||
export { reportUser } from './schemas/user/report-user';
|
||||
export { resetMyProgress } from './schemas/user/reset-my-progress';
|
||||
export { submitSurvey } from './schemas/user/submit-survey';
|
||||
export { userExamEnvironmentToken } from './schemas/user/exam-environment-token';
|
||||
export { sentryPostEvent } from './schemas/sentry/event';
|
||||
export { getPublicProfile } from './schemas/users/get-public-profile.js';
|
||||
export { userExists } from './schemas/users/exists.js';
|
||||
export { certSlug } from './schemas/certificate/cert-slug.js';
|
||||
export { certificateVerify } from './schemas/certificate/certificate-verify.js';
|
||||
export { backendChallengeCompleted } from './schemas/challenge/backend-challenge-completed.js';
|
||||
export { coderoadChallengeCompleted } from './schemas/challenge/coderoad-challenge-completed.js';
|
||||
export { exam } from './schemas/challenge/exam.js';
|
||||
export { examChallengeCompleted } from './schemas/challenge/exam-challenge-completed.js';
|
||||
export { dailyCodingChallengeCompleted } from './schemas/challenge/daily-coding-challenge-completed.js';
|
||||
export { modernChallengeCompleted } from './schemas/challenge/modern-challenge-completed.js';
|
||||
export { msTrophyChallengeCompleted } from './schemas/challenge/ms-trophy-challenge-completed.js';
|
||||
export { projectCompleted } from './schemas/challenge/project-completed.js';
|
||||
export { saveChallenge } from './schemas/challenge/save-challenge.js';
|
||||
export { submitQuizAttempt } from './schemas/challenge/submit-quiz-attempt.js';
|
||||
export { deprecatedEndpoints } from './schemas/deprecated/index.js';
|
||||
export { addDonation } from './schemas/donate/add-donation.js';
|
||||
export { chargeStripeCard } from './schemas/donate/charge-stripe-card.js';
|
||||
export { chargeStripe } from './schemas/donate/charge-stripe.js';
|
||||
export { createStripePaymentIntent } from './schemas/donate/create-stripe-payment-intent.js';
|
||||
export { updateStripeCard } from './schemas/donate/update-stripe-card.js';
|
||||
export { resubscribe } from './schemas/email-subscription/resubscribe.js';
|
||||
export { unsubscribe } from './schemas/email-subscription/unsubscribe.js';
|
||||
export { updateMyAbout } from './schemas/settings/update-my-about.js';
|
||||
export { confirmEmail } from './schemas/settings/confirm-email.js';
|
||||
export { updateMyClassroomMode } from './schemas/settings/update-my-classroom-mode.js';
|
||||
export { updateMyEmail } from './schemas/settings/update-my-email.js';
|
||||
export { updateMyHonesty } from './schemas/settings/update-my-honesty.js';
|
||||
export { updateMyKeyboardShortcuts } from './schemas/settings/update-my-keyboard-shortcuts.js';
|
||||
export { updateMyPortfolio } from './schemas/settings/update-my-portfolio.js';
|
||||
export { updateMyPrivacyTerms } from './schemas/settings/update-my-privacy-terms.js';
|
||||
export { updateMyProfileUI } from './schemas/settings/update-my-profile-ui.js';
|
||||
export { updateMyQuincyEmail } from './schemas/settings/update-my-quincy-email.js';
|
||||
export { updateMySocials } from './schemas/settings/update-my-socials.js';
|
||||
export { updateMyTheme } from './schemas/settings/update-my-theme.js';
|
||||
export { updateMyUsername } from './schemas/settings/update-my-username.js';
|
||||
export { deleteMsUsername } from './schemas/user/delete-ms-username.js';
|
||||
export { deleteMyAccount } from './schemas/user/delete-my-account.js';
|
||||
export { deleteUserToken } from './schemas/user/delete-user-token.js';
|
||||
export { getSessionUser } from './schemas/user/get-session-user.js';
|
||||
export { postMsUsername } from './schemas/user/post-ms-username.js';
|
||||
export { reportUser } from './schemas/user/report-user.js';
|
||||
export { resetMyProgress } from './schemas/user/reset-my-progress.js';
|
||||
export { submitSurvey } from './schemas/user/submit-survey.js';
|
||||
export { userExamEnvironmentToken } from './schemas/user/exam-environment-token.js';
|
||||
export { sentryPostEvent } from './schemas/sentry/event.js';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { Certification } from '../../../../shared/config/certification-settings';
|
||||
import { genericError } from '../types';
|
||||
import { Certification } from '../../../../shared/config/certification-settings.js';
|
||||
import { genericError } from '../types.js';
|
||||
|
||||
export const certSlug = {
|
||||
params: Type.Object({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { genericError, isCertMap } from '../types';
|
||||
import { genericError, isCertMap } from '../types.js';
|
||||
|
||||
export const certificateVerify = {
|
||||
// TODO(POST_MVP): Remove partial validation from route for schema validation
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { genericError } from '../types';
|
||||
import { genericError } from '../types.js';
|
||||
|
||||
export const backendChallengeCompleted = {
|
||||
body: Type.Object({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { examResults, genericError } from '../types';
|
||||
import { examResults, genericError } from '../types.js';
|
||||
|
||||
export const examChallengeCompleted = {
|
||||
body: Type.Object({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { genericError } from '../types';
|
||||
import { genericError } from '../types.js';
|
||||
|
||||
export const exam = {
|
||||
params: Type.Object({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { genericError, savedChallenge } from '../types';
|
||||
import { genericError, savedChallenge } from '../types.js';
|
||||
|
||||
export const modernChallengeCompleted = {
|
||||
body: Type.Object({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { genericError } from '../types';
|
||||
import { genericError } from '../types.js';
|
||||
|
||||
export const projectCompleted = {
|
||||
body: Type.Object({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { file, genericError, savedChallenge } from '../types';
|
||||
import { file, genericError, savedChallenge } from '../types.js';
|
||||
|
||||
export const saveChallenge = {
|
||||
body: Type.Object({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { genericError } from '../types';
|
||||
import { genericError } from '../types.js';
|
||||
|
||||
export const submitQuizAttempt = {
|
||||
body: Type.Object({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { genericError } from '../types';
|
||||
import { genericError } from '../types.js';
|
||||
|
||||
export const updateStripeCard = {
|
||||
body: Type.Object({}),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Type } from '@fastify/type-provider-typebox';
|
||||
import { genericError } from '../types';
|
||||
import { genericError } from '../types.js';
|
||||
|
||||
export const updateMyClassroomMode = {
|
||||
body: Type.Object({
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user