Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/api/.env-example
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ COOKIE_PASSWORD=blablablblablablblablablblablabl
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=

APP_URL=http://app.devfaq.localhost:3000
REVALIDATION_TOKEN=

DATABASE_URL=postgres://postgres:api2022@localhost:54421/database_development
6 changes: 6 additions & 0 deletions apps/api/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ export function getConfig(name: "NODE_ENV"): "production" | "development";
export function getConfig(name: "ENV"): "production" | "staging" | "development" | "test";
export function getConfig(name: "GITHUB_CLIENT_ID"): string;
export function getConfig(name: "GITHUB_CLIENT_SECRET"): string;
export function getConfig(name: "APP_URL"): string;
export function getConfig(name: "REVALIDATION_TOKEN"): string;
export function getConfig(name: "GIT_BRANCH"): string;
export function getConfig(name: "GIT_COMMIT_HASH"): string;
export function getConfig(name: "VERSION"): string;
Expand All @@ -21,6 +23,10 @@ export function getConfig(name: string): string | number {
case "GITHUB_CLIENT_ID":
case "GITHUB_CLIENT_SECRET":
return val || "";
case "APP_URL":
return val || "";
case "REVALIDATION_TOKEN":
return val || "";
case "GIT_BRANCH":
return val || "(unknown_branch)";
case "GIT_COMMIT_HASH":
Expand Down
12 changes: 11 additions & 1 deletion apps/api/modules/answers/answers.routes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { TypeBoxTypeProvider } from "@fastify/type-provider-typebox";
import { Prisma } from "@prisma/client";
import { FastifyPluginAsync, preHandlerAsyncHookHandler, preHandlerHookHandler } from "fastify";
import { revalidate } from "../../services/revalidation.service.js";
import { PrismaErrorCode } from "../db/prismaErrors.js";
import { isPrismaError } from "../db/prismaErrors.util.js";
import { dbAnswerToDto } from "./answers.mapper.js";
Expand All @@ -15,6 +16,7 @@ import {
export const answerSelect = (userId: number) => {
return {
id: true,
questionId: true,
content: true,
sources: true,
createdAt: true,
Expand All @@ -34,6 +36,8 @@ export const answerSelect = (userId: number) => {
} satisfies Prisma.QuestionAnswerSelect;
};

const revalidateQuestion = (id: number) => revalidate(`/questions/p/${id}`);

const answersPlugin: FastifyPluginAsync = async (fastify) => {
const checkAnswerUserHook: preHandlerAsyncHookHandler = async (request) => {
const {
Expand Down Expand Up @@ -101,6 +105,8 @@ const answersPlugin: FastifyPluginAsync = async (fastify) => {
select: answerSelect(request.session.data?._user.id || 0),
});

await revalidateQuestion(id);

return { data: dbAnswerToDto(answer) };
} catch (err) {
if (isPrismaError(err) && err.code === PrismaErrorCode.UniqueKeyViolation) {
Expand Down Expand Up @@ -132,6 +138,8 @@ const answersPlugin: FastifyPluginAsync = async (fastify) => {
select: answerSelect(request.session.data?._user.id || 0),
});

await revalidateQuestion(answer.questionId);

return { data: dbAnswerToDto(answer) };
},
});
Expand All @@ -146,10 +154,12 @@ const answersPlugin: FastifyPluginAsync = async (fastify) => {
params: { id },
} = request;

await fastify.db.questionAnswer.delete({
const { questionId } = await fastify.db.questionAnswer.delete({
where: { id },
});

await revalidateQuestion(questionId);

return reply.status(204).send();
},
});
Expand Down
9 changes: 9 additions & 0 deletions apps/api/services/revalidation.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { getConfig } from "../config/config.js";

export const revalidate = (path: string) =>
fetch(
`${getConfig("APP_URL")}/api/revalidation?token=${getConfig(
"REVALIDATION_TOKEN",
)}&path=${path}`,
{ method: "POST" },
);
9 changes: 9 additions & 0 deletions apps/api/typings/undici/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* eslint-disable import/export */
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/60924#issuecomment-1358837996

declare global {
export const { fetch, FormData, Headers, Request, Response }: typeof import("undici");
export type { FormData, Headers, Request, RequestInit, Response } from "undici";
}

export {};
1 change: 1 addition & 0 deletions apps/app/.env.local-example
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
NEXT_PUBLIC_API_URL=http://api.devfaq.localhost:3002
NEXT_PUBLIC_APP_URL=http://app.devfaq.localhost:3000

REVALIDATION_TOKEN=
FLAGSMITH_SERVER_SIDE_ENVIRONMENT_KEY=
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ export default async function SingleQuestionPage({ params }: { params: Params<"q
</>
);
}

export async function generateStaticParams() {
return [];
}
2 changes: 1 addition & 1 deletion apps/app/src/components/QuestionAnswers/EditAnswer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ export const EditAnswer = ({
deleteQuestionAnswerMutation.mutate(
{ id },
{
onSuccess: () => router.refresh(),
onError: () => setIsError(true),
},
);
router.refresh();
};

if (isEditMode) {
Expand Down
3 changes: 3 additions & 0 deletions apps/app/src/lib/revalidation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const validatePath = (path: string | string[] | undefined): path is string => {
return Boolean(path) && typeof path === "string";
};
21 changes: 21 additions & 0 deletions apps/app/src/pages/api/revalidation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { validatePath } from "../../lib/revalidation";

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { token, path } = req.query;

if (token !== process.env.REVALIDATION_TOKEN) {
return res.status(401).json({ message: "Invalid token" });
}

if (!validatePath(path)) {
return res.status(400).json({ message: "Incorrect path format" });
}

try {
await res.revalidate(path);
return res.status(204).end();
} catch (err) {
return res.status(500).json({ message: "Error revalidating" });
}
}