This commit is contained in:
浪子
2026-05-16 00:36:39 +08:00
parent cba4901058
commit 52c437311a
2 changed files with 24 additions and 7 deletions
+22 -5
View File
@@ -8,6 +8,7 @@ import {
getStatus, getStatus,
getStatusByObjectId, getStatusByObjectId,
getUserByUsername, getUserByUsername,
listMediaForStatus,
listProfileFields, listProfileFields,
recordNotification, recordNotification,
upsertActorCache, upsertActorCache,
@@ -33,7 +34,7 @@ import {
PUBLIC_COLLECTION, PUBLIC_COLLECTION,
SECURITY_CONTEXT SECURITY_CONTEXT
} from "./types"; } from "./types";
import type { ActorCache, CachedStatus, CachedStatusMention, CachedStatusTag, Json, RemoteActor, Status, User } from "./types"; import type { ActorCache, CachedStatus, CachedStatusMention, CachedStatusTag, Json, Media, RemoteActor, Status, User } from "./types";
import { import {
actorUrl, actorUrl,
activityUrl, activityUrl,
@@ -175,7 +176,7 @@ export async function outbox(request: Request, env: Env, username: string): Prom
const rows = await env.DB.prepare( const rows = await env.DB.prepare(
"SELECT * FROM statuses WHERE user_id = ? AND visibility IN ('public', 'unlisted') ORDER BY created_at DESC LIMIT ?" "SELECT * FROM statuses WHERE user_id = ? AND visibility IN ('public', 'unlisted') ORDER BY created_at DESC LIMIT ?"
).bind(user.id, limit).all<Status>(); ).bind(user.id, limit).all<Status>();
const items = rows.results.map((status) => createActivity(env, user, status)); const items = await Promise.all(rows.results.map((status) => createActivity(env, user, status)));
return activityJson({ return activityJson({
"@context": ACTIVITY_CONTEXT, "@context": ACTIVITY_CONTEXT,
id: `${base}?page=true`, id: `${base}?page=true`,
@@ -216,7 +217,8 @@ export async function activityObject(env: Env, objectId: string): Promise<Respon
if (status.visibility !== "public" && status.visibility !== "unlisted") return json({ error: "not_found" }, 404); if (status.visibility !== "public" && status.visibility !== "unlisted") return json({ error: "not_found" }, 404);
const user = await env.DB.prepare("SELECT * FROM users WHERE id = ?").bind(status.user_id).first<User>(); const user = await env.DB.prepare("SELECT * FROM users WHERE id = ?").bind(status.user_id).first<User>();
if (!user) return json({ error: "not_found" }, 404); if (!user) return json({ error: "not_found" }, 404);
return activityJson(noteObject(env, user, status)); const attachments = await loadStatusAttachments(env, status.id);
return activityJson(noteObject(env, user, status, { attachments }));
} }
const tomb = await env.DB.prepare("SELECT * FROM deleted_statuses WHERE id = ?").bind(objectId).first<{ id: string; deleted_at: string }>(); const tomb = await env.DB.prepare("SELECT * FROM deleted_statuses WHERE id = ?").bind(objectId).first<{ id: string; deleted_at: string }>();
if (tomb) { if (tomb) {
@@ -596,10 +598,11 @@ async function localUserFromTarget(env: Env, actorId: string | null): Promise<Us
return getUserByUsername(env, match[1]); return getUserByUsername(env, match[1]);
} }
export function createActivity(env: Env, user: User, status: Status, extra: { to?: string[]; cc?: string[] } = {}): Json { export async function createActivity(env: Env, user: User, status: Status, extra: { to?: string[]; cc?: string[] } = {}): Promise<Json> {
const audience = statusAudience(env, user, status); const audience = statusAudience(env, user, status);
const to = extra.to ?? audience.to; const to = extra.to ?? audience.to;
const cc = extra.cc ?? audience.cc; const cc = extra.cc ?? audience.cc;
const attachments = await loadStatusAttachments(env, status.id);
return { return {
"@context": [ACTIVITY_CONTEXT, SECURITY_CONTEXT], "@context": [ACTIVITY_CONTEXT, SECURITY_CONTEXT],
id: status.activity_id, id: status.activity_id,
@@ -608,10 +611,24 @@ export function createActivity(env: Env, user: User, status: Status, extra: { to
published: status.created_at, published: status.created_at,
to, to,
cc, cc,
object: noteObject(env, user, status, { to, cc }) object: noteObject(env, user, status, { to, cc, attachments })
}; };
} }
export function attachmentObject(env: Env, media: Media): Json {
return {
type: media.mime_type.startsWith("image/") ? "Image" : "Document",
mediaType: media.mime_type,
url: mediaUrl(env, media.r2_key),
name: media.description ?? null
};
}
export async function loadStatusAttachments(env: Env, statusId: string): Promise<Json[]> {
const media = await listMediaForStatus(env, statusId);
return media.map((item) => attachmentObject(env, item));
}
function statusAudience(env: Env, user: User, status: Status): { to: string[]; cc: string[] } { function statusAudience(env: Env, user: User, status: Status): { to: string[]; cc: string[] } {
if (status.visibility === "unlisted") { if (status.visibility === "unlisted") {
return { to: [`${actorUrl(env, user)}/followers`], cc: [PUBLIC_COLLECTION] }; return { to: [`${actorUrl(env, user)}/followers`], cc: [PUBLIC_COLLECTION] };
+2 -2
View File
@@ -696,7 +696,7 @@ async function publishStatus(env: Env, user: User, input: StatusCreateInput): Pr
: input.visibility === "unlisted" : input.visibility === "unlisted"
? ["https://www.w3.org/ns/activitystreams#Public", ...mentionActors] ? ["https://www.w3.org/ns/activitystreams#Public", ...mentionActors]
: []; : [];
const activity = createActivity(env, user, status, { to, cc }); const activity = await createActivity(env, user, status, { to, cc });
await deliverToInboxes(env, user, inboxes, activity); await deliverToInboxes(env, user, inboxes, activity);
} else if (input.visibility === "direct") { } else if (input.visibility === "direct") {
const inboxes = new Set<string>(); const inboxes = new Set<string>();
@@ -706,7 +706,7 @@ async function publishStatus(env: Env, user: User, input: StatusCreateInput): Pr
if (cache) inboxes.add(cache.shared_inbox ?? cache.inbox); if (cache) inboxes.add(cache.shared_inbox ?? cache.inbox);
} }
} }
const activity = createActivity(env, user, status, { to: resolvedMentions.map((m) => m.actorId), cc: [] }); const activity = await createActivity(env, user, status, { to: resolvedMentions.map((m) => m.actorId), cc: [] });
await deliverToInboxes(env, user, inboxes, activity); await deliverToInboxes(env, user, inboxes, activity);
} }