mirror of
https://github.com/barthuijgen/factorio-sites.git
synced 2025-03-06 16:16:30 +02:00
add handler wrappers for getServerSideProps are api routes to clean up code reuse
This commit is contained in:
parent
e3bc1c8f57
commit
fe51aa2376
@ -1,23 +1,13 @@
|
||||
import { NextApiHandler } from "next";
|
||||
import {
|
||||
init,
|
||||
createBlueprint,
|
||||
createBlueprintPage,
|
||||
createBlueprintBook,
|
||||
getSessionByToken,
|
||||
} from "@factorio-sites/database";
|
||||
import { getSessionToken, parseBlueprintString } from "@factorio-sites/node-utils";
|
||||
import { parseBlueprintString } from "@factorio-sites/node-utils";
|
||||
import { parseSequelizeError } from "../../../utils/api.utils";
|
||||
import { apiHandler } from "../../../utils/api-handler";
|
||||
|
||||
const handler: NextApiHandler = async (req, res) => {
|
||||
await init();
|
||||
|
||||
const token = getSessionToken(req);
|
||||
if (!token) {
|
||||
return res.status(401).json({ status: "Not authenticated" });
|
||||
}
|
||||
|
||||
const session = await getSessionByToken(token);
|
||||
const handler = apiHandler(async (req, res, { session }) => {
|
||||
if (!session) {
|
||||
return res.status(401).json({ status: "Not authenticated" });
|
||||
}
|
||||
@ -66,6 +56,6 @@ const handler: NextApiHandler = async (req, res) => {
|
||||
}
|
||||
|
||||
res.status(500).json({ status: "Failed to create blueprint" });
|
||||
};
|
||||
});
|
||||
|
||||
export default handler;
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { NextApiHandler } from "next";
|
||||
import { init, loginUserWithEmail } from "@factorio-sites/database";
|
||||
import { loginUserWithEmail } from "@factorio-sites/database";
|
||||
import { setUserToken } from "@factorio-sites/node-utils";
|
||||
import { apiHandler } from "../../utils/api-handler";
|
||||
|
||||
const handler: NextApiHandler = async (req, res) => {
|
||||
await init();
|
||||
const handler = apiHandler(async (req, res, { session, ip, useragent }) => {
|
||||
if (session) {
|
||||
return res.status(400).json({ status: "Already logged in" });
|
||||
}
|
||||
|
||||
const { email, password } = req.body;
|
||||
const ip = (req.headers["x-forwarded-for"] || (req as any).ip) as string;
|
||||
const useragent = req.headers["user-agent"] as string;
|
||||
|
||||
const user = await loginUserWithEmail({ email, password, useragent, ip });
|
||||
|
||||
if (user && user.session) {
|
||||
@ -16,6 +17,6 @@ const handler: NextApiHandler = async (req, res) => {
|
||||
} else {
|
||||
res.status(401).json({ status: "Invalid email and password combination" });
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
export default handler;
|
||||
|
@ -1,22 +1,14 @@
|
||||
import { NextApiHandler } from "next";
|
||||
import { init, getSessionByToken } from "@factorio-sites/database";
|
||||
import { deleteSessionToken, getSessionToken } from "@factorio-sites/node-utils";
|
||||
import { deleteSessionToken } from "@factorio-sites/node-utils";
|
||||
import { apiHandler } from "../../utils/api-handler";
|
||||
|
||||
const handler: NextApiHandler = async (req, res) => {
|
||||
await init();
|
||||
|
||||
const token = getSessionToken(req);
|
||||
|
||||
if (token) {
|
||||
const session = await getSessionByToken(token);
|
||||
if (session) {
|
||||
await session.destroy();
|
||||
}
|
||||
const handler = apiHandler(async (req, res, { session }) => {
|
||||
if (session) {
|
||||
await session.destroy();
|
||||
deleteSessionToken(res);
|
||||
}
|
||||
|
||||
res.setHeader("Location", req.query.redirect || "/");
|
||||
res.status(302).end();
|
||||
};
|
||||
});
|
||||
|
||||
export default handler;
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { NextApiHandler } from "next";
|
||||
import { init, createUserWithEmail, createSession } from "@factorio-sites/database";
|
||||
import { createUserWithEmail, createSession } from "@factorio-sites/database";
|
||||
import { setUserToken } from "@factorio-sites/node-utils";
|
||||
import { parseSequelizeError } from "../../utils/api.utils";
|
||||
import { apiHandler } from "../../utils/api-handler";
|
||||
|
||||
const handler: NextApiHandler = async (req, res) => {
|
||||
await init();
|
||||
const handler = apiHandler(async (req, res, { session, ip, useragent }) => {
|
||||
if (session) {
|
||||
return res.status(400).json({ status: "Already logged in" });
|
||||
}
|
||||
|
||||
const { email, username, password, password_confirm } = req.body;
|
||||
const ip = (req.headers["x-forwarded-for"] || (req as any).ip) as string;
|
||||
const useragent = req.headers["user-agent"] as string;
|
||||
|
||||
// Validation
|
||||
const errors: Record<string, string> = {};
|
||||
@ -37,6 +37,6 @@ const handler: NextApiHandler = async (req, res) => {
|
||||
}
|
||||
|
||||
res.status(401).json({ status: "Failed to register account" });
|
||||
};
|
||||
});
|
||||
|
||||
export default handler;
|
||||
|
@ -1,32 +1,21 @@
|
||||
import { NextApiHandler } from "next";
|
||||
import { deleteSessionToken, getSessionToken } from "@factorio-sites/node-utils";
|
||||
import { init, getSessionByToken } from "@factorio-sites/database";
|
||||
import { AuthContextProps } from "../../providers/auth";
|
||||
import { apiHandler } from "../../utils/api-handler";
|
||||
|
||||
const handler: NextApiHandler = async (req, res) => {
|
||||
await init();
|
||||
|
||||
const session_token = getSessionToken(req);
|
||||
|
||||
if (session_token) {
|
||||
const session = await getSessionByToken(session_token);
|
||||
if (session) {
|
||||
return res.status(200).json({
|
||||
auth: {
|
||||
user_id: session.user.get("id"),
|
||||
username: session.user.get("username"),
|
||||
email: session.user.get("email"),
|
||||
steam_id: session.user.get("steam_id"),
|
||||
} as AuthContextProps,
|
||||
});
|
||||
} else {
|
||||
deleteSessionToken(res);
|
||||
}
|
||||
const handler = apiHandler(async (_, res, { session }) => {
|
||||
if (session) {
|
||||
return res.status(200).json({
|
||||
auth: {
|
||||
user_id: session.user.get("id"),
|
||||
username: session.user.get("username"),
|
||||
email: session.user.get("email"),
|
||||
steam_id: session.user.get("steam_id"),
|
||||
} as AuthContextProps,
|
||||
});
|
||||
}
|
||||
|
||||
res.status(404).json({
|
||||
auth: null,
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
export default handler;
|
||||
|
@ -1,56 +1,45 @@
|
||||
import { NextApiHandler } from "next";
|
||||
import { deleteSessionToken, getSessionToken } from "@factorio-sites/node-utils";
|
||||
import { init, getSessionByToken } from "@factorio-sites/database";
|
||||
import { AuthContextProps } from "../../../providers/auth";
|
||||
import { parseSequelizeError } from "../../../utils/api.utils";
|
||||
import { apiHandler } from "../../../utils/api-handler";
|
||||
|
||||
const handler: NextApiHandler = async (req, res) => {
|
||||
const handler = apiHandler(async (req, res, { session }) => {
|
||||
if (req.method !== "POST") return res.status(400).json({ error: "method must be POST" });
|
||||
|
||||
await init();
|
||||
|
||||
const { username, email } = req.body;
|
||||
|
||||
const session_token = getSessionToken(req);
|
||||
|
||||
if (session_token) {
|
||||
const session = await getSessionByToken(session_token);
|
||||
if (session) {
|
||||
const user = session.user;
|
||||
if (username) {
|
||||
user.set("username", username);
|
||||
}
|
||||
if (email) {
|
||||
user.set("email", email);
|
||||
} else if (user.get("email") && user.get("steam_id")) {
|
||||
// User currently has email but wants to delete it, allow if steam_id exists
|
||||
user.set("email", null);
|
||||
}
|
||||
try {
|
||||
await user.save();
|
||||
} catch (reason) {
|
||||
const insert_errors = parseSequelizeError(reason);
|
||||
if (insert_errors) {
|
||||
return res.status(400).json({ errors: insert_errors });
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(200).json({
|
||||
auth: {
|
||||
user_id: session.user.get("id"),
|
||||
username: session.user.get("username"),
|
||||
email: session.user.get("email"),
|
||||
steam_id: session.user.get("steam_id"),
|
||||
} as AuthContextProps,
|
||||
});
|
||||
} else {
|
||||
deleteSessionToken(res);
|
||||
if (session) {
|
||||
const user = session.user;
|
||||
if (username) {
|
||||
user.set("username", username);
|
||||
}
|
||||
if (email) {
|
||||
user.set("email", email);
|
||||
} else if (user.get("email") && user.get("steam_id")) {
|
||||
// User currently has email but wants to delete it, allow if steam_id exists
|
||||
user.set("email", null);
|
||||
}
|
||||
try {
|
||||
await user.save();
|
||||
} catch (reason) {
|
||||
const insert_errors = parseSequelizeError(reason);
|
||||
if (insert_errors) {
|
||||
return res.status(400).json({ errors: insert_errors });
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(200).json({
|
||||
auth: {
|
||||
user_id: session.user.get("id"),
|
||||
username: session.user.get("username"),
|
||||
email: session.user.get("email"),
|
||||
steam_id: session.user.get("steam_id"),
|
||||
} as AuthContextProps,
|
||||
});
|
||||
}
|
||||
|
||||
res.status(404).json({
|
||||
auth: null,
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
export default handler;
|
||||
|
@ -1,45 +1,30 @@
|
||||
import { NextApiHandler } from "next";
|
||||
import { deleteSessionToken, getSessionToken } from "@factorio-sites/node-utils";
|
||||
import {
|
||||
init,
|
||||
getSessionByToken,
|
||||
isBlueprintPageUserFavorite,
|
||||
createUserFavorite,
|
||||
} from "@factorio-sites/database";
|
||||
import { isBlueprintPageUserFavorite, createUserFavorite } from "@factorio-sites/database";
|
||||
import { apiHandler } from "../../../utils/api-handler";
|
||||
|
||||
const handler: NextApiHandler = async (req, res) => {
|
||||
const handler = apiHandler(async (req, res, { session }) => {
|
||||
if (req.method !== "POST") return res.status(400).json({ error: "method must be POST" });
|
||||
|
||||
await init();
|
||||
|
||||
const { blueprint_page_id } = req.body;
|
||||
|
||||
const session_token = getSessionToken(req);
|
||||
if (session) {
|
||||
const user = session.user;
|
||||
|
||||
if (session_token) {
|
||||
const session = await getSessionByToken(session_token);
|
||||
if (session) {
|
||||
const user = session.user;
|
||||
const existing = await isBlueprintPageUserFavorite(user.id, blueprint_page_id);
|
||||
|
||||
const existing = await isBlueprintPageUserFavorite(user.id, blueprint_page_id);
|
||||
|
||||
if (existing) {
|
||||
await existing.destroy();
|
||||
} else {
|
||||
await createUserFavorite(user.id, blueprint_page_id);
|
||||
}
|
||||
|
||||
return res.status(200).json({
|
||||
favorite: !existing,
|
||||
});
|
||||
if (existing) {
|
||||
await existing.destroy();
|
||||
} else {
|
||||
deleteSessionToken(res);
|
||||
await createUserFavorite(user.id, blueprint_page_id);
|
||||
}
|
||||
|
||||
return res.status(200).json({
|
||||
favorite: !existing,
|
||||
});
|
||||
}
|
||||
|
||||
res.status(404).json({
|
||||
auth: null,
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
export default handler;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { NextPage, NextPageContext } from "next";
|
||||
import { NextPage } from "next";
|
||||
import BBCode from "bbcode-to-react";
|
||||
import { Button, Grid, Image, Box } from "@chakra-ui/react";
|
||||
import {
|
||||
@ -9,8 +9,6 @@ import {
|
||||
getBlueprintBookById,
|
||||
getBlueprintById,
|
||||
getBlueprintPageById,
|
||||
init,
|
||||
getSessionByToken,
|
||||
isBlueprintPageUserFavorite,
|
||||
} from "@factorio-sites/database";
|
||||
import { BlueprintStringData, timeLogger } from "@factorio-sites/common-utils";
|
||||
@ -20,7 +18,8 @@ import { Markdown } from "../../components/Markdown";
|
||||
import { BookChildTree } from "../../components/BookChildTree";
|
||||
import { CopyButton } from "../../components/CopyButton";
|
||||
import { ImageEditor } from "../../components/ImageEditor";
|
||||
import { getSessionToken } from "@factorio-sites/node-utils";
|
||||
import { useAuth } from "../../providers/auth";
|
||||
import { pageHandler } from "../../utils/page-handler";
|
||||
|
||||
type Selected =
|
||||
| { type: "blueprint"; data: Pick<Blueprint, "id" | "blueprint_hash" | "image_hash"> }
|
||||
@ -43,6 +42,7 @@ export const Index: NextPage<IndexProps> = ({
|
||||
blueprint_page,
|
||||
favorite,
|
||||
}) => {
|
||||
const auth = useAuth();
|
||||
// const [imageZoom, setImageZoom] = useState(false);
|
||||
const [blueprintString, setBlueprintString] = useState<string | null>(null);
|
||||
const [data, setData] = useState<BlueprintStringData | null>(null);
|
||||
@ -121,11 +121,13 @@ export const Index: NextPage<IndexProps> = ({
|
||||
gap={6}
|
||||
>
|
||||
<Panel title={blueprint_page.title} gridColumn="1">
|
||||
<Box>
|
||||
<Button colorScheme="green" onClick={onClickFavorite}>
|
||||
Favorite ({isFavorite ? "yes" : "no"})
|
||||
</Button>
|
||||
</Box>
|
||||
{auth && (
|
||||
<Box>
|
||||
<Button colorScheme="green" onClick={onClickFavorite}>
|
||||
Favorite ({isFavorite ? "yes" : "no"})
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
{blueprint_book ? (
|
||||
<>
|
||||
<div>This string contains a blueprint book </div>
|
||||
@ -271,14 +273,12 @@ export const Index: NextPage<IndexProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
export async function getServerSideProps(context: NextPageContext) {
|
||||
await init();
|
||||
|
||||
export const getServerSideProps = pageHandler(async (context, { session }) => {
|
||||
const throwError = (message: string) => {
|
||||
if (!blueprint_page && context.res) {
|
||||
context.res.statusCode = 404;
|
||||
context.res.end(JSON.stringify({ error: message }));
|
||||
return {};
|
||||
return { props: {} };
|
||||
}
|
||||
};
|
||||
|
||||
@ -339,14 +339,9 @@ export async function getServerSideProps(context: NextPageContext) {
|
||||
// const image_exists =
|
||||
// selected.type === "blueprint" ? await hasBlueprintImage(selected.data.image_hash) : false;
|
||||
|
||||
let favorite = false;
|
||||
const session_token = getSessionToken(context.req);
|
||||
if (session_token) {
|
||||
const session = await getSessionByToken(session_token);
|
||||
favorite = session
|
||||
? !!(await isBlueprintPageUserFavorite(session.user.id, blueprint_page.id))
|
||||
: false;
|
||||
}
|
||||
const favorite = session
|
||||
? !!(await isBlueprintPageUserFavorite(session.user.id, blueprint_page.id))
|
||||
: false;
|
||||
|
||||
return {
|
||||
props: {
|
||||
@ -358,6 +353,6 @@ export async function getServerSideProps(context: NextPageContext) {
|
||||
favorite,
|
||||
} as IndexProps,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
export default Index;
|
||||
|
29
apps/blueprints/src/utils/api-handler.ts
Normal file
29
apps/blueprints/src/utils/api-handler.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { getSessionByToken, init } from "@factorio-sites/database";
|
||||
import { deleteSessionToken, getSessionToken } from "@factorio-sites/node-utils";
|
||||
|
||||
type Await<T> = T extends PromiseLike<infer U> ? Await<U> : T;
|
||||
|
||||
interface CustomContext {
|
||||
session: Await<ReturnType<typeof getSessionByToken>>;
|
||||
ip: string;
|
||||
useragent: string;
|
||||
}
|
||||
|
||||
export const apiHandler = (
|
||||
fn: (req: NextApiRequest, res: NextApiResponse, ctx: CustomContext) => Promise<any>
|
||||
) => async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
await init();
|
||||
|
||||
const ip = (req.headers["x-forwarded-for"] || (req as any).ip) as string;
|
||||
const useragent = req.headers["user-agent"] as string;
|
||||
|
||||
const session_token = getSessionToken(req);
|
||||
const session = session_token ? await getSessionByToken(session_token) : null;
|
||||
|
||||
if (session_token && !session) {
|
||||
deleteSessionToken(res);
|
||||
}
|
||||
|
||||
return fn(req, res, { session, ip, useragent });
|
||||
};
|
27
apps/blueprints/src/utils/page-handler.ts
Normal file
27
apps/blueprints/src/utils/page-handler.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { NextPageContext } from "next";
|
||||
import { getSessionByToken, init } from "@factorio-sites/database";
|
||||
import { getSessionToken } from "@factorio-sites/node-utils";
|
||||
|
||||
interface GetServerSidePropsReturn {
|
||||
props: Record<string, any>;
|
||||
}
|
||||
|
||||
type Await<T> = T extends PromiseLike<infer U> ? Await<U> : T;
|
||||
|
||||
interface CustomContext {
|
||||
session: Await<ReturnType<typeof getSessionByToken>>;
|
||||
}
|
||||
|
||||
export const pageHandler = (
|
||||
fn: (
|
||||
context: NextPageContext,
|
||||
ctx: CustomContext
|
||||
) => Promise<GetServerSidePropsReturn | undefined>
|
||||
) => async (context: NextPageContext) => {
|
||||
await init();
|
||||
|
||||
const session_token = getSessionToken(context.req);
|
||||
const session = session_token ? await getSessionByToken(session_token) : null;
|
||||
|
||||
return fn(context, { session });
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user