Add view original functionality

This commit is contained in:
Bill Thiede 2025-04-19 12:33:11 -07:00
parent 122e949072
commit 7d9376d607
3 changed files with 57 additions and 15 deletions

View File

@ -29,7 +29,7 @@ use serde::Deserialize;
use sqlx::postgres::PgPool; use sqlx::postgres::PgPool;
use tokio::{net::TcpListener, sync::Mutex}; use tokio::{net::TcpListener, sync::Mutex};
use tower_http::trace::{DefaultMakeSpan, TraceLayer}; use tower_http::trace::{DefaultMakeSpan, TraceLayer};
use tracing::info; use tracing::{info, warn};
// Make our own error that wraps `anyhow::Error`. // Make our own error that wraps `anyhow::Error`.
struct AppError(letterbox_server::ServerError); struct AppError(letterbox_server::ServerError);
@ -142,6 +142,25 @@ async fn view_cid(
Ok(inline_attachment_response(attachment)) Ok(inline_attachment_response(attachment))
} }
async fn view_original(
State(AppState { nm, .. }): State<AppState>,
extract::Path(id): extract::Path<String>,
) -> Result<impl IntoResponse, AppError> {
info!("view_original {id}");
let mid = if id.starts_with("id:") {
id.to_string()
} else {
format!("id:{}", id)
};
let files = nm.files(&mid)?;
let Some(path) = files.first() else {
warn!("failed to find files for message {mid}");
return Ok((StatusCode::NOT_FOUND, mid).into_response());
};
let str = std::fs::read_to_string(&path)?;
Ok(str.into_response())
}
async fn graphiql() -> impl IntoResponse { async fn graphiql() -> impl IntoResponse {
response::Html( response::Html(
GraphiQLSource::build() GraphiQLSource::build()
@ -260,6 +279,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
get(download_attachment), get(download_attachment),
) )
.route("/view/attachment/{id}/{idx}/{*rest}", get(view_attachment)) .route("/view/attachment/{id}/{idx}/{*rest}", get(view_attachment))
.route("/original/{id}", get(view_original))
.route("/cid/{id}/{cid}", get(view_cid)) .route("/cid/{id}/{cid}", get(view_cid))
.route("/ws", any(start_ws)) .route("/ws", any(start_ws))
.route_service("/graphql/ws", GraphQLSubscription::new(schema.clone())) .route_service("/graphql/ws", GraphQLSubscription::new(schema.clone()))

View File

@ -20,6 +20,13 @@ pub enum WebsocketMessage {
pub mod urls { pub mod urls {
pub const MOUNT_POINT: &'static str = "/api"; pub const MOUNT_POINT: &'static str = "/api";
pub fn view_original(host: Option<&str>, id: &str) -> String {
if let Some(host) = host {
format!("//{host}/api/original/{id}")
} else {
format!("/api/original/{id}")
}
}
pub fn cid_prefix(host: Option<&str>, cid: &str) -> String { pub fn cid_prefix(host: Option<&str>, cid: &str) -> String {
if let Some(host) = host { if let Some(host) = host {
format!("//{host}/api/cid/{cid}/") format!("//{host}/api/cid/{cid}/")

View File

@ -694,6 +694,8 @@ fn render_open_header(msg: &ShowThreadQueryThreadOnEmailThreadMessages) -> Node<
.collect(); .collect();
let show_x_original_to = !*to_xinu.borrow() && msg.x_original_to.is_some(); let show_x_original_to = !*to_xinu.borrow() && msg.x_original_to.is_some();
let show_delivered_to = !*to_xinu.borrow() && !show_x_original_to && msg.delivered_to.is_some(); let show_delivered_to = !*to_xinu.borrow() && !show_x_original_to && msg.delivered_to.is_some();
let host = seed::window().location().host().expect("couldn't get host");
let href = letterbox_shared::urls::view_original(Some(&host), &msg.id);
div![ div![
C!["flex", "p-4", "bg-neutral-800"], C!["flex", "p-4", "bg-neutral-800"],
div![avatar], div![avatar],
@ -775,20 +777,33 @@ fn render_open_header(msg: &ShowThreadQueryThreadOnEmailThreadMessages) -> Node<
C!["text-right"], C!["text-right"],
msg.timestamp msg.timestamp
.map(|ts| div![C!["text-xs", "text-nowrap"], human_age(ts)]), .map(|ts| div![C!["text-xs", "text-nowrap"], human_age(ts)]),
i![C![ div![
"mx-4", C!["p-2"],
"read-status", i![C![
"far", "mx-4",
if is_unread { "read-status",
"fa-envelope" "far",
} else { if is_unread {
"fa-envelope-open" "fa-envelope"
}, } else {
]], "fa-envelope-open"
ev(Ev::Click, move |e| { },
e.stop_propagation(); ]],
Msg::SetUnread(id, !is_unread) ev(Ev::Click, move |e| {
}), e.stop_propagation();
Msg::SetUnread(id, !is_unread)
}),
],
div![
C!["text-xs"],
span![a![
attrs! {
At::Href=>href,
At::Target=>"_blank",
},
"View original"
]]
]
] ]
] ]
} }