Skip to content

Commit

Permalink
refactor: notification logic to createComment() (denoland#568)
Browse files Browse the repository at this point in the history
  • Loading branch information
iuioiua authored Sep 11, 2023
1 parent 8043b5e commit 7149738
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 29 deletions.
20 changes: 3 additions & 17 deletions routes/api/comments.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 { createHttpError } from "std/http/http_errors.ts";
import { createComment, createNotification, getItem } from "@/utils/db.ts";
import { createComment } from "@/utils/db.ts";
import { redirect } from "@/utils/http.ts";
import { assertSignedIn, State } from "@/middleware/session.ts";
import { ulid } from "std/ulid/mod.ts";
Expand All @@ -21,27 +21,13 @@ export const handler: Handlers<undefined, State> = {
throw createHttpError(Status.BadRequest, "Item ID must be a string");
}

const item = await getItem(itemId);
if (item === null) throw createHttpError(Status.NotFound, "Item not found");

const { sessionUser } = ctx.state;
await createComment({
id: ulid(),
userLogin: sessionUser.login,
itemId: itemId,
userLogin: ctx.state.sessionUser.login,
itemId,
text,
});

if (item.userLogin !== sessionUser.login) {
await createNotification({
id: ulid(),
userLogin: item.userLogin,
type: "comment",
text: `${sessionUser.login} commented on your post: ${item.title}`,
originUrl: `/items/${itemId}`,
});
}

return redirect("/items/" + itemId);
},
};
36 changes: 30 additions & 6 deletions utils/db.ts
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 { decodeTime } from "std/ulid/mod.ts";
import { decodeTime, ulid } from "std/ulid/mod.ts";
import { chunk } from "std/collections/chunk.ts";

const KV_PATH_KEY = "KV_PATH";
Expand Down Expand Up @@ -229,17 +229,41 @@ export interface Comment {
}

export async function createComment(comment: Comment) {
const key = [
const itemKey = ["items", comment.itemId];
const itemRes = await kv.get<Item>(itemKey);
const item = itemRes.value;
if (item === null) throw new Deno.errors.NotFound("Item not found");

const commentKey = [
"comments_by_item",
comment.itemId,
comment.id,
];

const res = await kv.atomic()
.check({ key, versionstamp: null })
.set(key, comment)
.commit();
const atomicOp = kv.atomic()
.check({ key: commentKey, versionstamp: null })
.set(commentKey, comment);

// Create a notification if the item doesn't belong to the user who commented.
if (comment.userLogin !== item.userLogin) {
const notification: Notification = {
id: ulid(decodeTime(comment.id)),
userLogin: item.userLogin,
type: "comment",
text: `${comment.userLogin} commented on your post: ${item.title}`,
originUrl: `/items/${item.id}`,
};
const notificationKey = [
"notifications_by_user",
notification.userLogin,
notification.id,
];
atomicOp
.check({ key: notificationKey, versionstamp: null })
.set(notificationKey, notification);
}

const res = await atomicOp.commit();
if (!res.ok) throw new Error("Failed to create comment");
}

Expand Down
13 changes: 7 additions & 6 deletions utils/db_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,16 +165,17 @@ Deno.test("[db] visit", async () => {
});

Deno.test("[db] comments", async () => {
const itemId = crypto.randomUUID();
const comment1 = { ...genNewComment(), itemId };
const comment2 = { ...genNewComment(), itemId };
const item = genNewItem();
await createItem(item);
const comment1: Comment = { ...genNewComment(), itemId: item.id };
const comment2: Comment = { ...genNewComment(), itemId: item.id };

assertEquals(await collectValues(listCommentsByItem(itemId)), []);
assertEquals(await collectValues(listCommentsByItem(item.id)), []);

await createComment(comment1);
await createComment(comment2);
await assertRejects(async () => await createComment(comment2));
assertArrayIncludes(await collectValues(listCommentsByItem(itemId)), [
assertArrayIncludes(await collectValues(listCommentsByItem(item.id)), [
comment1,
comment2,
]);
Expand All @@ -185,7 +186,7 @@ Deno.test("[db] comments", async () => {
async () => await deleteComment(comment1),
"Comment not found",
);
assertEquals(await collectValues(listCommentsByItem(itemId)), []);
assertEquals(await collectValues(listCommentsByItem(item.id)), []);
});

Deno.test("[db] votes", async () => {
Expand Down

0 comments on commit 7149738

Please sign in to comment.