Skip to content

Commit 3f4cc02

Browse files
committed
fix moderation flow
1 parent 0b8b270 commit 3f4cc02

File tree

5 files changed

+89
-9
lines changed

5 files changed

+89
-9
lines changed

backend/src/__tests__/mocks/drizzle.mock.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ interface DbInterface {
2929
name: string;
3030
description?: string;
3131
}) => void;
32+
getSubmissionByCuratorTweetId: (curatorTweetId: string) => Submission | null;
3233
getSubmission: (tweetId: string) => Submission | null;
3334
getDailySubmissionCount: (userId: string) => number;
3435
saveSubmission: (submission: Submission) => void;
@@ -63,6 +64,7 @@ interface DbInterface {
6364
// Create mock functions for each database operation
6465
export const drizzleMock = {
6566
upsertFeed: mock<DbInterface["upsertFeed"]>(() => {}),
67+
getSubmissionByCuratorTweetId: mock<DbInterface["getSubmissionByCuratorTweetId"]>(() => null),
6668
getSubmission: mock<DbInterface["getSubmission"]>(() => null),
6769
getDailySubmissionCount: mock<DbInterface["getDailySubmissionCount"]>(
6870
() => 0,

backend/src/__tests__/submission.service.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ describe("SubmissionService", () => {
232232

233233
it("should handle moderation responses for pending submissions", async () => {
234234
// Setup existing submission
235-
drizzleMock.getSubmission.mockReturnValue({
235+
drizzleMock.getSubmissionByCuratorTweetId.mockReturnValue({
236236
tweetId: TWEET_IDS.original1_tweet,
237237
userId: user1.id,
238238
username: user1.username,
@@ -301,7 +301,7 @@ describe("SubmissionService", () => {
301301

302302
it("should ignore moderation responses from non-moderators", async () => {
303303
// Setup existing submission
304-
drizzleMock.getSubmission.mockReturnValue({
304+
drizzleMock.getSubmissionByCuratorTweetId.mockReturnValue({
305305
tweetId: TWEET_IDS.original1_tweet,
306306
userId: user1.id,
307307
username: user1.username,
@@ -419,7 +419,7 @@ describe("SubmissionService", () => {
419419

420420
it("should handle rejection responses", async () => {
421421
// Setup existing submission
422-
drizzleMock.getSubmission.mockReturnValue({
422+
drizzleMock.getSubmissionByCuratorTweetId.mockReturnValue({
423423
tweetId: TWEET_IDS.original1_tweet,
424424
userId: user1.id,
425425
username: user1.username,
@@ -616,7 +616,7 @@ describe("SubmissionService", () => {
616616

617617
it("should ignore moderation of already moderated submissions", async () => {
618618
// Setup existing submission
619-
drizzleMock.getSubmission.mockReturnValue({
619+
drizzleMock.getSubmissionByCuratorTweetId.mockReturnValue({
620620
tweetId: TWEET_IDS.original1_tweet,
621621
userId: user1.id,
622622
username: user1.username,
@@ -664,7 +664,7 @@ describe("SubmissionService", () => {
664664

665665
it("should use first moderation response when multiple moderators respond", async () => {
666666
// Setup existing submission
667-
drizzleMock.getSubmission.mockReturnValue({
667+
drizzleMock.getSubmissionByCuratorTweetId.mockReturnValue({
668668
tweetId: TWEET_IDS.original1_tweet,
669669
userId: user1.id,
670670
username: user1.username,

backend/src/services/db/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ export class DatabaseService {
6363
return queries.getSubmission(this.db, tweetId);
6464
}
6565

66+
getSubmissionByCuratorTweetId(curatorTweetId: string): TwitterSubmission | null {
67+
return queries.getSubmissionByCuratorTweetId(this.db, curatorTweetId);
68+
}
69+
6670
getAllSubmissions(): TwitterSubmission[] {
6771
return queries.getAllSubmissions(this.db);
6872
}

backend/src/services/db/queries.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,80 @@ export function updateSubmissionFeedStatus(
170170
);
171171
}
172172

173+
export function getSubmissionByCuratorTweetId(
174+
db: BunSQLiteDatabase,
175+
curatorTweetId: string,
176+
): TwitterSubmission | null {
177+
const results = db
178+
.select({
179+
s: {
180+
tweetId: submissions.tweetId,
181+
userId: submissions.userId,
182+
username: submissions.username,
183+
content: submissions.content,
184+
curatorNotes: submissions.curatorNotes,
185+
curatorId: submissions.curatorId,
186+
curatorUsername: submissions.curatorUsername,
187+
curatorTweetId: submissions.curatorTweetId,
188+
createdAt: submissions.createdAt,
189+
submittedAt: sql<string>`COALESCE(${submissions.submittedAt}, ${submissions.createdAt})`,
190+
},
191+
m: {
192+
tweetId: moderationHistory.tweetId,
193+
adminId: moderationHistory.adminId,
194+
action: moderationHistory.action,
195+
note: moderationHistory.note,
196+
createdAt: moderationHistory.createdAt,
197+
feedId: moderationHistory.feedId,
198+
moderationResponseTweetId: submissionFeeds.moderationResponseTweetId,
199+
},
200+
})
201+
.from(submissions)
202+
.leftJoin(
203+
moderationHistory,
204+
eq(submissions.tweetId, moderationHistory.tweetId),
205+
)
206+
.leftJoin(
207+
submissionFeeds,
208+
and(
209+
eq(submissions.tweetId, submissionFeeds.submissionId),
210+
eq(moderationHistory.feedId, submissionFeeds.feedId),
211+
),
212+
)
213+
.where(eq(submissions.curatorTweetId, curatorTweetId))
214+
.orderBy(moderationHistory.createdAt)
215+
.all() as DbQueryResult[];
216+
217+
if (!results.length) return null;
218+
219+
// Group moderation history
220+
const modHistory: Moderation[] = results
221+
.filter((r: DbQueryResult) => r.m && r.m.adminId !== null)
222+
.map((r: DbQueryResult) => ({
223+
tweetId: results[0].s.tweetId,
224+
feedId: r.m.feedId!,
225+
adminId: r.m.adminId!,
226+
action: r.m.action as "approve" | "reject",
227+
note: r.m.note,
228+
timestamp: new Date(r.m.createdAt!),
229+
moderationResponseTweetId: r.m.moderationResponseTweetId ?? undefined,
230+
}));
231+
232+
return {
233+
tweetId: results[0].s.tweetId,
234+
userId: results[0].s.userId,
235+
username: results[0].s.username,
236+
content: results[0].s.content,
237+
curatorNotes: results[0].s.curatorNotes,
238+
curatorId: results[0].s.curatorId,
239+
curatorUsername: results[0].s.curatorUsername,
240+
curatorTweetId: results[0].s.curatorTweetId,
241+
createdAt: results[0].s.createdAt,
242+
submittedAt: results[0].s.submittedAt,
243+
moderationHistory: modHistory,
244+
};
245+
}
246+
173247
export function getSubmission(
174248
db: BunSQLiteDatabase,
175249
tweetId: string,

backend/src/services/submissions/submission.service.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -371,11 +371,11 @@ export class SubmissionService {
371371
return;
372372
}
373373

374-
// submission is what we're replying to
375-
const inReplyToId = tweet.inReplyToStatusId;
376-
if (!inReplyToId) return;
374+
// Get the curator's tweet that the moderator is replying to
375+
const curatorTweetId = tweet.inReplyToStatusId;
376+
if (!curatorTweetId) return;
377377

378-
const submission = db.getSubmission(inReplyToId);
378+
const submission = db.getSubmissionByCuratorTweetId(curatorTweetId);
379379
if (!submission) {
380380
logger.error(`${tweet.id}: Received moderation for unsaved submission`);
381381
return;

0 commit comments

Comments
 (0)