feat(api): reset progress endpoint (#50432)

---------

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
Niraj Nandish
2023-05-26 12:26:26 +04:00
committed by GitHub
parent 405a40b6b0
commit 8171abfa6d
3 changed files with 152 additions and 22 deletions

View File

@@ -1,17 +1,48 @@
import request from 'supertest';
import { setupServer, superRequest } from '../../jest.utils';
const baseProgressData = {
currentChallengeId: '',
isRespWebDesignCert: false,
is2018DataVisCert: false,
isFrontEndLibsCert: false,
isJsAlgoDataStructCert: false,
isApisMicroservicesCert: false,
isInfosecQaCert: false,
isQaCertV7: false,
isInfosecCertV7: false,
is2018FullStackCert: false,
isFrontEndCert: false,
isBackEndCert: false,
isDataVisCert: false,
isFullStackCert: false,
isSciCompPyCertV7: false,
isDataAnalysisPyCertV7: false,
isMachineLearningPyCertV7: false,
isRelationalDatabaseCertV8: false,
isCollegeAlgebraPyCertV8: false,
completedChallenges: [],
savedChallenges: [],
partiallyCompletedChallenges: [],
needsModeration: false
};
const modifiedProgressData = {
...baseProgressData,
currentChallengeId: 'hello there',
isRespWebDesignCert: true,
isJsAlgoDataStructCert: true,
isRelationalDatabaseCertV8: true,
needsModeration: true
};
describe('userRoutes', () => {
setupServer();
describe('Authenticated user', () => {
let setCookies: string[];
beforeAll(async () => {
const res = await request(fastifyTestInstance?.server).get(
'/auth/dev-callback'
);
beforeEach(async () => {
const res = await superRequest('/auth/dev-callback', { method: 'GET' });
setCookies = res.get('Set-Cookie');
});
@@ -22,7 +53,7 @@ describe('userRoutes', () => {
setCookies
});
const userCount = await fastifyTestInstance?.prisma.user.count({
const userCount = await fastifyTestInstance.prisma.user.count({
where: { email: 'foo@bar.com' }
});
@@ -31,6 +62,30 @@ describe('userRoutes', () => {
expect(userCount).toBe(0);
});
});
describe('/account/reset-progress', () => {
test('POST returns 200 status code with empty object', async () => {
await fastifyTestInstance.prisma.user.updateMany({
where: { email: 'foo@bar.com' },
data: modifiedProgressData
});
const response = await superRequest('/account/reset-progress', {
method: 'POST',
setCookies
});
const user = await fastifyTestInstance.prisma.user.findFirst({
where: { email: 'foo@bar.com' }
});
expect(response.status).toBe(200);
expect(response.body).toStrictEqual({});
expect(user?.progressTimestamps).toHaveLength(1);
expect(user).toMatchObject(baseProgressData);
});
});
});
describe('Unauthenticated user', () => {
@@ -44,5 +99,15 @@ describe('userRoutes', () => {
expect(response?.statusCode).toBe(401);
});
});
describe('/account/reset-progress', () => {
test('POST returns 401 status code with error message', async () => {
const response = await superRequest('/account/reset-progress', {
method: 'POST'
});
expect(response?.statusCode).toBe(401);
});
});
});
});

View File

@@ -1,7 +1,6 @@
import {
Type,
type FastifyPluginCallbackTypebox
} from '@fastify/type-provider-typebox';
import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
import { schemas } from '../schemas';
export const userRoutes: FastifyPluginCallbackTypebox = (
fastify,
@@ -13,17 +12,7 @@ export const userRoutes: FastifyPluginCallbackTypebox = (
fastify.post(
'/account/delete',
{
schema: {
response: {
200: Type.Object({}),
500: Type.Object({
message: Type.Literal(
'Oops! Something went wrong. Please try again in a moment or contact support@freecodecamp.org if the error persists.'
),
type: Type.Literal('danger')
})
}
}
schema: schemas.deleteMyAccount
},
async (req, reply) => {
try {
@@ -49,5 +38,58 @@ export const userRoutes: FastifyPluginCallbackTypebox = (
}
);
fastify.post(
'/account/reset-progress',
{
schema: schemas.resetMyProgress
},
async (req, reply) => {
try {
await fastify.prisma.userToken.deleteMany({
where: { userId: req.session.user.id }
});
await fastify.prisma.user.update({
where: { id: req.session.user.id },
data: {
progressTimestamps: [Date.now()],
currentChallengeId: '',
isRespWebDesignCert: false,
is2018DataVisCert: false,
isFrontEndLibsCert: false,
isJsAlgoDataStructCert: false,
isApisMicroservicesCert: false,
isInfosecQaCert: false,
isQaCertV7: false,
isInfosecCertV7: false,
is2018FullStackCert: false,
isFrontEndCert: false,
isBackEndCert: false,
isDataVisCert: false,
isFullStackCert: false,
isSciCompPyCertV7: false,
isDataAnalysisPyCertV7: false,
isMachineLearningPyCertV7: false,
isRelationalDatabaseCertV8: false,
isCollegeAlgebraPyCertV8: false,
completedChallenges: [],
savedChallenges: [],
partiallyCompletedChallenges: [],
needsModeration: false
}
});
return {};
} catch (err) {
fastify.log.error(err);
void reply.code(500);
return {
message:
'Oops! Something went wrong. Please try again in a moment or contact support@freecodecamp.org if the error persists.',
type: 'danger'
};
}
}
);
done();
};

View File

@@ -123,6 +123,29 @@ export const schemas = {
})
}
},
// User:
deleteMyAccount: {
response: {
200: Type.Object({}),
500: Type.Object({
message: Type.Literal(
'Oops! Something went wrong. Please try again in a moment or contact support@freecodecamp.org if the error persists.'
),
type: Type.Literal('danger')
})
}
},
resetMyProgress: {
response: {
200: Type.Object({}),
500: Type.Object({
message: Type.Literal(
'Oops! Something went wrong. Please try again in a moment or contact support@freecodecamp.org if the error persists.'
),
type: Type.Literal('danger')
})
}
},
// Deprecated endpoints:
deprecatedEndpoints: {
response: {