in apps/newsletters-api/src/app/routes/newsletters.ts [86:211]
export function registerReadWriteNewsletterRoutes(app: FastifyInstance) {
const hasAccessHook = async (
request: FastifyRequest,
reply: FastifyReply,
) => {
const user = getUserProfile(request);
const isAuthorised = await hasEditAccess(user.profile);
const { body } = request;
const update = replaceNullWithUndefinedForUnknown(body);
if (!isPartialNewsletterData(update)) {
void reply.status(400).send(makeErrorResponse('invalid update data'));
} else {
const isAuthorisedForUpdate =
await isAuthorisedToMakeRequestedNewsletterUpdate(user.profile, update);
if (!isAuthorised || !isAuthorisedForUpdate) {
void reply
.status(403)
.send(makeErrorResponse('You do not have edit access'));
}
}
};
app.patch<{
Params: { newsletterId: string };
Body: unknown;
}>(
'/api/newsletters/:newsletterId',
{ preValidation: hasAccessHook },
async (req, res) => {
const user = getUserProfile(req);
const { newsletterId } = req.params;
const { body: modifications } = req;
const newsletterIdAsNumber = Number(newsletterId);
if (isNaN(newsletterIdAsNumber)) {
return res
.status(400)
.send(makeErrorResponse(`Non numeric id provided`));
}
replaceNullWithUndefinedForUnknown(modifications);
if (!isPartialNewsletterData(modifications)) {
return res
.status(400)
.send(makeErrorResponse(`Not a valid partial newsletter`));
}
// This test would never fail on the current implementation since
// user.profile must be defined or there would be an accessDeniedError.
// Kept in to preserve type-safety.
if (!user.profile) {
return res.status(403).send(makeErrorResponse('No user profile.'));
}
const storageResponse = await newsletterStore.update(
newsletterIdAsNumber,
modifications,
user.profile,
);
if (!storageResponse.ok) {
return res
.status(mapStorageFailureReasonToStatusCode(storageResponse.reason))
.send(makeErrorResponse(storageResponse.message));
}
return makeSuccessResponse(storageResponse.data);
},
);
app.post<{
Params: { newsletterId: string };
Body: unknown;
}>(
'/api/newsletters/:newsletterId',
{ preValidation: hasAccessHook },
async (req, res) => {
const user = getUserProfile(req);
const accessDeniedError = await makeAccessDeniedApiResponse(
user.profile,
'editNewsletters',
);
if (accessDeniedError) {
return res.status(403).send(accessDeniedError);
}
const { newsletterId } = req.params;
const { body: newsletter } = req;
const newsletterIdAsNumber = Number(newsletterId);
if (isNaN(newsletterIdAsNumber)) {
return res
.status(400)
.send(makeErrorResponse(`Non numeric id provided`));
}
replaceNullWithUndefinedForUnknown(newsletter);
if (!isNewsletterData(newsletter)) {
return res
.status(400)
.send(makeErrorResponse(`Not a valid newsletter`));
}
if (!user.profile) {
return res.status(403).send(makeErrorResponse('No user profile'));
}
const storageResponse = await newsletterStore.replace(
newsletterIdAsNumber,
newsletter,
user.profile,
);
if (!storageResponse.ok) {
return res
.status(mapStorageFailureReasonToStatusCode(storageResponse.reason))
.send(makeErrorResponse(storageResponse.message));
}
return makeSuccessResponse(storageResponse.data);
},
);
}