feat: add force log out endpoint
This commit is contained in:
parent
c18b79e570
commit
42041d49bc
7 changed files with 72 additions and 15 deletions
|
@ -2,4 +2,5 @@ import "dotenv/config";
|
|||
import { env } from "node:process";
|
||||
|
||||
export const API_BASE = env.API_BASE || "https://pronouns.localhost/api";
|
||||
export const INTERNAL_API_BASE = env.INTERNAL_API_BASE || "https://localhost:5000/api";
|
||||
export const LANGUAGE = env.LANGUAGE || "en";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { parse as parseCookie, serialize as serializeCookie } from "cookie";
|
||||
import { API_BASE } from "~/env.server";
|
||||
import { API_BASE, INTERNAL_API_BASE } from "~/env.server";
|
||||
import { ApiError, ErrorCode } from "./api/error";
|
||||
import { tokenCookieName } from "~/lib/utils";
|
||||
|
||||
|
@ -8,14 +8,17 @@ export type RequestParams = {
|
|||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
body?: any;
|
||||
headers?: Record<string, string>;
|
||||
isInternal?: boolean;
|
||||
};
|
||||
|
||||
export default async function serverRequest<T>(
|
||||
async function requestInternal(
|
||||
method: string,
|
||||
path: string,
|
||||
params: RequestParams = {},
|
||||
) {
|
||||
const url = `${API_BASE}/v2${path}`;
|
||||
): Promise<Response> {
|
||||
const base = params.isInternal ? INTERNAL_API_BASE : API_BASE + "/v2";
|
||||
|
||||
const url = `${base}${path}`;
|
||||
const resp = await fetch(url, {
|
||||
method,
|
||||
body: params.body ? JSON.stringify(params.body) : undefined,
|
||||
|
@ -37,6 +40,19 @@ export default async function serverRequest<T>(
|
|||
}
|
||||
|
||||
if (resp.status < 200 || resp.status >= 400) throw (await resp.json()) as ApiError;
|
||||
return resp;
|
||||
}
|
||||
|
||||
export async function fastRequest(method: string, path: string, params: RequestParams = {}) {
|
||||
await requestInternal(method, path, params);
|
||||
}
|
||||
|
||||
export default async function serverRequest<T>(
|
||||
method: string,
|
||||
path: string,
|
||||
params: RequestParams = {},
|
||||
) {
|
||||
const resp = await requestInternal(method, path, params);
|
||||
return (await resp.json()) as T;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Button, Form, InputGroup, Table } from "react-bootstrap";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form as RemixForm, useActionData, useRouteLoaderData } from "@remix-run/react";
|
||||
import { Form as RemixForm, useActionData, useFetcher, useRouteLoaderData } from "@remix-run/react";
|
||||
import { loader as settingsLoader } from "../settings/route";
|
||||
import { loader as rootLoader } from "../../root";
|
||||
import { DateTime } from "luxon";
|
||||
|
@ -43,6 +43,7 @@ export default function SettingsIndex() {
|
|||
const actionData = useActionData<typeof action>();
|
||||
const { meta } = useRouteLoaderData<typeof rootLoader>("root")!;
|
||||
const { t } = useTranslation();
|
||||
const fetcher = useFetcher();
|
||||
|
||||
const createdAt = idTimestamp(user.id);
|
||||
|
||||
|
@ -55,13 +56,7 @@ export default function SettingsIndex() {
|
|||
<Form.Group className="mb-3" controlId="username">
|
||||
<Form.Label>{t("settings.general.username")}</Form.Label>
|
||||
<InputGroup className="m-1 w-75">
|
||||
<Form.Control
|
||||
defaultValue={user.username}
|
||||
id="username"
|
||||
name="username"
|
||||
type="text"
|
||||
required
|
||||
/>
|
||||
<Form.Control defaultValue={user.username} name="username" type="text" required />
|
||||
<Button variant="secondary" type="submit">
|
||||
{t("settings.general.change-username")}
|
||||
</Button>
|
||||
|
@ -85,9 +80,14 @@ export default function SettingsIndex() {
|
|||
</div>
|
||||
<div>
|
||||
<h4>{t("settings.general.log-out-everywhere")}</h4>
|
||||
<p></p>
|
||||
<p>{t("settings.general.log-out-everywhere-hint")}</p>
|
||||
<fetcher.Form method="POST" action="/settings/force-log-out">
|
||||
<Button type="submit" variant="danger">
|
||||
{t("settings.general.force-log-out-button")}
|
||||
</Button>
|
||||
</fetcher.Form>
|
||||
</div>
|
||||
<h4>{t("settings.general.table-header")}</h4>
|
||||
<h4 className="mt-2">{t("settings.general.table-header")}</h4>
|
||||
<Table striped bordered hover>
|
||||
<tbody>
|
||||
<tr>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import { ActionFunction, redirect } from "@remix-run/node";
|
||||
import { fastRequest, getToken, writeCookie } from "~/lib/request.server";
|
||||
import { tokenCookieName } from "~/lib/utils";
|
||||
|
||||
export const action: ActionFunction = async ({ request }) => {
|
||||
const token = getToken(request);
|
||||
if (!token)
|
||||
return redirect("/", {
|
||||
status: 303,
|
||||
headers: { "Set-Cookie": writeCookie(tokenCookieName, "token", 0) },
|
||||
});
|
||||
|
||||
await fastRequest("POST", "/internal/force-log-out", { token, isInternal: true });
|
||||
|
||||
return redirect("/", {
|
||||
status: 303,
|
||||
headers: { "Set-Cookie": writeCookie(tokenCookieName, "token", 0) },
|
||||
});
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue