From c97c3f7b6978cc4d7128b6e0efe4c3d045b3fee3 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Sat, 8 Oct 2022 02:53:13 -0500 Subject: [PATCH] Basics coming together... --- components/Note.tsx | 21 +++++++++++++++++++++ db/mod.ts | 20 +++++++++++--------- routes/_middleware.ts | 20 ++++++++------------ routes/dashboard.tsx | 16 +++++++++------- routes/note.tsx | 13 ++----------- routes/note/create.tsx | 7 ++++--- types.ts | 15 +++++++++++---- 7 files changed, 66 insertions(+), 46 deletions(-) create mode 100644 components/Note.tsx diff --git a/components/Note.tsx b/components/Note.tsx new file mode 100644 index 0000000..092a2a8 --- /dev/null +++ b/components/Note.tsx @@ -0,0 +1,21 @@ +import { type Note } from "@/types.ts"; + +export function NoteItem( + { id, createdAt, content, userId, userDisplayName, userUsername }: Note, +) { + return ( +
+ + Note {id} + {" created by "} + {!userId + ? "Anonymous" + : {userDisplayName || userUsername}} + {` at ${createdAt.toLocaleString()}`} + +
+
{content}
+
+
+ ); +} diff --git a/db/mod.ts b/db/mod.ts index c4f4333..f260166 100644 --- a/db/mod.ts +++ b/db/mod.ts @@ -53,13 +53,15 @@ export async function queryObject( sql: string, args?: QueryArguments, ): Promise | null> { - return await dbOp(async (connection) => - await connection.queryObject({ + return await dbOp(async (connection) => { + const result = await connection.queryObject({ camelcase: true, text: sql.trim(), args, - }) - ); + }); + console.debug(result); + return result; + }); } export async function queryArray( @@ -76,8 +78,8 @@ export async function queryArray( export async function listNotes(): Promise { return someRows( - await queryObject( - "select * from note order by created_at desc", + await queryObject( + 'select u.username as user_username, u.display_name as user_display_name, n.* from note n left join "user" u on u.id = n.user_id order by n.created_at desc', ), ); } @@ -98,12 +100,12 @@ export async function getNote( type Ungenerated = Omit; export async function createNote( - { content }: Ungenerated, + { content, userId }: Ungenerated, ): Promise { return singleRow( await queryObject( - "insert into note (content) values ($1) returning *", - [content], + "insert into note (content, user_id) values ($1, $2) returning *", + [content, userId], ), ); } diff --git a/routes/_middleware.ts b/routes/_middleware.ts index 0553de9..e87521b 100644 --- a/routes/_middleware.ts +++ b/routes/_middleware.ts @@ -1,28 +1,24 @@ import { MiddlewareHandlerContext } from "$fresh/server.ts"; import { deleteCookie, getCookies } from "$std/http/cookie.ts"; import { getUserFromNonExpiredLoginToken } from "@/db/mod.ts"; - -interface State { - data: string; -} +import { type ContextState } from "@/types.ts"; export async function handler( request: Request, - ctx: MiddlewareHandlerContext, + ctx: MiddlewareHandlerContext, ) { - ctx.state.data = ""; let hasBadAuthCookie = false; const { lsauth } = getCookies(request.headers); console.log("lsauth cookie:", lsauth); if (lsauth) { const user = await getUserFromNonExpiredLoginToken(lsauth); if (!user) hasBadAuthCookie = true; - else {ctx.state.data += "user:" + JSON.stringify({ - id: user.id, - username: user.username, - displayName: user.displayName || user.username, - }) + - "\n";} + else { + ctx.state.user = user; + delete ctx.state.user.createdAt; + delete ctx.state.user.updatedAt; + delete ctx.state.user.passwordDigest; + } } const resp = await ctx.next(); diff --git a/routes/dashboard.tsx b/routes/dashboard.tsx index ad64411..301d01e 100644 --- a/routes/dashboard.tsx +++ b/routes/dashboard.tsx @@ -1,17 +1,19 @@ -import { HandlerContext, Handlers, PageProps } from "$fresh/server.ts"; +import { Handlers, PageProps } from "$fresh/server.ts"; import { Page } from "@/components/Page.tsx"; // import { getToken, getUser } from "@/db/mod.ts"; // import * as base64 from "$std/encoding/base64.ts"; -import { getCookies } from "$std/http/cookie.ts"; -import { type User } from "@/types.ts"; +import { type ContextState } from "@/types.ts"; -export const handler: Handlers = { - async GET(request: Request, context) { - return await context.render(context.state.data); +export const handler: Handlers = { + async GET(_request: Request, context) { + const user: Partial = context.state.user; + delete user.passwordDigest; + return await context.render(context.state.user); }, }; export default function Dashboard({ data }: PageProps) { + console.log(data); if (data) { return You(data); } else { @@ -23,7 +25,7 @@ function You(data: unknown) { return (

- You are

{data}
. + You are
{JSON.stringify(data)}
.

); diff --git a/routes/note.tsx b/routes/note.tsx index 8307c78..ae3da0e 100644 --- a/routes/note.tsx +++ b/routes/note.tsx @@ -2,6 +2,7 @@ import { Handlers, PageProps } from "$fresh/server.ts"; import { listNotes } from "@/db/mod.ts"; import { Page } from "@/components/Page.tsx"; import { type Note } from "@/types.ts"; +import { NoteItem } from "@/components/Note.tsx"; export const handler: Handlers = { async GET(_request, context) { @@ -19,17 +20,7 @@ export default function NotesPage({ data: notes }: PageProps) { - {notes.map(({ id, content, createdAt }) => ( -
- - Note {id}{" "} - created at {createdAt.toLocaleString()} - -
-
{content}
-
-
- ))} + {notes.map(NoteItem)} ); } diff --git a/routes/note/create.tsx b/routes/note/create.tsx index 66fc1da..197619f 100644 --- a/routes/note/create.tsx +++ b/routes/note/create.tsx @@ -1,13 +1,14 @@ import { Handlers, PageProps } from "$fresh/server.ts"; import { createNote } from "@/db/mod.ts"; import { Page } from "@/components/Page.tsx"; -import { type Note } from "@/types.ts"; +import { type ContextState, type Note } from "@/types.ts"; -export const handler: Handlers = { +export const handler: Handlers = { async POST(request, context) { + const userId = context.state.user ? context.state.user.id : null; const content = (await request.formData()).get("content"); if (!content) throw "no content provided"; - const note = await createNote({ content: content.toString() }); + const note = await createNote({ userId, content: content.toString() }); if (!note) throw "no note created"; return await context.render(note); }, diff --git a/types.ts b/types.ts index ce19b8f..8ca144f 100644 --- a/types.ts +++ b/types.ts @@ -12,10 +12,6 @@ export interface Updated { export type Timestamped = Created & Updated; -export interface Note extends Identifiable, Timestamped { - content: string; -} - export interface Team extends Identifiable, Timestamped { displayName: string; } @@ -26,6 +22,13 @@ export interface User extends Identifiable, Timestamped { displayName?: string; } +export interface Note extends Identifiable, Timestamped { + content: string; + userId: User["id"] | null; + userUsername?: User["username"]; + userDisplayName?: User["displayName"]; +} + type IdentifierFor = T["id"]; export interface Token extends Created { @@ -37,3 +40,7 @@ export interface Token extends Created { /** 32 bytes base64-encoded */ export type TokenDigest = string; + +export interface ContextState { + user?: Omit & Partial; +}