From 69be5af48f8dee8d44c8b95758d387a34a6ba4ad Mon Sep 17 00:00:00 2001
From: CI <project_7_bot_1bfaee5701aed20091a86249a967a6c1@noreply.firefish.dev>
Date: Sun, 9 Jun 2024 12:06:15 +0000
Subject: [PATCH 1/2] chore(deps): update rust crate regex to 1.10.5

---
 Cargo.lock | 4 ++--
 Cargo.toml | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 583c3e9041..44cf837769 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2470,9 +2470,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.10.4"
+version = "1.10.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
+checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
 dependencies = [
  "aho-corasick",
  "memchr",
diff --git a/Cargo.toml b/Cargo.toml
index ce4f502ba5..de00661349 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,7 +29,7 @@ proc-macro2 = { version = "1.0.85", default-features = false }
 quote = { version = "1.0.36", default-features = false }
 rand = { version = "0.8.5", default-features = false }
 redis = { version = "0.25.4", default-features = false }
-regex = { version = "1.10.4", default-features = false }
+regex = { version = "1.10.5", default-features = false }
 rmp-serde = { version = "1.3.0", default-features = false }
 sea-orm = { version = "0.12.15", default-features = false }
 serde = { version = "1.0.203", default-features = false }

From 679749a2cc92ad37f2c57b4f769709c88d4d620b Mon Sep 17 00:00:00 2001
From: naskya <m@naskya.net>
Date: Sun, 9 Jun 2024 21:09:11 +0900
Subject: [PATCH 2/2] chore (backend-rs): rename modules to more comfortable
 names

---
 packages/backend-rs/index.d.ts                |   8 +-
 packages/backend-rs/index.js                  |   4 +-
 .../backend-rs/src/misc/check_word_mute.rs    |   4 +-
 .../backend-rs/src/misc/get_note_summary.rs   |  93 -----------
 packages/backend-rs/src/misc/mod.rs           |   3 +-
 .../elaborate.rs}                             |  28 ++--
 packages/backend-rs/src/misc/note/mod.rs      |   5 +
 .../backend-rs/src/misc/note/summarize.rs     | 145 ++++++++++++++++++
 .../src/service/antenna/process_new_note.rs   |   4 +-
 .../src/service/push_notification.rs          |  22 ++-
 packages/backend/src/server/web/index.ts      |  10 +-
 11 files changed, 193 insertions(+), 133 deletions(-)
 delete mode 100644 packages/backend-rs/src/misc/get_note_summary.rs
 rename packages/backend-rs/src/misc/{get_note_all_texts.rs => note/elaborate.rs} (86%)
 create mode 100644 packages/backend-rs/src/misc/note/mod.rs
 create mode 100644 packages/backend-rs/src/misc/note/summarize.rs

diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts
index 9063008572..5f51bba686 100644
--- a/packages/backend-rs/index.d.ts
+++ b/packages/backend-rs/index.d.ts
@@ -419,19 +419,13 @@ export interface ImageSize {
   height: number
 }
 export function getImageSizeFromUrl(url: string): Promise<ImageSize>
-export interface PartialNoteToSummarize {
-  fileIds: Array<string>
-  text: string | null
-  cw: string | null
-  hasPoll: boolean
-}
-export function getNoteSummary(note: PartialNoteToSummarize): string
 export function isQuote(note: Note): boolean
 export function isSafeUrl(url: string): boolean
 /** Returns the latest Firefish version. */
 export function latestVersion(): Promise<string>
 export function toMastodonId(firefishId: string): string | null
 export function fromMastodonId(mastodonId: string): string | null
+export function getNoteSummary(fileIds: Array<string>, text: string | undefined | null, cw: string | undefined | null, hasPoll: boolean): string
 /**
  * Converts the given text into the cat language.
  *
diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js
index b4a6bea090..6559eef30f 100644
--- a/packages/backend-rs/index.js
+++ b/packages/backend-rs/index.js
@@ -310,7 +310,7 @@ if (!nativeBinding) {
   throw new Error(`Failed to load native binding`)
 }
 
-const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, fetchMeta, updateMetaCache, metaToPugArgs, loadConfig, stringToAcct, acctToString, fetchNodeinfo, nodeinfo_2_1, nodeinfo_2_0, updateNodeinfoCache, Protocol, Inbound, Outbound, greet, initializeRustLogger, showServerInfo, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, isQuote, isSafeUrl, latestVersion, toMastodonId, fromMastodonId, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, cpuInfo, cpuUsage, memoryUsage, storageUsage, AntennaSrc, DriveFileUsageHint, MutedNoteReason, NoteVisibility, NotificationType, PageVisibility, PollNoteVisibility, RelayStatus, UserEmojiModPerm, UserProfileFfvisibility, UserProfileMutingNotificationTypes, updateAntennasOnNewNote, updateAntennaCache, watchNote, unwatchNote, PushNotificationKind, sendPushNotification, publishToChannelStream, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, ChatEvent, getTimestamp, genId, genIdAt, generateSecureRandomString, generateUserToken } = nativeBinding
+const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, fetchMeta, updateMetaCache, metaToPugArgs, loadConfig, stringToAcct, acctToString, fetchNodeinfo, nodeinfo_2_1, nodeinfo_2_0, updateNodeinfoCache, Protocol, Inbound, Outbound, greet, initializeRustLogger, showServerInfo, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, isQuote, isSafeUrl, latestVersion, toMastodonId, fromMastodonId, getNoteSummary, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, cpuInfo, cpuUsage, memoryUsage, storageUsage, AntennaSrc, DriveFileUsageHint, MutedNoteReason, NoteVisibility, NotificationType, PageVisibility, PollNoteVisibility, RelayStatus, UserEmojiModPerm, UserProfileFfvisibility, UserProfileMutingNotificationTypes, updateAntennasOnNewNote, updateAntennaCache, watchNote, unwatchNote, PushNotificationKind, sendPushNotification, publishToChannelStream, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, ChatEvent, getTimestamp, genId, genIdAt, generateSecureRandomString, generateUserToken } = nativeBinding
 
 module.exports.SECOND = SECOND
 module.exports.MINUTE = MINUTE
@@ -349,12 +349,12 @@ module.exports.sqlLikeEscape = sqlLikeEscape
 module.exports.safeForSql = safeForSql
 module.exports.formatMilliseconds = formatMilliseconds
 module.exports.getImageSizeFromUrl = getImageSizeFromUrl
-module.exports.getNoteSummary = getNoteSummary
 module.exports.isQuote = isQuote
 module.exports.isSafeUrl = isSafeUrl
 module.exports.latestVersion = latestVersion
 module.exports.toMastodonId = toMastodonId
 module.exports.fromMastodonId = fromMastodonId
+module.exports.getNoteSummary = getNoteSummary
 module.exports.nyaify = nyaify
 module.exports.hashPassword = hashPassword
 module.exports.verifyPassword = verifyPassword
diff --git a/packages/backend-rs/src/misc/check_word_mute.rs b/packages/backend-rs/src/misc/check_word_mute.rs
index 6faf9352ec..6c3e7875e6 100644
--- a/packages/backend-rs/src/misc/check_word_mute.rs
+++ b/packages/backend-rs/src/misc/check_word_mute.rs
@@ -1,4 +1,4 @@
-use crate::misc::get_note_all_texts::all_texts;
+use crate::misc::note::elaborate;
 use once_cell::sync::Lazy;
 use regex::Regex;
 use sea_orm::DbErr;
@@ -59,7 +59,7 @@ pub async fn check_word_mute(
         Ok(false)
     } else {
         Ok(check_word_mute_impl(
-            &all_texts!(note, true).await?,
+            &elaborate!(note, true).await?,
             muted_words,
             muted_patterns,
         ))
diff --git a/packages/backend-rs/src/misc/get_note_summary.rs b/packages/backend-rs/src/misc/get_note_summary.rs
deleted file mode 100644
index f2bfcd2470..0000000000
--- a/packages/backend-rs/src/misc/get_note_summary.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-use serde::Deserialize;
-
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-#[crate::export(object)]
-pub struct PartialNoteToSummarize {
-    pub file_ids: Vec<String>,
-    pub text: Option<String>,
-    pub cw: Option<String>,
-    pub has_poll: bool,
-}
-
-#[crate::export]
-pub fn get_note_summary(note: PartialNoteToSummarize) -> String {
-    let mut buf: Vec<String> = vec![];
-
-    if let Some(cw) = note.cw {
-        buf.push(cw)
-    } else if let Some(text) = note.text {
-        buf.push(text)
-    }
-
-    match note.file_ids.len() {
-        0 => (),
-        1 => buf.push("📎".to_string()),
-        n => buf.push(format!("📎 ({})", n)),
-    };
-
-    if note.has_poll {
-        buf.push("📊".to_string())
-    }
-
-    buf.join(" ")
-}
-
-#[cfg(test)]
-mod unit_test {
-    use super::{get_note_summary, PartialNoteToSummarize};
-    use pretty_assertions::assert_eq;
-
-    #[test]
-    fn test_note_summary() {
-        let note = PartialNoteToSummarize {
-            file_ids: vec![],
-            text: Some("Hello world!".to_string()),
-            cw: None,
-            has_poll: false,
-        };
-        assert_eq!(get_note_summary(note), "Hello world!");
-
-        let note_with_cw = PartialNoteToSummarize {
-            file_ids: vec![],
-            text: Some("Hello world!".to_string()),
-            cw: Some("Content warning".to_string()),
-            has_poll: false,
-        };
-        assert_eq!(get_note_summary(note_with_cw), "Content warning");
-
-        let note_with_file_and_cw = PartialNoteToSummarize {
-            file_ids: vec!["9s7fmcqogiq4igin".to_string()],
-            text: None,
-            cw: Some("Selfie, no ec".to_string()),
-            has_poll: false,
-        };
-        assert_eq!(get_note_summary(note_with_file_and_cw), "Selfie, no ec 📎");
-
-        let note_with_files_only = PartialNoteToSummarize {
-            file_ids: vec![
-                "9s7fmcqogiq4igin".to_string(),
-                "9s7qrld5u14cey98".to_string(),
-                "9s7gebs5zgts4kca".to_string(),
-                "9s5z3e4vefqd29ee".to_string(),
-            ],
-            text: None,
-            cw: None,
-            has_poll: false,
-        };
-        assert_eq!(get_note_summary(note_with_files_only), "📎 (4)");
-
-        let note_all = PartialNoteToSummarize {
-            file_ids: vec![
-                "9s7fmcqogiq4igin".to_string(),
-                "9s7qrld5u14cey98".to_string(),
-                "9s7gebs5zgts4kca".to_string(),
-                "9s5z3e4vefqd29ee".to_string(),
-            ],
-            text: Some("Hello world!".to_string()),
-            cw: Some("Content warning".to_string()),
-            has_poll: true,
-        };
-        assert_eq!(get_note_summary(note_all), "Content warning 📎 (4) 📊");
-    }
-}
diff --git a/packages/backend-rs/src/misc/mod.rs b/packages/backend-rs/src/misc/mod.rs
index 9d717ded7f..e3eb23a2eb 100644
--- a/packages/backend-rs/src/misc/mod.rs
+++ b/packages/backend-rs/src/misc/mod.rs
@@ -7,12 +7,11 @@ pub mod emoji;
 pub mod escape_sql;
 pub mod format_milliseconds;
 pub mod get_image_size;
-pub mod get_note_all_texts;
-pub mod get_note_summary;
 pub mod is_quote;
 pub mod is_safe_url;
 pub mod latest_version;
 pub mod mastodon_id;
+pub mod note;
 pub mod nyaify;
 pub mod password;
 pub mod reaction;
diff --git a/packages/backend-rs/src/misc/get_note_all_texts.rs b/packages/backend-rs/src/misc/note/elaborate.rs
similarity index 86%
rename from packages/backend-rs/src/misc/get_note_all_texts.rs
rename to packages/backend-rs/src/misc/note/elaborate.rs
index 8db5fbc8f3..878dbb4f83 100644
--- a/packages/backend-rs/src/misc/get_note_all_texts.rs
+++ b/packages/backend-rs/src/misc/note/elaborate.rs
@@ -6,7 +6,7 @@ use sea_orm::{prelude::*, QuerySelect};
 
 /// Returns [`Vec<String>`] containing the post text, content warning,
 /// those of the "parent" (replied/quoted) posts, and alt texts of attached files.
-/// Consider using [`all_texts`] macro instead
+/// Consider using [`elaborate`] macro instead
 /// when dealing with a note ([`note::Model`])-like instance.
 ///
 /// # Arguments
@@ -14,7 +14,7 @@ use sea_orm::{prelude::*, QuerySelect};
 /// * `file_ids` : IDs of attached files ([`drive_file::Model`])
 /// * `text`, `cw`, `renote_id`, `reply_id` : note ([`note::Model`]) fields
 /// * `include_parent` : whether to take the reply-to post and quoted post into account
-pub async fn all_texts_impl(
+pub async fn elaborate_impl(
     file_ids: &[String],
     text: Option<String>,
     cw: Option<String>,
@@ -87,15 +87,15 @@ pub async fn all_texts_impl(
 /// # Caveats
 ///
 /// The `note_like` argument should not contain function calls
-/// (e.g., `all_texts!(note.clone(), false)`)
+/// (e.g., `elaborate!(note.clone(), false)`)
 /// since the function will be called multiple times after macro expansion.
 ///
 /// # Examples
 ///
 /// ```
-/// # use backend_rs::misc::get_note_all_texts::all_texts;
+/// # use backend_rs::misc::note::elaborate;
 /// // note-like struct
-/// struct SomeNoteLikeStruct {
+/// struct NoteLike {
 ///     // required fields
 ///     file_ids: Vec<String>,
 ///     text: Option<String>,
@@ -107,18 +107,19 @@ pub async fn all_texts_impl(
 ///     extra_field_2: Vec<String>,
 /// }
 ///
-/// async fn all_texts_from_some_note_like_struct(
-///     note_like: &SomeNoteLikeStruct,
-///     include_parent: bool,
-/// ) -> Result<Vec<String>, sea_orm::DbErr> {
-///     all_texts!(note_like, include_parent).await
+/// async fn print_all_related_texts(
+///     note: &NoteLike
+/// ) -> Result<(), sea_orm::DbErr> {
+///     let all_texts = elaborate!(note, true).await?;
+///     all_texts.iter().map(|text| println!("{}", text));
+///     Ok(())
 /// }
 /// ```
 #[doc(hidden)] // hide the macro in the top doc page
 #[macro_export]
-macro_rules! all_texts {
+macro_rules! elaborate {
     ($note_like:expr, $include_parent:expr) => {
-        $crate::misc::get_note_all_texts::all_texts_impl(
+        $crate::misc::note::elaborate::elaborate_impl(
             &$note_like.file_ids,
             $note_like.text.clone(),
             $note_like.cw.clone(),
@@ -128,5 +129,6 @@ macro_rules! all_texts {
         )
     };
 }
+
 #[doc(inline)] // show the macro in the module doc page
-pub use all_texts;
+pub use elaborate;
diff --git a/packages/backend-rs/src/misc/note/mod.rs b/packages/backend-rs/src/misc/note/mod.rs
new file mode 100644
index 0000000000..84e2560af8
--- /dev/null
+++ b/packages/backend-rs/src/misc/note/mod.rs
@@ -0,0 +1,5 @@
+pub use elaborate::elaborate;
+pub use summarize::summarize;
+
+pub mod elaborate;
+pub mod summarize;
diff --git a/packages/backend-rs/src/misc/note/summarize.rs b/packages/backend-rs/src/misc/note/summarize.rs
new file mode 100644
index 0000000000..2bfabba71b
--- /dev/null
+++ b/packages/backend-rs/src/misc/note/summarize.rs
@@ -0,0 +1,145 @@
+#[crate::export(js_name = "getNoteSummary")]
+pub fn summarize_impl(
+    file_ids: &[String],
+    text: Option<String>,
+    cw: Option<String>,
+    has_poll: bool,
+) -> String {
+    let mut buf: Vec<String> = vec![];
+
+    if let Some(cw) = cw {
+        buf.push(cw)
+    } else if let Some(text) = text {
+        buf.push(text)
+    }
+
+    match file_ids.len() {
+        0 => (),
+        1 => buf.push("📎".to_string()),
+        n => buf.push(format!("📎 ({})", n)),
+    };
+
+    if has_poll {
+        buf.push("📊".to_string())
+    }
+
+    buf.join(" ")
+}
+
+/// Returns the summary of a post, which can be used to display posts in small spaces
+/// such as push notifications.
+///
+/// # Arguments
+///
+/// * `note_like` : a note ([`crate::model::entity::note::Model`])-like instance containing
+///   `file_ids`, `text`, `cw`, `has_poll` fields
+///
+/// # Caveats
+///
+/// The `note_like` argument should not contain function calls
+/// (e.g., `summarize!(note.clone())`)
+/// since the function will be called multiple times after macro expansion.
+///
+/// # Examples
+///
+/// ```
+/// # use backend_rs::misc::note::summarize;
+/// // note-like struct
+/// struct NoteLike {
+///     // required fields
+///     file_ids: Vec<String>,
+///     text: Option<String>,
+///     cw: Option<String>,
+///     has_poll: bool,
+///     // arbitrary extra fields
+///     renote_id: Option<String>,
+///     reply_id: Option<String>,
+///     extra_field_1: u32,
+///     extra_field_2: Vec<String>,
+/// }
+///
+/// fn print_note_summary(note: &NoteLike) {
+///     println!("{}", summarize!(note));
+/// }
+/// ```
+#[doc(hidden)] // hide the macro in the top doc page
+#[macro_export]
+macro_rules! summarize {
+    ($note_like:expr) => {
+        $crate::misc::note::summarize::summarize_impl(
+            &$note_like.file_ids,
+            $note_like.text.to_owned(),
+            $note_like.cw.to_owned(),
+            $note_like.has_poll.to_owned(),
+        )
+    };
+}
+
+#[doc(inline)] // show the macro in the module doc page
+pub use summarize;
+
+#[cfg(test)]
+mod unit_test {
+    use super::summarize;
+    use pretty_assertions::assert_eq;
+
+    struct NoteLike {
+        file_ids: Vec<String>,
+        text: Option<String>,
+        cw: Option<String>,
+        has_poll: bool,
+    }
+
+    #[test]
+    fn summarize() {
+        let note = NoteLike {
+            file_ids: vec![],
+            text: Some("Hello world!".to_string()),
+            cw: None,
+            has_poll: false,
+        };
+        assert_eq!(summarize!(note), "Hello world!");
+
+        let note_with_cw = NoteLike {
+            file_ids: vec![],
+            text: Some("Hello world!".to_string()),
+            cw: Some("Content warning".to_string()),
+            has_poll: false,
+        };
+        assert_eq!(summarize!(note_with_cw), "Content warning");
+
+        let note_with_file_and_cw = NoteLike {
+            file_ids: vec!["9s7fmcqogiq4igin".to_string()],
+            text: None,
+            cw: Some("Selfie, no ec".to_string()),
+            has_poll: false,
+        };
+        assert_eq!(summarize!(note_with_file_and_cw), "Selfie, no ec 📎");
+
+        let note_with_files_only = NoteLike {
+            file_ids: vec![
+                "9s7fmcqogiq4igin".to_string(),
+                "9s7qrld5u14cey98".to_string(),
+                "9s7gebs5zgts4kca".to_string(),
+                "9s5z3e4vefqd29ee".to_string(),
+            ],
+            text: None,
+            cw: None,
+            has_poll: false,
+        };
+        assert_eq!(summarize!(note_with_files_only), "📎 (4)");
+
+        let note_all = NoteLike {
+            file_ids: vec![
+                "9s7fmcqogiq4igin".to_string(),
+                "9s7qrld5u14cey98".to_string(),
+                "9s7gebs5zgts4kca".to_string(),
+                "9s5z3e4vefqd29ee".to_string(),
+            ],
+            text: Some("Hello world!".to_string()),
+            cw: Some("Content warning".to_string()),
+            has_poll: true,
+        };
+        assert_eq!(summarize!(note_all), "Content warning 📎 (4) 📊");
+    }
+}
diff --git a/packages/backend-rs/src/service/antenna/process_new_note.rs b/packages/backend-rs/src/service/antenna/process_new_note.rs
index f4ec336681..a90ef11803 100644
--- a/packages/backend-rs/src/service/antenna/process_new_note.rs
+++ b/packages/backend-rs/src/service/antenna/process_new_note.rs
@@ -1,7 +1,7 @@
 use crate::{
     database::{cache, redis_conn, redis_key, RedisConnError},
     federation::acct::Acct,
-    misc::get_note_all_texts::all_texts,
+    misc::note::elaborate,
     model::entity::note,
     service::{
         antenna,
@@ -41,7 +41,7 @@ pub async fn update_antennas_on_new_note(
     note_author: &Acct,
     note_muted_users: &[String],
 ) -> Result<(), Error> {
-    let note_all_texts = all_texts!(note, false).await?;
+    let note_all_texts = elaborate!(note, false).await?;
 
     // TODO: do this in parallel
     for antenna in antenna::cache::get().await?.iter() {
diff --git a/packages/backend-rs/src/service/push_notification.rs b/packages/backend-rs/src/service/push_notification.rs
index 35c97f86c1..ccd83bf689 100644
--- a/packages/backend-rs/src/service/push_notification.rs
+++ b/packages/backend-rs/src/service/push_notification.rs
@@ -1,12 +1,10 @@
 use crate::{
-    config::local_server_info,
-    database::db_conn,
-    misc::get_note_summary::{get_note_summary, PartialNoteToSummarize},
-    model::entity::sw_subscription,
-    util::http_client,
+    config::local_server_info, database::db_conn, misc::note::summarize,
+    model::entity::sw_subscription, util::http_client,
 };
 use once_cell::sync::OnceCell;
 use sea_orm::prelude::*;
+use serde::Deserialize;
 use web_push::*;
 
 #[derive(thiserror::Error, Debug)]
@@ -72,8 +70,18 @@ fn compact_content(mut content: serde_json::Value) -> Result<serde_json::Value,
         ));
     }
 
-    let note_like: PartialNoteToSummarize = serde_json::from_value(note.clone())?;
-    let text = get_note_summary(note_like);
+    // TODO: get rid of this struct
+    #[derive(Deserialize)]
+    #[serde(rename_all = "camelCase")]
+    struct PartialNote {
+        file_ids: Vec<String>,
+        text: Option<String>,
+        cw: Option<String>,
+        has_poll: bool,
+    }
+
+    let note_like: PartialNote = serde_json::from_value(note.clone())?;
+    let text = summarize!(note_like);
 
     let note_object = note.as_object_mut().unwrap();
 
diff --git a/packages/backend/src/server/web/index.ts b/packages/backend/src/server/web/index.ts
index f776c19ed4..af6e237be6 100644
--- a/packages/backend/src/server/web/index.ts
+++ b/packages/backend/src/server/web/index.ts
@@ -540,7 +540,7 @@ router.get("/notes/:note", async (ctx, next) => {
 					await Users.findOneByOrFail({ id: note.userId }),
 				),
 				// TODO: Let locale changeable by instance setting
-				summary: getNoteSummary(note),
+				summary: getNoteSummary(note.fileIds, note.text, note.cw, note.hasPoll),
 			});
 
 			ctx.set("Cache-Control", "public, max-age=15");
@@ -562,19 +562,19 @@ router.get("/posts/:note", async (ctx, next) => {
 		visibility: In(["public", "home"]),
 	});
 
-	if (note) {
-		const _note = await Notes.pack(note);
+	if (note != null) {
+		const packedNote = await Notes.pack(note);
 		const profile = await UserProfiles.findOneByOrFail({ userId: note.userId });
 		const meta = await fetchMeta();
 		await ctx.render("note", {
 			...metaToPugArgs(meta),
-			note: _note,
+			note: packedNote,
 			profile,
 			avatarUrl: await Users.getAvatarUrl(
 				await Users.findOneByOrFail({ id: note.userId }),
 			),
 			// TODO: Let locale changeable by instance setting
-			summary: getNoteSummary(_note),
+			summary: getNoteSummary(note.fileIds, note.text, note.cw, note.hasPoll),
 		});
 
 		ctx.set("Cache-Control", "public, max-age=15");