fix local markdown attachment regressions

This commit is contained in:
lix-2026
2026-05-29 11:13:05 +08:00
parent 1109e3c0d8
commit cbe789e034
63 changed files with 3249 additions and 1502 deletions
+38 -53
View File
@@ -25,17 +25,17 @@ use crate::workspace_shell::{
use axum::body::Body;
use axum::extract::ws::{Message as AxumWsMessage, WebSocket, WebSocketUpgrade};
use axum::extract::{Extension, Query, State};
use axum::http::{HeaderName, HeaderValue, Request, StatusCode, Uri, header};
use axum::http::{header, HeaderName, HeaderValue, Request, StatusCode, Uri};
use axum::response::{Html, IntoResponse, Response};
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
use control_plane::{
AppendAuditInput, AuthenticatePasswordInput, CreatePasswordIdentityInput,
NavigationRecentRecord, UpsertNavigationRecentInput, UpsertUserInput, session_token_hash,
session_token_hash, AppendAuditInput, AuthenticatePasswordInput, CreatePasswordIdentityInput,
NavigationRecentRecord, UpsertNavigationRecentInput, UpsertUserInput,
};
use futures_util::{SinkExt, StreamExt};
use leptos::prelude::InnerHtmlAttribute;
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use serde_json::{json, Value};
use std::collections::BTreeMap;
use std::time::Duration;
use tokio_tungstenite::tungstenite::Message as TungsteniteMessage;
@@ -560,6 +560,7 @@ pub async fn root_entry(
active_page_title={active_page_title.clone()}
navigation_html={navigation_html.clone().unwrap_or_default()}
show_admin_access_policy={show_admin_access_policy}
enable_tree_live={active_source_kind.as_deref() == Some("local_folder")}
/>
})
};
@@ -622,7 +623,7 @@ pub async fn root_entry(
workspace_sidebar_html={workspace_sidebar_html.clone()}
page_subtree_json={page_subtree_json}
show_admin_access_policy={show_admin_access_policy}
enable_tree_live={active_source_kind.as_deref() != Some("local_folder")}
enable_tree_live={true}
/>
});
let body_extra = format!(
@@ -645,7 +646,7 @@ pub async fn root_entry(
let editor_runtime_preload_links = if body_extra.contains("__MNOTE_EDITOR_BOOTSTRAP__") {
render_editor_runtime_preload_links()
} else {
""
String::new()
};
let mut response = Html(format!(
r#"<!doctype html>
@@ -2448,9 +2449,9 @@ fn normalize_legacy_referer(value: &HeaderValue, upstream_origin: &str) -> Strin
#[cfg(test)]
mod tests {
use crate::app::{AppConfig, AppState, build_app};
use axum::body::{Body, to_bytes};
use axum::http::{HeaderMap, HeaderValue, Request, StatusCode, header};
use crate::app::{build_app, AppConfig, AppState};
use axum::body::{to_bytes, Body};
use axum::http::{header, HeaderMap, HeaderValue, Request, StatusCode};
use axum::response::{Html, IntoResponse};
use axum::routing::{get, post};
use control_plane::{UpsertNavigationRecentInput, UpsertUserInput};
@@ -3019,7 +3020,7 @@ mod tests {
#[tokio::test]
async fn root_entry_uses_sqlite_session_display_name_for_workspace_label() {
use control_plane::{CreateSessionInput, UpsertUserInput, session_token_hash};
use control_plane::{session_token_hash, CreateSessionInput, UpsertUserInput};
let app_state = AppState::new(AppConfig {
service_name: "mnote-web".into(),
@@ -3486,9 +3487,7 @@ mod tests {
.expect("body");
let html = String::from_utf8(body.to_vec()).expect("utf8");
assert!(html.contains(r#"data-node-id="local-dir:design~2F05-editor-mainline""#));
assert!(
html.contains(r#"data-node-id="local-md:design~2F05-editor-mainline~2FTarget.md""#)
);
assert!(html.contains(r#"data-node-id="local-md:design~2F05-editor-mainline~2FTarget.md""#));
assert!(
!html.contains(r#"data-node-id="local-md:Home.md""#),
"星标 scoped folder 入口的 PageTree 不应回退到 workspace root 页面树"
@@ -3672,14 +3671,12 @@ mod tests {
.and_then(|value| value.to_str().ok()),
Some("mnote-web")
);
assert!(
response
.headers()
.get("content-type")
.and_then(|value| value.to_str().ok())
.unwrap_or_default()
.contains("text/html")
);
assert!(response
.headers()
.get("content-type")
.and_then(|value| value.to_str().ok())
.unwrap_or_default()
.contains("text/html"));
}
#[tokio::test]
@@ -3734,16 +3731,12 @@ mod tests {
.map(|value| value.to_str().unwrap_or_default())
.collect::<Vec<_>>();
assert!(values.iter().any(|value| value.contains("mnote_session=")));
assert!(
values
.iter()
.any(|value| value.contains("mnote_actor_id=new-user"))
);
assert!(
values
.iter()
.any(|value| value.contains("mnote_actor_type=user"))
);
assert!(values
.iter()
.any(|value| value.contains("mnote_actor_id=new-user")));
assert!(values
.iter()
.any(|value| value.contains("mnote_actor_type=user")));
let body = to_bytes(response.into_body(), usize::MAX)
.await
.expect("body");
@@ -3822,12 +3815,10 @@ mod tests {
.expect("body");
let payload: serde_json::Value = serde_json::from_slice(&body).expect("json");
assert_eq!(payload["code"], "auth_signup_email_required");
assert!(
payload["message"]
.as_str()
.unwrap_or_default()
.contains("注册账号时请填写邮箱")
);
assert!(payload["message"]
.as_str()
.unwrap_or_default()
.contains("注册账号时请填写邮箱"));
}
#[tokio::test]
@@ -3851,11 +3842,9 @@ mod tests {
.iter()
.map(|value| value.to_str().unwrap_or_default())
.collect::<Vec<_>>();
assert!(
values
.iter()
.any(|value| value.contains("mnote_session=") && value.contains("Max-Age=0"))
);
assert!(values
.iter()
.any(|value| value.contains("mnote_session=") && value.contains("Max-Age=0")));
}
#[tokio::test]
@@ -3961,16 +3950,12 @@ mod tests {
.iter()
.map(|value| value.to_str().unwrap_or_default())
.collect::<Vec<_>>();
assert!(
!values
.iter()
.any(|value| value.contains("__convexAuthJWT="))
);
assert!(
!values
.iter()
.any(|value| value.contains("__convexAuthRefreshToken="))
);
assert!(!values
.iter()
.any(|value| value.contains("__convexAuthJWT=")));
assert!(!values
.iter()
.any(|value| value.contains("__convexAuthRefreshToken=")));
assert!(response.headers().get("x-mnote-legacy-upstream").is_none());
}