From efda68bc6441fbc81848ef43f501e6fcb8115ba8 Mon Sep 17 00:00:00 2001 From: Namekuji Date: Tue, 5 Sep 2023 10:58:20 -0400 Subject: [PATCH] further cleanup --- packages/backend/assets/robots.txt | 16 ++++- packages/backend/src/server/activitypub.ts | 67 +++++++++++++++---- .../src/server/activitypub/featured.ts | 16 ++++- .../backend/src/server/activitypub/outbox.ts | 21 +++++- .../users/get-frequently-replied-users.ts | 5 ++ packages/backend/src/server/web/feed.ts | 40 ++++++++--- packages/backend/src/services/i/pin.ts | 27 ++++++-- .../backend/src/services/note/polls/update.ts | 26 +++++-- 8 files changed, 178 insertions(+), 40 deletions(-) diff --git a/packages/backend/assets/robots.txt b/packages/backend/assets/robots.txt index dc17e04e3f..cedb5b6cf2 100644 --- a/packages/backend/assets/robots.txt +++ b/packages/backend/assets/robots.txt @@ -1,4 +1,14 @@ -user-agent: * -allow: / +User-agent: * +Allow: / -# todo: sitemap +# Uncomment the following to block CommonCrawl +# +# User-agent: CCBot +# User-agent: CCBot/2.0 +# User-agent: CCBot/3.1 +# Disallow: / + +# Uncomment the following to block ChatGPT +# +# User-agent: GPTBot +# Disallow: / diff --git a/packages/backend/src/server/activitypub.ts b/packages/backend/src/server/activitypub.ts index f9d5eb99c3..e500c585a0 100644 --- a/packages/backend/src/server/activitypub.ts +++ b/packages/backend/src/server/activitypub.ts @@ -33,6 +33,8 @@ import Following from "./activitypub/following.js"; import Followers from "./activitypub/followers.js"; import Outbox, { packActivity } from "./activitypub/outbox.js"; import { serverLogger } from "./index.js"; +import { parseScyllaNote, prepared, scyllaClient } from "@/db/scylla.js"; +import type { Note } from "@/models/entities/note.js"; // Init router const router = new Router(); @@ -87,13 +89,32 @@ router.get("/notes/:note", async (ctx, next) => { return; } - const note = await Notes.findOneBy({ - id: ctx.params.note, - visibility: In(["public" as const, "home" as const, "followers" as const]), - localOnly: false, - }); + let note: Note | null = null; + const validVisibilities = ["public", "home", "followers"]; + if (scyllaClient) { + const result = await scyllaClient.execute( + prepared.note.select.byId, + [ctx.params.note], + { prepare: true }, + ); + if (result.rowLength > 0) { + const candidate = parseScyllaNote(result.first()); + if ( + !candidate.localOnly && + validVisibilities.includes(candidate.visibility) + ) { + note = candidate; + } + } + } else { + note = await Notes.findOneBy({ + id: ctx.params.note, + visibility: In(validVisibilities), + localOnly: false, + }); + } - if (note == null) { + if (!note) { ctx.status = 404; return; } @@ -158,14 +179,34 @@ router.get("/notes/:note/activity", async (ctx) => { return; } - const note = await Notes.findOneBy({ - id: ctx.params.note, - userHost: IsNull(), - visibility: In(["public" as const, "home" as const]), - localOnly: false, - }); + let note: Note | null = null; + const validVisibilities = ["public", "home"]; + if (scyllaClient) { + const result = await scyllaClient.execute( + prepared.note.select.byId, + [ctx.params.note], + { prepare: true }, + ); + if (result.rowLength > 0) { + const candidate = parseScyllaNote(result.first()); + if ( + !candidate.userHost && + !candidate.localOnly && + validVisibilities.includes(candidate.visibility) + ) { + note = candidate; + } + } + } else { + note = await Notes.findOneBy({ + id: ctx.params.note, + userHost: IsNull(), + visibility: In(validVisibilities), + localOnly: false, + }); + } - if (note == null) { + if (!note) { ctx.status = 404; return; } diff --git a/packages/backend/src/server/activitypub/featured.ts b/packages/backend/src/server/activitypub/featured.ts index 82bb19fa12..e3c79f1069 100644 --- a/packages/backend/src/server/activitypub/featured.ts +++ b/packages/backend/src/server/activitypub/featured.ts @@ -8,6 +8,8 @@ import { checkFetch } from "@/remote/activitypub/check-fetch.js"; import { fetchMeta } from "@/misc/fetch-meta.js"; import { setResponseType } from "../activitypub.js"; import type Router from "@koa/router"; +import { parseScyllaNote, prepared, scyllaClient } from "@/db/scylla.js"; +import { Note } from "@/models/entities/note.js"; export default async (ctx: Router.RouterContext) => { const verify = await checkFetch(ctx.req); @@ -33,9 +35,17 @@ export default async (ctx: Router.RouterContext) => { order: { id: "DESC" }, }); - const pinnedNotes = await Promise.all( - pinings.map((pining) => Notes.findOneByOrFail({ id: pining.noteId })), - ); + let pinnedNotes: Note[] = []; + if (scyllaClient) { + const noteIds = pinings.map(({ noteId }) => noteId); + pinnedNotes = await scyllaClient + .execute(prepared.note.select.byIds, [noteIds], { prepare: true }) + .then((result) => result.rows.map(parseScyllaNote)); + } else { + pinnedNotes = await Promise.all( + pinings.map((pining) => Notes.findOneByOrFail({ id: pining.noteId })), + ); + } const renderedNotes = await Promise.all( pinnedNotes.map((note) => renderNote(note)), diff --git a/packages/backend/src/server/activitypub/outbox.ts b/packages/backend/src/server/activitypub/outbox.ts index e0a380ffb6..3851e0eb04 100644 --- a/packages/backend/src/server/activitypub/outbox.ts +++ b/packages/backend/src/server/activitypub/outbox.ts @@ -15,6 +15,7 @@ import { fetchMeta } from "@/misc/fetch-meta.js"; import { makePaginationQuery } from "../api/common/make-pagination-query.js"; import { setResponseType } from "../activitypub.js"; import type Router from "@koa/router"; +import { parseScyllaNote, prepared, scyllaClient } from "@/db/scylla.js"; export default async (ctx: Router.RouterContext) => { const verify = await checkFetch(ctx.req); @@ -136,7 +137,25 @@ export async function packActivity(note: Note): Promise { !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0) ) { - const renote = await Notes.findOneByOrFail({ id: note.renoteId }); + let renote: Note | null = null; + + if (scyllaClient) { + const result = await scyllaClient.execute( + prepared.note.select.byId, + [note.renoteId], + { prepare: true }, + ); + if (result.rowLength > 0) { + renote = parseScyllaNote(result.first()); + } + } else { + renote = await Notes.findOneBy({ id: note.renoteId }); + } + + if (!renote) { + throw new Error("Renote not found"); + } + return renderAnnounce( renote.uri ? renote.uri : `${config.url}/notes/${renote.id}`, note, diff --git a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts index 9722804c8d..b7b80f44e0 100644 --- a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts +++ b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts @@ -4,6 +4,7 @@ import { Notes, Users } from "@/models/index.js"; import define from "../../define.js"; import { ApiError } from "../../error.js"; import { getUser } from "../../common/getters.js"; +import { scyllaClient } from "@/db/scylla.js"; export const meta = { tags: ["users"], @@ -64,6 +65,10 @@ export default define(meta, paramDef, async (ps, me) => { throw e; }); + if (scyllaClient) { + return []; + } + // Fetch recent notes const recentNotes = await Notes.find({ where: { diff --git a/packages/backend/src/server/web/feed.ts b/packages/backend/src/server/web/feed.ts index 50e6bfc325..2aa488b79a 100644 --- a/packages/backend/src/server/web/feed.ts +++ b/packages/backend/src/server/web/feed.ts @@ -3,6 +3,8 @@ import { In, IsNull } from "typeorm"; import config from "@/config/index.js"; import type { User } from "@/models/entities/user.js"; import { Notes, DriveFiles, UserProfiles, Users } from "@/models/index.js"; +import { parseScyllaNote, prepared, scyllaClient } from "@/db/scylla.js"; +import type { Note } from "@/models/entities/note.js"; export default async function ( user: User, @@ -146,17 +148,35 @@ export default async function ( return outstr; } - async function findById(id) { + async function findById(id: string) { let text = ""; - let next = null; - const findings = await Notes.findOneBy({ - id: id, - visibility: In(["public", "home"]), - }); - if (findings) { - text += `
`; - text += await noteToString(findings); - next = findings.renoteId ? findings.renoteId : findings.replyId; + let next: string | null = null; + let note: Note | null = null; + const validVisibilities = ["public", "home"]; + + if (scyllaClient) { + const result = await scyllaClient.execute( + prepared.note.select.byId, + [id], + { prepare: true }, + ); + if (result.rowLength > 0) { + const candidate = parseScyllaNote(result.first()); + if (validVisibilities.includes(candidate.visibility)) { + note = candidate; + } + } + } else { + note = await Notes.findOneBy({ + id: id, + visibility: In(validVisibilities), + }); + } + + if (note) { + text += "
"; + text += await noteToString(note); + next = note.renoteId ? note.renoteId : note.replyId; } return { text, next }; } diff --git a/packages/backend/src/services/i/pin.ts b/packages/backend/src/services/i/pin.ts index 7e108b2774..5ebb82474a 100644 --- a/packages/backend/src/services/i/pin.ts +++ b/packages/backend/src/services/i/pin.ts @@ -78,7 +78,7 @@ export async function addPinned( } /** - * 指定した投稿のピン留めを解除します + * Remove pinned note * @param user * @param noteId */ @@ -87,12 +87,27 @@ export async function removePinned( noteId: Note["id"], ) { // Fetch unpinee - const note = await Notes.findOneBy({ - id: noteId, - userId: user.id, - }); + let note: Note | null = null; + if (scyllaClient) { + const result = await scyllaClient.execute( + prepared.note.select.byId, + [noteId], + { prepare: true }, + ); + if (result.rowLength > 0) { + const candidate = parseScyllaNote(result.first()); + if (candidate.userId === user.id) { + note = candidate; + } + } + } else { + note = await Notes.findOneBy({ + id: noteId, + userId: user.id, + }); + } - if (note == null) { + if (!note) { throw new IdentifiableError( "b302d4cf-c050-400a-bbb3-be208681f40c", "No such note.", diff --git a/packages/backend/src/services/note/polls/update.ts b/packages/backend/src/services/note/polls/update.ts index e02d48d055..41d53e66fa 100644 --- a/packages/backend/src/services/note/polls/update.ts +++ b/packages/backend/src/services/note/polls/update.ts @@ -5,13 +5,31 @@ import { Users, Notes } from "@/models/index.js"; import type { Note } from "@/models/entities/note.js"; import { deliverToFollowers } from "@/remote/activitypub/deliver-manager.js"; import { deliverToRelays } from "../../relay.js"; +import { parseScyllaNote, prepared, scyllaClient } from "@/db/scylla.js"; +import { userByIdCache } from "@/services/user-cache.js"; export async function deliverQuestionUpdate(noteId: Note["id"]) { - const note = await Notes.findOneBy({ id: noteId }); - if (note == null) throw new Error("note not found"); + let note: Note | null = null; + if (scyllaClient) { + const result = await scyllaClient.execute( + prepared.note.select.byId, + [noteId], + { prepare: true }, + ); + if (result.rowLength > 0) { + note = parseScyllaNote(result.first()); + } + } else { + note = await Notes.findOneBy({ id: noteId }); + } + if (!note) throw new Error("note not found"); - const user = await Users.findOneBy({ id: note.userId }); - if (user == null) throw new Error("note not found"); + const user = await userByIdCache.fetchMaybe(note.userId, () => + Users.findOneBy({ id: (note as Note).userId }).then( + (user) => user ?? undefined, + ), + ); + if (!user) throw new Error("note not found"); if (Users.isLocalUser(user)) { const content = renderActivity(