mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat(api): update my classroom mode (#54009)
This commit is contained in:
@@ -198,6 +198,7 @@ model user {
|
||||
verificationToken String? // Undefined
|
||||
website String? // Undefined
|
||||
yearsTopContributor String[] @default([]) // Undefined | String[]
|
||||
isClassroomAccount Boolean? // Undefined
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
|
||||
@@ -114,7 +114,7 @@ model user {
|
||||
is2018DataVisCert Boolean? // Undefined
|
||||
is2018FullStackCert Boolean? // Undefined
|
||||
isCollegeAlgebraPyCertV8 Boolean? // Undefined
|
||||
isUpcomingPythonCertV8 Boolean? // Undefined
|
||||
isUpcomingPythonCertV8 Boolean? // Undefined
|
||||
keyboardShortcuts Boolean? // Undefined
|
||||
linkedin String? // Null | Undefined
|
||||
location String? // Null
|
||||
@@ -139,6 +139,7 @@ model user {
|
||||
verificationToken String? // Undefined
|
||||
website String? // Undefined
|
||||
yearsTopContributor String[] // Undefined | String[]
|
||||
isClassroomAccount Boolean? // Undefined
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
|
||||
@@ -689,51 +689,80 @@ Please wait 5 minutes to resend an authentication link.`
|
||||
expect(response.statusCode).toEqual(400);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Unauthenticated User', () => {
|
||||
let setCookies: string[];
|
||||
describe('/update-my-classroom-mode', () => {
|
||||
test('PUT returns 200 status code with "success" message', async () => {
|
||||
const response = await superPut('/update-my-classroom-mode').send({
|
||||
isClassroomAccount: true
|
||||
});
|
||||
|
||||
// Get the CSRF cookies from an unprotected route
|
||||
beforeAll(async () => {
|
||||
const res = await superRequest('/status/ping', { method: 'GET' });
|
||||
setCookies = res.get('Set-Cookie');
|
||||
expect(response.body).toEqual({
|
||||
message: 'flash.classroom-mode-updated',
|
||||
type: 'success'
|
||||
});
|
||||
|
||||
expect(response.statusCode).toEqual(200);
|
||||
});
|
||||
|
||||
test('After updating the classroom mode, the user should have this property set', async () => {
|
||||
await superPut('/update-my-classroom-mode').send({
|
||||
isClassroomAccount: false
|
||||
});
|
||||
|
||||
const user = await fastifyTestInstance?.prisma.user.findFirst({
|
||||
where: {
|
||||
email: developerUserEmail
|
||||
}
|
||||
});
|
||||
|
||||
expect(user?.isClassroomAccount).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
const endpoints: { path: string; method: 'PUT' }[] = [
|
||||
{ path: '/update-my-profileui', method: 'PUT' },
|
||||
{ path: '/update-my-theme', method: 'PUT' },
|
||||
{ path: '/update-my-username', method: 'PUT' },
|
||||
{ path: '/update-my-keyboard-shortcuts', method: 'PUT' },
|
||||
{ path: '/update-my-socials', method: 'PUT' },
|
||||
{ path: '/update-my-quincy-email', method: 'PUT' },
|
||||
{ path: '/update-my-about', method: 'PUT' },
|
||||
{ path: '/update-my-honesty', method: 'PUT' },
|
||||
{ path: '/update-privacy-terms', method: 'PUT' },
|
||||
{ path: '/update-my-portfolio', method: 'PUT' }
|
||||
];
|
||||
describe('Unauthenticated User', () => {
|
||||
let setCookies: string[];
|
||||
|
||||
endpoints.forEach(({ path, method }) => {
|
||||
test(`${method} ${path} returns 401 status code with error message`, async () => {
|
||||
const response = await superRequest(path, {
|
||||
method,
|
||||
setCookies
|
||||
// Get the CSRF cookies from an unprotected route
|
||||
beforeAll(async () => {
|
||||
const res = await superRequest('/status/ping', { method: 'GET' });
|
||||
setCookies = res.get('Set-Cookie');
|
||||
});
|
||||
|
||||
const endpoints: { path: string; method: 'PUT' }[] = [
|
||||
{ path: '/update-my-profileui', method: 'PUT' },
|
||||
{ path: '/update-my-theme', method: 'PUT' },
|
||||
{ path: '/update-my-username', method: 'PUT' },
|
||||
{ path: '/update-my-keyboard-shortcuts', method: 'PUT' },
|
||||
{ path: '/update-my-socials', method: 'PUT' },
|
||||
{ path: '/update-my-quincy-email', method: 'PUT' },
|
||||
{ path: '/update-my-about', method: 'PUT' },
|
||||
{ path: '/update-my-honesty', method: 'PUT' },
|
||||
{ path: '/update-privacy-terms', method: 'PUT' },
|
||||
{ path: '/update-my-portfolio', method: 'PUT' }
|
||||
];
|
||||
|
||||
endpoints.forEach(({ path, method }) => {
|
||||
test(`${method} ${path} returns 401 status code with error message`, async () => {
|
||||
const response = await superRequest(path, {
|
||||
method,
|
||||
setCookies
|
||||
});
|
||||
expect(response.statusCode).toBe(401);
|
||||
});
|
||||
expect(response.statusCode).toBe(401);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isPictureWithProtocol', () => {
|
||||
test('Valid protocol', () => {
|
||||
expect(isPictureWithProtocol('https://www.example.com/')).toEqual(true);
|
||||
expect(isPictureWithProtocol('http://www.example.com/')).toEqual(true);
|
||||
});
|
||||
describe('isPictureWithProtocol', () => {
|
||||
test('Valid protocol', () => {
|
||||
expect(isPictureWithProtocol('https://www.example.com/')).toEqual(true);
|
||||
expect(isPictureWithProtocol('http://www.example.com/')).toEqual(true);
|
||||
});
|
||||
|
||||
test('Invalid protocol', () => {
|
||||
expect(isPictureWithProtocol('htps://www.example.com/')).toEqual(false);
|
||||
expect(isPictureWithProtocol('tp://www.example.com/')).toEqual(false);
|
||||
expect(isPictureWithProtocol('www.example.com/')).toEqual(false);
|
||||
test('Invalid protocol', () => {
|
||||
expect(isPictureWithProtocol('htps://www.example.com/')).toEqual(false);
|
||||
expect(isPictureWithProtocol('tp://www.example.com/')).toEqual(false);
|
||||
expect(isPictureWithProtocol('www.example.com/')).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -576,5 +576,41 @@ ${isLinkSentWithinLimitTTL}`
|
||||
}
|
||||
);
|
||||
|
||||
fastify.put(
|
||||
'/update-my-classroom-mode',
|
||||
{
|
||||
schema: schemas.updateMyClassroomMode,
|
||||
errorHandler: (error, request, reply) => {
|
||||
if (error.validation) {
|
||||
void reply.code(403);
|
||||
void reply.send({ message: 'flash.wrong-updating', type: 'danger' });
|
||||
} else {
|
||||
fastify.errorHandler(error, request, reply);
|
||||
}
|
||||
}
|
||||
},
|
||||
async (req, reply) => {
|
||||
try {
|
||||
const classroomMode = req.body.isClassroomAccount;
|
||||
|
||||
await fastify.prisma.user.update({
|
||||
where: { id: req.session.user.id },
|
||||
data: {
|
||||
isClassroomAccount: classroomMode
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
message: 'flash.classroom-mode-updated',
|
||||
type: 'success'
|
||||
} as const;
|
||||
} catch (err) {
|
||||
fastify.log.error(err);
|
||||
void reply.code(403);
|
||||
return { message: 'flash.wrong-updating', type: 'danger' } as const;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
done();
|
||||
};
|
||||
|
||||
@@ -297,6 +297,21 @@ export const schemas = {
|
||||
})
|
||||
}
|
||||
},
|
||||
updateMyClassroomMode: {
|
||||
body: Type.Object({
|
||||
isClassroomAccount: Type.Boolean()
|
||||
}),
|
||||
response: {
|
||||
200: Type.Object({
|
||||
message: Type.Literal('flash.classroom-mode-updated'),
|
||||
type: Type.Literal('success')
|
||||
}),
|
||||
403: Type.Object({
|
||||
message: Type.Literal('flash.wrong-updating'),
|
||||
type: Type.Literal('danger')
|
||||
})
|
||||
}
|
||||
},
|
||||
// User:
|
||||
deleteMyAccount: {
|
||||
response: {
|
||||
|
||||
Reference in New Issue
Block a user