feat(api): update my classroom mode (#54009)

This commit is contained in:
Sem Bauke
2024-03-19 14:42:28 +01:00
committed by GitHub
parent dbac720ba7
commit e8e9f40cc5
5 changed files with 118 additions and 36 deletions
+1
View File
@@ -198,6 +198,7 @@ model user {
verificationToken String? // Undefined
website String? // Undefined
yearsTopContributor String[] @default([]) // Undefined | String[]
isClassroomAccount Boolean? // Undefined
}
// -----------------------------------
+2 -1
View File
@@ -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
}
// -----------------------------------
+64 -35
View File
@@ -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);
});
});
});
+36
View File
@@ -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();
};
+15
View File
@@ -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: {