Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { performModerationAction } from "../page";
import { UserHandle } from "./user-handle";
import Link from "next/link";
import { cn } from "@/lib/utils";
import { CommentCollection } from "@/lib/data/atproto/comment";
import { getPostFromComment } from "@/lib/data/db/post";
import { getCommentLink, getPostLink } from "@/lib/navigation";
import { nsids } from "@/lib/data/atproto/repo";
Expand All @@ -25,7 +24,7 @@ const createLink = async (
case nsids.FyiUnravelFrontpagePost:
return getPostLink({ handleOrDid: author!, rkey: rkey! });

case CommentCollection: {
case nsids.FyiUnravelFrontpageComment: {
const { postAuthor, postRkey } = (await getPostFromComment({
rkey: rkey!,
did: author!,
Expand Down
7 changes: 3 additions & 4 deletions packages/frontpage/app/(app)/moderation/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
type ModerationEventDTO,
createModerationEvent,
} from "@/lib/data/db/moderation";
import { CommentCollection } from "@/lib/data/atproto/comment";
import { revalidatePath } from "next/cache";
import Link from "next/link";
import { ReportCard } from "./_components/report-card";
Expand Down Expand Up @@ -51,8 +50,8 @@ export async function performModerationAction(
if (report.subjectCollection) {
if (report.subjectCollection === nsids.FyiUnravelFrontpagePost) {
newModEvent.subjectCollection = nsids.FyiUnravelFrontpagePost;
} else if (report.subjectCollection === CommentCollection) {
newModEvent.subjectCollection = CommentCollection;
} else if (report.subjectCollection === nsids.FyiUnravelFrontpageComment) {
newModEvent.subjectCollection = nsids.FyiUnravelFrontpageComment;
}

newModEvent.subjectRkey = report.subjectRkey;
Expand All @@ -69,7 +68,7 @@ export async function performModerationAction(
hide: input.status === "accepted",
});

case CommentCollection:
case nsids.FyiUnravelFrontpageComment:
return await moderateComment({
rkey: report.subjectRkey!,
authorDid: report.subjectDid as DID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { type Metadata } from "next";
import { getVerifiedHandle } from "@/lib/data/atproto/identity";
import { type CommentPageParams, getCommentPageData } from "./_lib/page-data";
import { LinkAlternateAtUri } from "@/lib/components/link-alternate-at";
import { CommentCollection } from "@/lib/data/atproto/comment";
import { nsids } from "@/lib/data/atproto/repo";

function truncateText(text: string, maxLength: number) {
if (text.length > maxLength) {
Expand Down Expand Up @@ -61,7 +61,7 @@ export default async function CommentPage(props: {
<>
<LinkAlternateAtUri
authority={comment.authorDid}
collection={CommentCollection}
collection={nsids.FyiUnravelFrontpageComment}
rkey={comment.rkey}
/>
<div className="flex justify-end">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use server";

import { CommentCollection } from "@/lib/data/atproto/comment";
import { type DID } from "@/lib/data/atproto/did";
import { getComment } from "@/lib/data/db/comment";
import { getPost } from "@/lib/data/db/post";
Expand All @@ -12,6 +11,7 @@ import { revalidatePath } from "next/cache";
import { createComment, deleteComment } from "@/lib/api/comment";
import { createVote, deleteVote } from "@/lib/api/vote";
import { invariant } from "@/lib/utils";
import { nsids } from "@/lib/data/atproto/repo";

export async function createCommentAction(
input: { parentRkey?: string; postRkey: string; postAuthorDid: DID },
Expand Down Expand Up @@ -76,9 +76,9 @@ export async function reportCommentAction(

await createReport({
...formResult.data,
subjectUri: `at://${input.authorDid}/${CommentCollection}/${input.rkey}`,
subjectUri: `at://${input.authorDid}/${nsids.FyiUnravelFrontpageComment}/${input.rkey}`,
subjectDid: input.authorDid,
subjectCollection: CommentCollection,
subjectCollection: nsids.FyiUnravelFrontpageComment,
subjectRkey: input.rkey,
subjectCid: input.cid,
});
Expand All @@ -96,7 +96,7 @@ export async function commentVoteAction(input: {
rkey: input.rkey,
cid: input.cid,
authorDid: input.authorDid,
collection: CommentCollection,
collection: nsids.FyiUnravelFrontpageComment,
},
});
}
Expand Down
31 changes: 20 additions & 11 deletions packages/frontpage/app/api/receive_hook/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as atprotoComment from "@/lib/data/atproto/comment";
import { getPdsUrl, type DID } from "@/lib/data/atproto/did";
import { type Operation } from "@/lib/data/atproto/event";
import { getAtprotoClient, nsids } from "@/lib/data/atproto/repo";
import { AtUri } from "@/lib/data/atproto/uri";
import * as atprotoVote from "@/lib/data/atproto/vote";
import * as dbComment from "@/lib/data/db/comment";
import * as dbNotification from "@/lib/data/db/notification";
Expand All @@ -22,12 +22,17 @@ type HandlerInput = {
// Since we use read after write, we need to check if the record exists before creating it
// If it's a delete then setting the status to delete again doesn't matter

export async function handlePost({ op, repo, rkey }: HandlerInput) {
async function getAtprotoClientFromRepo(repo: DID) {
const pds = await getPdsUrl(repo);
if (!pds) {
throw new Error("Failed to get PDS");
}
const atproto = getAtprotoClient(pds);
return getAtprotoClient(pds);
}

export async function handlePost({ op, repo, rkey }: HandlerInput) {
const atproto = await getAtprotoClientFromRepo(repo);

if (op.action === "create") {
const postRecord = await atproto.fyi.unravel.frontpage.post.get({
repo,
Expand Down Expand Up @@ -91,8 +96,10 @@ export async function handlePost({ op, repo, rkey }: HandlerInput) {
}

export async function handleComment({ op, repo, rkey }: HandlerInput) {
const atproto = await getAtprotoClientFromRepo(repo);

if (op.action === "create") {
const commentRecord = await atprotoComment.getComment({
const commentRecord = await atproto.fyi.unravel.frontpage.comment.get({
rkey,
repo,
});
Expand All @@ -109,22 +116,24 @@ export async function handleComment({ op, repo, rkey }: HandlerInput) {
});
} else {
const { content, createdAt, parent, post } = commentRecord.value;
const postUri = AtUri.parse(post.uri);
const parentUri = parent ? AtUri.parse(parent.uri) : null;
Comment on lines +119 to +120
Copy link
Contributor Author

@tom-sherman tom-sherman Apr 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really like this tbh, I'd like if the generated client would parse to AtUri for us. Raised in bluesky-social/atproto#3767

const createdComment = await dbComment.createComment({
cid: commentRecord.cid,
authorDid: repo,
rkey,
content,
createdAt: new Date(createdAt),
parent: parent
parent: parentUri
? {
//TODO: is authority a DID?
authorDid: parent.uri.authority as DID,
rkey: parent.uri.rkey,
authorDid: parentUri.authority as DID,
rkey: parentUri.rkey,
}
: undefined,
post: {
authorDid: post.uri.authority as DID,
rkey: post.uri.rkey,
authorDid: postUri.authority as DID,
rkey: postUri.rkey,
},
status: "live",
});
Expand All @@ -133,7 +142,7 @@ export async function handleComment({ op, repo, rkey }: HandlerInput) {
throw new Error("Failed to insert comment from relay in database");
}

const didToNotify = parent ? parent.uri.authority : post.uri.authority;
const didToNotify = parentUri ? parentUri.authority : postUri.authority;

if (didToNotify !== repo) {
await dbNotification.createNotification({
Expand Down Expand Up @@ -190,7 +199,7 @@ export async function handleVote({ op, repo, rkey }: HandlerInput) {
}
break;
}
case atprotoComment.CommentCollection: {
case nsids.FyiUnravelFrontpageComment: {
const commentVote = await dbVote.uncached_doesCommentVoteExist(
repo,
rkey,
Expand Down
3 changes: 1 addition & 2 deletions packages/frontpage/app/api/receive_hook/route.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { db } from "@/lib/db";
import * as schema from "@/lib/schema";
import { Commit } from "@/lib/data/atproto/event";
import * as atprotoComment from "@/lib/data/atproto/comment";
import * as atprotoVote from "@/lib/data/atproto/vote";
import { getPdsUrl } from "@/lib/data/atproto/did";
import { handleComment, handlePost, handleVote } from "./handlers";
Expand Down Expand Up @@ -46,7 +45,7 @@ export async function POST(request: Request) {
case nsids.FyiUnravelFrontpagePost:
await handlePost({ op, repo, rkey });
break;
case atprotoComment.CommentCollection:
case nsids.FyiUnravelFrontpageComment:
await handleComment({ op, repo, rkey });
break;
case atprotoVote.VoteCollection:
Expand Down
41 changes: 32 additions & 9 deletions packages/frontpage/lib/api/comment.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import "server-only";
import * as atproto from "../data/atproto/comment";
import { DataLayerError } from "../data/error";
import { ensureUser } from "../data/user";
import * as db from "../data/db/comment";
Expand All @@ -8,8 +7,13 @@ import { createNotification } from "../data/db/notification";
import { invariant } from "../utils";
import { TID } from "@atproto/common-web";
import { after } from "next/server";
import { getAtprotoClient, nsids } from "../data/atproto/repo";

export type ApiCreateCommentInput = Omit<atproto.CommentInput, "rkey"> & {
export type ApiCreateCommentInput = {
// TODO: Use strongRef type for parent and post
parent?: { cid: string; rkey: string; authorDid: DID };
post: { cid: string; rkey: string; authorDid: DID };
content: string;
authorDid: DID;
};

Expand Down Expand Up @@ -38,12 +42,26 @@ export async function createComment({
invariant(dbCreatedComment, "Failed to insert comment in database");

after(() =>
atproto.createComment({
parent,
post,
content: sanitizedContent,
rkey,
}),
getAtprotoClient().fyi.unravel.frontpage.comment.create(
{
repo: user.did,
rkey,
},
{
parent: parent
? {
cid: parent.cid,
uri: `at://${parent.authorDid}/${nsids.FyiUnravelFrontpageComment}/${parent.rkey}`,
}
: undefined,
post: {
cid: post.cid,
uri: `at://${post.authorDid}/${nsids.FyiUnravelFrontpagePost}/${post.rkey}`,
},
content: sanitizedContent,
createdAt: new Date().toISOString(),
},
),
);

const didToNotify = parent ? parent.authorDid : post.authorDid;
Expand Down Expand Up @@ -73,7 +91,12 @@ export async function deleteComment({
}

try {
after(() => atproto.deleteComment(authorDid, rkey));
after(() =>
getAtprotoClient().fyi.unravel.frontpage.comment.delete({
repo: authorDid,
rkey,
}),
);
await db.deleteComment({ authorDid: user.did, rkey });
} catch (e) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
Expand Down
7 changes: 4 additions & 3 deletions packages/frontpage/lib/api/vote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import * as atproto from "../data/atproto/vote";
import { DataLayerError } from "../data/error";
import { ensureUser } from "../data/user";
import { type DID } from "../data/atproto/did";
import { CommentCollection } from "../data/atproto/comment";
import { invariant } from "../utils";
import { TID } from "@atproto/common-web";
import { after } from "next/server";
Expand All @@ -16,7 +15,9 @@ export type ApiCreateVoteInput = {
rkey: string;
cid: string;
authorDid: DID;
collection: typeof nsids.FyiUnravelFrontpagePost | typeof CommentCollection;
collection:
| typeof nsids.FyiUnravelFrontpagePost
| typeof nsids.FyiUnravelFrontpageComment;
};
};

Expand All @@ -42,7 +43,7 @@ export async function createVote({ authorDid, subject }: ApiCreateVoteInput) {
});

invariant(dbCreatedVote, "Failed to insert post vote in database");
} else if (subject.collection == CommentCollection) {
} else if (subject.collection == nsids.FyiUnravelFrontpageComment) {
const dbCreatedVote = await db.createCommentVote({
repo: authorDid,
rkey,
Expand Down
Loading