Skip to content

Commit

Permalink
refactor: move session middleware into new session plugin (denoland#599)
Browse files Browse the repository at this point in the history
This brings all session-related logic under one roof.
  • Loading branch information
iuioiua authored Sep 21, 2023
1 parent 006ee58 commit 2f841d0
Show file tree
Hide file tree
Showing 17 changed files with 144 additions and 150 deletions.
4 changes: 2 additions & 2 deletions fresh.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
import twindPlugin from "$fresh/plugins/twindv1.ts";
import twindConfig from "./twind.config.ts";
import kvOAuthPlugin from "./plugins/kv_oauth.ts";
import protectedRoutes from "./plugins/protected_routes.ts";
import sessionPlugin from "./plugins/session.ts";
import errorHandling from "./plugins/error_handling.ts";
import { FreshOptions } from "$fresh/server.ts";

export default {
plugins: [
kvOAuthPlugin,
protectedRoutes,
sessionPlugin,
twindPlugin(twindConfig),
errorHandling,
],
Expand Down
86 changes: 42 additions & 44 deletions fresh.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,27 @@
import * as $0 from "./routes/_404.tsx";
import * as $1 from "./routes/_500.tsx";
import * as $2 from "./routes/_app.tsx";
import * as $3 from "./routes/_middleware.ts";
import * as $4 from "./routes/account/index.tsx";
import * as $5 from "./routes/account/manage.ts";
import * as $6 from "./routes/account/upgrade.ts";
import * as $7 from "./routes/api/items/[id]/index.ts";
import * as $8 from "./routes/api/items/[id]/vote.ts";
import * as $9 from "./routes/api/items/index.ts";
import * as $10 from "./routes/api/me/votes.ts";
import * as $11 from "./routes/api/stripe-webhooks.ts";
import * as $12 from "./routes/api/users/[login]/index.ts";
import * as $13 from "./routes/api/users/[login]/items.ts";
import * as $14 from "./routes/api/users/index.ts";
import * as $15 from "./routes/blog/[slug].tsx";
import * as $16 from "./routes/blog/index.tsx";
import * as $17 from "./routes/dashboard/index.tsx";
import * as $18 from "./routes/dashboard/stats.tsx";
import * as $19 from "./routes/dashboard/users.tsx";
import * as $20 from "./routes/feed.ts";
import * as $21 from "./routes/index.tsx";
import * as $22 from "./routes/pricing.tsx";
import * as $23 from "./routes/submit.tsx";
import * as $24 from "./routes/users/[login].tsx";
import * as $3 from "./routes/account/index.tsx";
import * as $4 from "./routes/account/manage.ts";
import * as $5 from "./routes/account/upgrade.ts";
import * as $6 from "./routes/api/items/[id]/index.ts";
import * as $7 from "./routes/api/items/[id]/vote.ts";
import * as $8 from "./routes/api/items/index.ts";
import * as $9 from "./routes/api/me/votes.ts";
import * as $10 from "./routes/api/stripe-webhooks.ts";
import * as $11 from "./routes/api/users/[login]/index.ts";
import * as $12 from "./routes/api/users/[login]/items.ts";
import * as $13 from "./routes/api/users/index.ts";
import * as $14 from "./routes/blog/[slug].tsx";
import * as $15 from "./routes/blog/index.tsx";
import * as $16 from "./routes/dashboard/index.tsx";
import * as $17 from "./routes/dashboard/stats.tsx";
import * as $18 from "./routes/dashboard/users.tsx";
import * as $19 from "./routes/feed.ts";
import * as $20 from "./routes/index.tsx";
import * as $21 from "./routes/pricing.tsx";
import * as $22 from "./routes/submit.tsx";
import * as $23 from "./routes/users/[login].tsx";
import * as $$0 from "./islands/Chart.tsx";
import * as $$1 from "./islands/ItemsList.tsx";
import * as $$2 from "./islands/UsersTable.tsx";
Expand All @@ -36,28 +35,27 @@ const manifest = {
"./routes/_404.tsx": $0,
"./routes/_500.tsx": $1,
"./routes/_app.tsx": $2,
"./routes/_middleware.ts": $3,
"./routes/account/index.tsx": $4,
"./routes/account/manage.ts": $5,
"./routes/account/upgrade.ts": $6,
"./routes/api/items/[id]/index.ts": $7,
"./routes/api/items/[id]/vote.ts": $8,
"./routes/api/items/index.ts": $9,
"./routes/api/me/votes.ts": $10,
"./routes/api/stripe-webhooks.ts": $11,
"./routes/api/users/[login]/index.ts": $12,
"./routes/api/users/[login]/items.ts": $13,
"./routes/api/users/index.ts": $14,
"./routes/blog/[slug].tsx": $15,
"./routes/blog/index.tsx": $16,
"./routes/dashboard/index.tsx": $17,
"./routes/dashboard/stats.tsx": $18,
"./routes/dashboard/users.tsx": $19,
"./routes/feed.ts": $20,
"./routes/index.tsx": $21,
"./routes/pricing.tsx": $22,
"./routes/submit.tsx": $23,
"./routes/users/[login].tsx": $24,
"./routes/account/index.tsx": $3,
"./routes/account/manage.ts": $4,
"./routes/account/upgrade.ts": $5,
"./routes/api/items/[id]/index.ts": $6,
"./routes/api/items/[id]/vote.ts": $7,
"./routes/api/items/index.ts": $8,
"./routes/api/me/votes.ts": $9,
"./routes/api/stripe-webhooks.ts": $10,
"./routes/api/users/[login]/index.ts": $11,
"./routes/api/users/[login]/items.ts": $12,
"./routes/api/users/index.ts": $13,
"./routes/blog/[slug].tsx": $14,
"./routes/blog/index.tsx": $15,
"./routes/dashboard/index.tsx": $16,
"./routes/dashboard/stats.tsx": $17,
"./routes/dashboard/users.tsx": $18,
"./routes/feed.ts": $19,
"./routes/index.tsx": $20,
"./routes/pricing.tsx": $21,
"./routes/submit.tsx": $22,
"./routes/users/[login].tsx": $23,
},
islands: {
"./islands/Chart.tsx": $$0,
Expand Down
47 changes: 0 additions & 47 deletions middleware/session.ts

This file was deleted.

2 changes: 1 addition & 1 deletion plugins/error_handling.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import type { Plugin } from "$fresh/server.ts";
import type { State } from "@/middleware/session.ts";
import type { State } from "@/plugins/session.ts";
import { Status } from "$fresh/server.ts";
import { errors, isHttpError } from "std/http/http_errors.ts";
import { redirect } from "@/utils/http.ts";
Expand Down
40 changes: 0 additions & 40 deletions plugins/protected_routes.ts

This file was deleted.

89 changes: 89 additions & 0 deletions plugins/session.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import { Plugin } from "$fresh/server.ts";
import type { MiddlewareHandlerContext } from "$fresh/server.ts";
import { getSessionId } from "kv_oauth";
import { getUserBySession } from "@/utils/db.ts";
import type { User } from "@/utils/db.ts";
import { createHttpError } from "std/http/http_errors.ts";
import { Status } from "std/http/http_status.ts";

export interface State {
sessionUser?: User;
}

export type SignedInState = Required<State>;

export function assertSignedIn(
ctx: { state: State },
): asserts ctx is { state: SignedInState } {
if (ctx.state.sessionUser === undefined) {
throw createHttpError(Status.Unauthorized, "User must be signed in");
}
}

async function setSessionState(
req: Request,
ctx: MiddlewareHandlerContext<State>,
) {
if (ctx.destination !== "route") return await ctx.next();

// Initial state
ctx.state.sessionUser = undefined;

const sessionId = getSessionId(req);
if (sessionId === undefined) return await ctx.next();
const user = await getUserBySession(sessionId);
if (user === null) return await ctx.next();

ctx.state.sessionUser = user;

return await ctx.next();
}

async function ensureSignedIn(
_req: Request,
ctx: MiddlewareHandlerContext<State>,
) {
assertSignedIn(ctx);
return await ctx.next();
}

/**
* Adds middleware to the defined routes that ensures the client is signed-in
* before proceeding. The {@linkcode ensureSignedIn} middleware throws an error
* equivalent to the
* {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401|HTTP 401 Unauthorized}
* error if `ctx.state.sessionUser` is `undefined`.
*
* The thrown error is then handled by {@linkcode handleWebPageErrors}, or
* {@linkcode handleRestApiErrors}, if the request is made to a REST API
* endpoint.
*
* @see {@link https://fresh.deno.dev/docs/concepts/plugins|Plugins documentation}
* for more information on Fresh's plugin functionality.
*/
export default {
name: "session",
middlewares: [
{
path: "/",
middleware: { handler: setSessionState },
},
{
path: "/account",
middleware: { handler: ensureSignedIn },
},
{
path: "/dashboard",
middleware: { handler: ensureSignedIn },
},
{
path: "/submit",
middleware: { handler: ensureSignedIn },
},
{
path: "/api/me",
middleware: { handler: ensureSignedIn },
},
],
} as Plugin<State>;
2 changes: 1 addition & 1 deletion routes/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import Header from "@/components/Header.tsx";
import Footer from "@/components/Footer.tsx";
import type { State } from "@/middleware/session.ts";
import type { State } from "@/plugins/session.ts";
import { defineApp } from "$fresh/server.ts";

export default defineApp<State>((_, ctx) => {
Expand Down
6 changes: 0 additions & 6 deletions routes/_middleware.ts

This file was deleted.

2 changes: 1 addition & 1 deletion routes/account/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import { defineRoute } from "$fresh/server.ts";
import type { SignedInState } from "@/middleware/session.ts";
import type { SignedInState } from "@/plugins/session.ts";
import { BUTTON_STYLES } from "@/utils/constants.ts";
import { isStripeEnabled } from "@/utils/stripe.ts";
import Head from "@/components/Head.tsx";
Expand Down
2 changes: 1 addition & 1 deletion routes/account/manage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import { defineRoute } from "$fresh/server.ts";
import type { SignedInState } from "@/middleware/session.ts";
import type { SignedInState } from "@/plugins/session.ts";
import { redirect } from "@/utils/http.ts";
import { isStripeEnabled, stripe } from "@/utils/stripe.ts";

Expand Down
2 changes: 1 addition & 1 deletion routes/account/upgrade.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import { defineRoute } from "$fresh/server.ts";
import type { SignedInState } from "@/middleware/session.ts";
import type { SignedInState } from "@/plugins/session.ts";
import { redirect } from "@/utils/http.ts";
import {
getStripePremiumPlanPriceId,
Expand Down
2 changes: 1 addition & 1 deletion routes/api/items/[id]/vote.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import { type Handlers, Status } from "$fresh/server.ts";
import { assertSignedIn, type State } from "@/middleware/session.ts";
import { assertSignedIn, type State } from "@/plugins/session.ts";
import { createVote, deleteVote, getItem } from "@/utils/db.ts";
import { createHttpError } from "std/http/http_errors.ts";

Expand Down
2 changes: 1 addition & 1 deletion routes/api/items/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getCursor } from "@/utils/http.ts";
import { type Handlers } from "$fresh/server.ts";
import { createItem, type Item } from "@/utils/db.ts";
import { redirect } from "@/utils/http.ts";
import { assertSignedIn, State } from "@/middleware/session.ts";
import { assertSignedIn, State } from "@/plugins/session.ts";
import { createHttpError } from "std/http/http_errors.ts";
import { ulid } from "std/ulid/mod.ts";
import { Status } from "std/http/http_status.ts";
Expand Down
2 changes: 1 addition & 1 deletion routes/api/me/votes.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import type { Handlers } from "$fresh/server.ts";
import { collectValues, listItemsVotedByUser } from "@/utils/db.ts";
import { SignedInState } from "@/middleware/session.ts";
import { SignedInState } from "@/plugins/session.ts";

export const handler: Handlers<undefined, SignedInState> = {
async GET(_req, ctx) {
Expand Down
2 changes: 1 addition & 1 deletion routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import type { State } from "@/middleware/session.ts";
import type { State } from "@/plugins/session.ts";
import Head from "@/components/Head.tsx";
import ItemsList from "@/islands/ItemsList.tsx";
import { defineRoute } from "$fresh/server.ts";
Expand Down
2 changes: 1 addition & 1 deletion routes/pricing.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import type { State } from "@/middleware/session.ts";
import type { State } from "@/plugins/session.ts";
import { BUTTON_STYLES } from "@/utils/constants.ts";
import { assertIsPrice, isStripeEnabled, stripe } from "@/utils/stripe.ts";
import { formatCurrency } from "@/utils/display.ts";
Expand Down
2 changes: 1 addition & 1 deletion routes/users/[login].tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import type { State } from "@/middleware/session.ts";
import type { State } from "@/plugins/session.ts";
import { getUser } from "@/utils/db.ts";
import IconBrandGithub from "tabler_icons_tsx/brand-github.tsx";
import { LINK_STYLES } from "@/utils/constants.ts";
Expand Down

0 comments on commit 2f841d0

Please sign in to comment.