From c59d7fcd0308bf362227543a19ff17c1ecd10b69 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 2 Jul 2024 23:31:28 +0900 Subject: [PATCH] fix (backend): broken RSS feed title --- packages/backend-rs/index.d.ts | 135 ++++++++++++----------- packages/backend-rs/src/misc/is_quote.rs | 14 ++- packages/backend/src/server/web/feed.ts | 31 ++++-- 3 files changed, 98 insertions(+), 82 deletions(-) diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index e0602c472b..52e4e1af1a 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -46,7 +46,7 @@ export interface Acct { host: string | null } -export function acctToString(acct: Acct): string +export declare function acctToString(acct: Acct): string export interface Ad { id: string @@ -194,7 +194,7 @@ export enum ChatIndexEvent { * * `muted_words` : list of muted keyword lists (each array item is a space-separated keyword list that represents an AND condition) * * `muted_patterns` : list of JavaScript-style (e.g., `/foo/i`) regular expressions */ -export function checkWordMute(note: PartialNoteToCheckWordMute, mutedWords: Array, mutedPatterns: Array): Promise +export declare function checkWordMute(note: PartialNoteToCheckWordMute, mutedWords: Array, mutedPatterns: Array): Promise export interface Clip { id: string @@ -263,16 +263,16 @@ export interface Config { userAgent: string } -export function countReactions(reactions: Record): Record +export declare function countReactions(reactions: Record): Record export interface Cpu { model: string cores: number } -export function cpuInfo(): Cpu +export declare function cpuInfo(): Cpu -export function cpuUsage(): number +export declare function cpuUsage(): number export const DAY: number @@ -292,7 +292,7 @@ export interface DecodedReaction { host: string | null } -export function decodeReaction(reaction: string): DecodedReaction +export declare function decodeReaction(reaction: string): DecodedReaction export interface DeepLConfig { managed?: boolean @@ -381,12 +381,12 @@ export interface Emoji { height: number | null } -export function extractHost(uri: string): string +export declare function extractHost(uri: string): string -export function fetchMeta(): Promise +export declare function fetchMeta(): Promise /** Fetches and returns the NodeInfo (version 2.0) of a remote server. */ -export function fetchNodeinfo(host: string): Promise +export declare function fetchNodeinfo(host: string): Promise /** * List of file types allowed to be viewed directly in the browser @@ -427,9 +427,9 @@ export interface FollowRequest { } /** Converts milliseconds to a human readable string. */ -export function formatMilliseconds(milliseconds: number): string +export declare function formatMilliseconds(milliseconds: number): string -export function fromMastodonId(mastodonId: string): string | null +export declare function fromMastodonId(mastodonId: string): string | null export interface GalleryLike { id: string @@ -452,9 +452,9 @@ export interface GalleryPost { } /** Generates a random string based on [thread_rng] and [Alphanumeric]. */ -export function generateSecureRandomString(length: number): string +export declare function generateSecureRandomString(length: number): string -export function generateUserToken(): string +export declare function generateUserToken(): string /** * The generated ID results in the form of `[8 chars timestamp] + [cuid2]`. @@ -464,24 +464,24 @@ export function generateUserToken(): string * * Ref: */ -export function genId(): string +export declare function genId(): string /** Generate an ID using a specific datetime */ -export function genIdAt(date: Date): string +export declare function genIdAt(date: Date): string -export function getFullApAccount(username: string, host?: string | undefined | null): string +export declare function getFullApAccount(username: string, host?: string | undefined | null): string -export function getImageSizeFromUrl(url: string): Promise +export declare function getImageSizeFromUrl(url: string): Promise -export function getNoteSummary(fileIds: Array, text: string | undefined | null, cw: string | undefined | null, hasPoll: boolean): string +export declare function getNoteSummary(fileIds: Array, text: string | undefined | null, cw: string | undefined | null, hasPoll: boolean): string -export function getTimestamp(id: string): number +export declare function getTimestamp(id: string): number /** Prints the greeting message and the Firefish version to stdout. */ -export function greet(): void +export declare function greet(): void /** Hashes the given password using [argon2] algorithm. */ -export function hashPassword(password: string): string +export declare function hashPassword(password: string): string export interface Hashtag { id: string @@ -525,7 +525,7 @@ export enum Inbound { } /** Initializes the [tracing] logger. */ -export function initializeRustLogger(): void +export declare function initializeRustLogger(): void export interface Instance { id: string @@ -573,7 +573,7 @@ export interface Instance { * # } * ``` */ -export function isAllowedServer(host: string): Promise +export declare function isAllowedServer(host: string): Promise /** * Checks if a server is blocked. @@ -593,18 +593,18 @@ export function isAllowedServer(host: string): Promise * # } * ``` */ -export function isBlockedServer(host: string): Promise +export declare function isBlockedServer(host: string): Promise /** Returns whether the [bcrypt] algorithm is used for the password hash. */ -export function isOldPasswordAlgorithm(hash: string): boolean +export declare function isOldPasswordAlgorithm(hash: string): boolean -export function isQuote(note: Note): boolean +export declare function isQuote(note: NoteLikeForIsQuote): boolean -export function isSafeUrl(url: string): boolean +export declare function isSafeUrl(url: string): boolean -export function isSameOrigin(uri: string): boolean +export declare function isSameOrigin(uri: string): boolean -export function isSelfHost(host?: string | undefined | null): boolean +export declare function isSelfHost(host?: string | undefined | null): boolean /** * Checks if a server is silenced. @@ -624,12 +624,12 @@ export function isSelfHost(host?: string | undefined | null): boolean * # } * ``` */ -export function isSilencedServer(host: string): Promise +export declare function isSilencedServer(host: string): Promise -export function isUnicodeEmoji(s: string): boolean +export declare function isUnicodeEmoji(s: string): boolean /** Returns the latest Firefish version. */ -export function latestVersion(): Promise +export declare function latestVersion(): Promise export interface LibreTranslateConfig { managed?: boolean @@ -637,7 +637,7 @@ export interface LibreTranslateConfig { apiKey?: string } -export function loadConfig(): Config +export declare function loadConfig(): Config export interface Memory { /** Total memory amount in bytes */ @@ -648,7 +648,7 @@ export interface Memory { available: number } -export function memoryUsage(): Memory +export declare function memoryUsage(): Memory export interface MessagingMessage { id: string @@ -751,7 +751,7 @@ export interface Meta { antennaLimit: number } -export function metaToPugArgs(meta: Meta): PugArgs +export declare function metaToPugArgs(meta: Meta): PugArgs export interface Migrations { id: number @@ -807,9 +807,9 @@ export interface Nodeinfo { metadata: Record } -export function nodeinfo_2_0(): Promise +export declare function nodeinfo_2_0(): Promise -export function nodeinfo_2_1(): Promise +export declare function nodeinfo_2_1(): Promise export interface Note { id: string @@ -871,6 +871,13 @@ export interface NoteFile { fileId: string } +export interface NoteLikeForIsQuote { + renoteId: string | null + text: string | null + hasPoll: boolean + fileIds: Array +} + export interface NoteReaction { id: string createdAt: DateTimeWithTimeZone @@ -964,7 +971,7 @@ export enum NotificationType { * assert_eq!(nyaify("I'll take a nap.", Some("en")), "I'll take a nyap."); * ``` */ -export function nyaify(text: string, lang?: string | undefined | null): string +export declare function nyaify(text: string, lang?: string | undefined | null): string export interface ObjectStorageConfig { managed?: boolean @@ -1126,23 +1133,23 @@ export enum Protocol { Zot = 9 } -export function publishToBroadcastStream(emoji: PackedEmoji): Promise +export declare function publishToBroadcastStream(emoji: PackedEmoji): Promise -export function publishToChannelStream(channelId: string, userId: string): Promise +export declare function publishToChannelStream(channelId: string, userId: string): Promise -export function publishToChatIndexStream(userId: string, kind: ChatIndexEvent, object: any): Promise +export declare function publishToChatIndexStream(userId: string, kind: ChatIndexEvent, object: any): Promise -export function publishToChatStream(senderUserId: string, receiverUserId: string, kind: ChatEvent, object: any): Promise +export declare function publishToChatStream(senderUserId: string, receiverUserId: string, kind: ChatEvent, object: any): Promise -export function publishToDriveFileStream(userId: string, kind: DriveFileEvent, object: any): Promise +export declare function publishToDriveFileStream(userId: string, kind: DriveFileEvent, object: any): Promise -export function publishToDriveFolderStream(userId: string, kind: DriveFolderEvent, object: any): Promise +export declare function publishToDriveFolderStream(userId: string, kind: DriveFolderEvent, object: any): Promise -export function publishToGroupChatStream(groupId: string, kind: ChatEvent, object: any): Promise +export declare function publishToGroupChatStream(groupId: string, kind: ChatEvent, object: any): Promise -export function publishToModerationStream(moderatorId: string, report: AbuseUserReportLike): Promise +export declare function publishToModerationStream(moderatorId: string, report: AbuseUserReportLike): Promise -export function publishToNotesStream(note: Note): Promise +export declare function publishToNotesStream(note: Note): Promise export interface PugArgs { img: string | null @@ -1207,7 +1214,7 @@ export enum RelayStatus { } /** Delete all entries in the [attestation_challenge] table created at more than 5 minutes ago */ -export function removeOldAttestationChallenges(): Promise +export declare function removeOldAttestationChallenges(): Promise export interface RenoteMuting { id: string @@ -1224,11 +1231,11 @@ export interface ReplyMuting { } /** Returns `true` if `src` does not contain suspicious characters like `%`. */ -export function safeForSql(src: string): boolean +export declare function safeForSql(src: string): boolean export const SECOND: number -export function sendPushNotification(receiverUserId: string, kind: PushNotificationKind, content: any): Promise +export declare function sendPushNotification(receiverUserId: string, kind: PushNotificationKind, content: any): Promise export interface ServerConfig { url: string @@ -1289,7 +1296,7 @@ export interface Services { } /** Prints the server hardware information as the server info log. */ -export function showServerInfo(): void +export declare function showServerInfo(): void export interface Signin { id: string @@ -1309,7 +1316,7 @@ export interface Software20 { } /** Escapes `%` and `\` in the given string. */ -export function sqlLikeEscape(src: string): string +export declare function sqlLikeEscape(src: string): string export interface Storage { /** Total storage space in bytes */ @@ -1318,9 +1325,9 @@ export interface Storage { used: number } -export function storageUsage(): Storage | null +export declare function storageUsage(): Storage | null -export function stringToAcct(acct: string): Acct +export declare function stringToAcct(acct: string): Acct export interface SwSubscription { id: string @@ -1342,21 +1349,21 @@ export interface TlsConfig { rejectUnauthorized: boolean } -export function toDbReaction(reaction?: string | undefined | null, host?: string | undefined | null): Promise +export declare function toDbReaction(reaction?: string | undefined | null, host?: string | undefined | null): Promise -export function toMastodonId(firefishId: string): string | null +export declare function toMastodonId(firefishId: string): string | null -export function toPuny(host: string): string +export declare function toPuny(host: string): string -export function unwatchNote(watcherId: string, noteId: string): Promise +export declare function unwatchNote(watcherId: string, noteId: string): Promise -export function updateAntennaCache(): Promise +export declare function updateAntennaCache(): Promise -export function updateAntennasOnNewNote(note: Note, noteAuthor: Acct, noteMutedUsers: Array): Promise +export declare function updateAntennasOnNewNote(note: Note, noteAuthor: Acct, noteMutedUsers: Array): Promise -export function updateMetaCache(): Promise +export declare function updateMetaCache(): Promise -export function updateNodeinfoCache(): Promise +export declare function updateNodeinfoCache(): Promise /** Usage statistics for this server. */ export interface Usage { @@ -1575,9 +1582,9 @@ export interface UserSecurityKey { } /** Checks whether the given password and hash match. */ -export function verifyPassword(password: string, hash: string): boolean +export declare function verifyPassword(password: string, hash: string): boolean -export function watchNote(watcherId: string, noteAuthorId: string, noteId: string): Promise +export declare function watchNote(watcherId: string, noteAuthorId: string, noteId: string): Promise export interface Webhook { id: string diff --git a/packages/backend-rs/src/misc/is_quote.rs b/packages/backend-rs/src/misc/is_quote.rs index 3ee15a5873..e754b82936 100644 --- a/packages/backend-rs/src/misc/is_quote.rs +++ b/packages/backend-rs/src/misc/is_quote.rs @@ -1,10 +1,12 @@ -use crate::model::entity::note; - -// for napi export -// https://github.com/napi-rs/napi-rs/issues/2060 -type Note = note::Model; +#[macros::export(object, js_name = "NoteLikeForIsQuote")] +pub struct NoteLike { + pub renote_id: Option, + pub text: Option, + pub has_poll: bool, + pub file_ids: Vec, +} #[macros::export] -pub fn is_quote(note: Note) -> bool { +pub fn is_quote(note: &NoteLike) -> bool { note.renote_id.is_some() && (note.text.is_some() || note.has_poll || !note.file_ids.is_empty()) } diff --git a/packages/backend/src/server/web/feed.ts b/packages/backend/src/server/web/feed.ts index 3beffc82f0..efdda8c1cd 100644 --- a/packages/backend/src/server/web/feed.ts +++ b/packages/backend/src/server/web/feed.ts @@ -5,6 +5,7 @@ import type { User } from "@/models/entities/user.js"; import type { Note } from "@/models/entities/note.js"; import { Notes, DriveFiles, UserProfiles, Users } from "@/models/index.js"; import getNoteHtml from "@/remote/activitypub/misc/get-note-html.js"; +import { isQuote, getNoteSummary } from "backend-rs"; /** * If there is this part in the note, it will cause CDATA to be terminated early. @@ -17,7 +18,7 @@ export default async function ( user: User, threadDepth = 5, history = 20, - noteintitle = false, + noteintitle = true, renotes = true, replies = true, ) { @@ -81,20 +82,26 @@ export default async function ( depth -= 1; } - let title = `${author.name} `; - if (note.renoteId) { - title += "renotes"; - } else if (note.replyId) { - title += "replies"; - } else { - title += "says"; - } + let title = `Post by ${author.name}`; + if (noteintitle) { - const content = note.cw ?? note.text; + if (note.renoteId) { + title = `Boost by ${author.name}`; + } else if (note.replyId) { + title = `Reply by ${author.name}`; + } else { + title = `Post by ${author.name}`; + } + const effectiveNote = + !isQuote(note) && note.renote != null ? note.renote : note; + const content = getNoteSummary( + effectiveNote.fileIds, + effectiveNote.text, + effectiveNote.cw, + effectiveNote.hasPoll, + ); if (content) { title += `: ${content}`; - } else { - title += "something"; } }