further cleanup
This commit is contained in:
parent
2570f8a9eb
commit
efda68bc64
8 changed files with 178 additions and 40 deletions
|
@ -1,4 +1,14 @@
|
||||||
user-agent: *
|
User-agent: *
|
||||||
allow: /
|
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: /
|
||||||
|
|
|
@ -33,6 +33,8 @@ import Following from "./activitypub/following.js";
|
||||||
import Followers from "./activitypub/followers.js";
|
import Followers from "./activitypub/followers.js";
|
||||||
import Outbox, { packActivity } from "./activitypub/outbox.js";
|
import Outbox, { packActivity } from "./activitypub/outbox.js";
|
||||||
import { serverLogger } from "./index.js";
|
import { serverLogger } from "./index.js";
|
||||||
|
import { parseScyllaNote, prepared, scyllaClient } from "@/db/scylla.js";
|
||||||
|
import type { Note } from "@/models/entities/note.js";
|
||||||
|
|
||||||
// Init router
|
// Init router
|
||||||
const router = new Router();
|
const router = new Router();
|
||||||
|
@ -87,13 +89,32 @@ router.get("/notes/:note", async (ctx, next) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const note = await Notes.findOneBy({
|
let note: Note | null = null;
|
||||||
id: ctx.params.note,
|
const validVisibilities = ["public", "home", "followers"];
|
||||||
visibility: In(["public" as const, "home" as const, "followers" as const]),
|
if (scyllaClient) {
|
||||||
localOnly: false,
|
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;
|
ctx.status = 404;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -158,14 +179,34 @@ router.get("/notes/:note/activity", async (ctx) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const note = await Notes.findOneBy({
|
let note: Note | null = null;
|
||||||
id: ctx.params.note,
|
const validVisibilities = ["public", "home"];
|
||||||
userHost: IsNull(),
|
if (scyllaClient) {
|
||||||
visibility: In(["public" as const, "home" as const]),
|
const result = await scyllaClient.execute(
|
||||||
localOnly: false,
|
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;
|
ctx.status = 404;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import { checkFetch } from "@/remote/activitypub/check-fetch.js";
|
||||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||||
import { setResponseType } from "../activitypub.js";
|
import { setResponseType } from "../activitypub.js";
|
||||||
import type Router from "@koa/router";
|
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) => {
|
export default async (ctx: Router.RouterContext) => {
|
||||||
const verify = await checkFetch(ctx.req);
|
const verify = await checkFetch(ctx.req);
|
||||||
|
@ -33,9 +35,17 @@ export default async (ctx: Router.RouterContext) => {
|
||||||
order: { id: "DESC" },
|
order: { id: "DESC" },
|
||||||
});
|
});
|
||||||
|
|
||||||
const pinnedNotes = await Promise.all(
|
let pinnedNotes: Note[] = [];
|
||||||
pinings.map((pining) => Notes.findOneByOrFail({ id: pining.noteId })),
|
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(
|
const renderedNotes = await Promise.all(
|
||||||
pinnedNotes.map((note) => renderNote(note)),
|
pinnedNotes.map((note) => renderNote(note)),
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||||
import { makePaginationQuery } from "../api/common/make-pagination-query.js";
|
import { makePaginationQuery } from "../api/common/make-pagination-query.js";
|
||||||
import { setResponseType } from "../activitypub.js";
|
import { setResponseType } from "../activitypub.js";
|
||||||
import type Router from "@koa/router";
|
import type Router from "@koa/router";
|
||||||
|
import { parseScyllaNote, prepared, scyllaClient } from "@/db/scylla.js";
|
||||||
|
|
||||||
export default async (ctx: Router.RouterContext) => {
|
export default async (ctx: Router.RouterContext) => {
|
||||||
const verify = await checkFetch(ctx.req);
|
const verify = await checkFetch(ctx.req);
|
||||||
|
@ -136,7 +137,25 @@ export async function packActivity(note: Note): Promise<any> {
|
||||||
!note.hasPoll &&
|
!note.hasPoll &&
|
||||||
(note.fileIds == null || note.fileIds.length === 0)
|
(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(
|
return renderAnnounce(
|
||||||
renote.uri ? renote.uri : `${config.url}/notes/${renote.id}`,
|
renote.uri ? renote.uri : `${config.url}/notes/${renote.id}`,
|
||||||
note,
|
note,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { Notes, Users } from "@/models/index.js";
|
||||||
import define from "../../define.js";
|
import define from "../../define.js";
|
||||||
import { ApiError } from "../../error.js";
|
import { ApiError } from "../../error.js";
|
||||||
import { getUser } from "../../common/getters.js";
|
import { getUser } from "../../common/getters.js";
|
||||||
|
import { scyllaClient } from "@/db/scylla.js";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["users"],
|
tags: ["users"],
|
||||||
|
@ -64,6 +65,10 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
throw e;
|
throw e;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (scyllaClient) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch recent notes
|
// Fetch recent notes
|
||||||
const recentNotes = await Notes.find({
|
const recentNotes = await Notes.find({
|
||||||
where: {
|
where: {
|
||||||
|
|
|
@ -3,6 +3,8 @@ import { In, IsNull } from "typeorm";
|
||||||
import config from "@/config/index.js";
|
import config from "@/config/index.js";
|
||||||
import type { User } from "@/models/entities/user.js";
|
import type { User } from "@/models/entities/user.js";
|
||||||
import { Notes, DriveFiles, UserProfiles, Users } from "@/models/index.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 (
|
export default async function (
|
||||||
user: User,
|
user: User,
|
||||||
|
@ -146,17 +148,35 @@ export default async function (
|
||||||
return outstr;
|
return outstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function findById(id) {
|
async function findById(id: string) {
|
||||||
let text = "";
|
let text = "";
|
||||||
let next = null;
|
let next: string | null = null;
|
||||||
const findings = await Notes.findOneBy({
|
let note: Note | null = null;
|
||||||
id: id,
|
const validVisibilities = ["public", "home"];
|
||||||
visibility: In(["public", "home"]),
|
|
||||||
});
|
if (scyllaClient) {
|
||||||
if (findings) {
|
const result = await scyllaClient.execute(
|
||||||
text += `<hr>`;
|
prepared.note.select.byId,
|
||||||
text += await noteToString(findings);
|
[id],
|
||||||
next = findings.renoteId ? findings.renoteId : findings.replyId;
|
{ 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 += "<hr>";
|
||||||
|
text += await noteToString(note);
|
||||||
|
next = note.renoteId ? note.renoteId : note.replyId;
|
||||||
}
|
}
|
||||||
return { text, next };
|
return { text, next };
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ export async function addPinned(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 指定した投稿のピン留めを解除します
|
* Remove pinned note
|
||||||
* @param user
|
* @param user
|
||||||
* @param noteId
|
* @param noteId
|
||||||
*/
|
*/
|
||||||
|
@ -87,12 +87,27 @@ export async function removePinned(
|
||||||
noteId: Note["id"],
|
noteId: Note["id"],
|
||||||
) {
|
) {
|
||||||
// Fetch unpinee
|
// Fetch unpinee
|
||||||
const note = await Notes.findOneBy({
|
let note: Note | null = null;
|
||||||
id: noteId,
|
if (scyllaClient) {
|
||||||
userId: user.id,
|
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(
|
throw new IdentifiableError(
|
||||||
"b302d4cf-c050-400a-bbb3-be208681f40c",
|
"b302d4cf-c050-400a-bbb3-be208681f40c",
|
||||||
"No such note.",
|
"No such note.",
|
||||||
|
|
|
@ -5,13 +5,31 @@ import { Users, Notes } from "@/models/index.js";
|
||||||
import type { Note } from "@/models/entities/note.js";
|
import type { Note } from "@/models/entities/note.js";
|
||||||
import { deliverToFollowers } from "@/remote/activitypub/deliver-manager.js";
|
import { deliverToFollowers } from "@/remote/activitypub/deliver-manager.js";
|
||||||
import { deliverToRelays } from "../../relay.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"]) {
|
export async function deliverQuestionUpdate(noteId: Note["id"]) {
|
||||||
const note = await Notes.findOneBy({ id: noteId });
|
let note: Note | null = null;
|
||||||
if (note == null) throw new Error("note not found");
|
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 });
|
const user = await userByIdCache.fetchMaybe(note.userId, () =>
|
||||||
if (user == null) throw new Error("note not found");
|
Users.findOneBy({ id: (note as Note).userId }).then(
|
||||||
|
(user) => user ?? undefined,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (!user) throw new Error("note not found");
|
||||||
|
|
||||||
if (Users.isLocalUser(user)) {
|
if (Users.isLocalUser(user)) {
|
||||||
const content = renderActivity(
|
const content = renderActivity(
|
||||||
|
|
Loading…
Reference in a new issue