Skip to content

Commit a733c91

Browse files
properly fetch markdown content when editing posts
1 parent 83a7a25 commit a733c91

5 files changed

Lines changed: 105 additions & 42 deletions

File tree

src/commands.rs

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -411,8 +411,7 @@ pub fn handle_ui_command(cmd: UiCommand, ctx: &mut UiCommandContext<'_>) {
411411
}
412412
}
413413
UiCommand::EditPost => {
414-
let (status, max_post_chars, enter_to_send) =
415-
(get_selected_status(state).cloned(), state.max_post_chars, state.config.enter_to_send);
414+
let status = get_selected_status(state).cloned();
416415
let Some(status) = status else {
417416
live_region.announce("No post selected");
418417
return;
@@ -427,46 +426,8 @@ pub fn handle_ui_command(cmd: UiCommand, ctx: &mut UiCommandContext<'_>) {
427426
live_region.announce("Cannot verify ownership");
428427
return;
429428
}
430-
let Some((edit, config)) =
431-
dialogs::prompt_for_edit(frame, target, max_post_chars, &state.poll_limits, enter_to_send)
432-
else {
433-
return;
434-
};
435429
if let Some(handle) = &state.network_handle {
436-
state.pending_post = Some(crate::PendingPost {
437-
config,
438-
operation: crate::PostOperation::Edit { status_id: target.id.clone() },
439-
last_result: edit.clone(),
440-
});
441-
let media = edit
442-
.media
443-
.into_iter()
444-
.map(|item| {
445-
if item.is_existing {
446-
network::EditMedia::Existing(item.path)
447-
} else {
448-
network::EditMedia::New(network::MediaUpload {
449-
path: item.path,
450-
description: item.description,
451-
})
452-
}
453-
})
454-
.collect();
455-
456-
handle.send(NetworkCommand::EditStatus {
457-
status_id: target.id.clone(),
458-
content: edit.content,
459-
sensitive: edit.sensitive,
460-
spoiler_text: edit.spoiler_text,
461-
language: edit.language,
462-
media,
463-
poll: edit.poll.map(|poll| network::PollData {
464-
options: poll.options,
465-
expires_in: poll.expires_in,
466-
multiple: poll.multiple,
467-
hide_totals: poll.hide_totals,
468-
}),
469-
});
430+
handle.send(NetworkCommand::FetchStatusSource { status: Box::new(target.clone()) });
470431
} else {
471432
live_region.announce("Network not available");
472433
}
@@ -2777,3 +2738,51 @@ fn close_timeline(
27772738
}
27782739
update_window_title(state, frame);
27792740
}
2741+
2742+
pub fn run_edit_post_dialog(
2743+
frame: &Frame,
2744+
state: &mut AppState,
2745+
target: &crate::mastodon::Status,
2746+
source_text: Option<&str>,
2747+
) {
2748+
let max_post_chars = state.max_post_chars;
2749+
let enter_to_send = state.config.enter_to_send;
2750+
let Some((edit, config)) =
2751+
dialogs::prompt_for_edit(frame, target, source_text, max_post_chars, &state.poll_limits, enter_to_send)
2752+
else {
2753+
return;
2754+
};
2755+
if let Some(handle) = &state.network_handle {
2756+
state.pending_post = Some(crate::PendingPost {
2757+
config,
2758+
operation: crate::PostOperation::Edit { status_id: target.id.clone() },
2759+
last_result: edit.clone(),
2760+
});
2761+
let media = edit
2762+
.media
2763+
.into_iter()
2764+
.map(|item| {
2765+
if item.is_existing {
2766+
network::EditMedia::Existing(item.path)
2767+
} else {
2768+
network::EditMedia::New(network::MediaUpload { path: item.path, description: item.description })
2769+
}
2770+
})
2771+
.collect();
2772+
2773+
handle.send(NetworkCommand::EditStatus {
2774+
status_id: target.id.clone(),
2775+
content: edit.content,
2776+
sensitive: edit.sensitive,
2777+
spoiler_text: edit.spoiler_text,
2778+
language: edit.language,
2779+
media,
2780+
poll: edit.poll.map(|poll| network::PollData {
2781+
options: poll.options,
2782+
expires_in: poll.expires_in,
2783+
multiple: poll.multiple,
2784+
hide_totals: poll.hide_totals,
2785+
}),
2786+
});
2787+
}
2788+
}

src/mastodon.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ pub struct Status {
107107
pub filtered: Vec<FilterResult>,
108108
}
109109

110+
#[derive(Debug, Clone, Deserialize)]
111+
#[allow(dead_code)]
112+
pub struct StatusSource {
113+
pub id: String,
114+
#[serde(default)]
115+
pub text: String,
116+
#[serde(default)]
117+
pub spoiler_text: String,
118+
}
119+
110120
#[derive(Debug, Clone, Deserialize)]
111121
#[allow(dead_code)]
112122
pub struct FilterResult {
@@ -1963,6 +1973,20 @@ impl MastodonClient {
19631973
Ok(account)
19641974
}
19651975

1976+
pub fn fetch_status_source(&self, access_token: &str, status_id: &str) -> Result<StatusSource> {
1977+
let url = self.base_url.join(&format!("api/v1/statuses/{status_id}/source"))?;
1978+
let response = self
1979+
.http
1980+
.get(url)
1981+
.bearer_auth(access_token)
1982+
.send()
1983+
.context("Failed to fetch status source")?
1984+
.error_for_status()
1985+
.context("Instance rejected request")?;
1986+
let source: StatusSource = response.json().context("Invalid source response")?;
1987+
Ok(source)
1988+
}
1989+
19661990
pub fn edit_status(
19671991
&self,
19681992
access_token: &str,

src/network.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ pub enum NetworkCommand {
7575
timeline_type: TimelineType,
7676
status_id: String,
7777
},
78+
FetchStatusSource {
79+
status: Box<Status>,
80+
},
7881
ResolveStatusForThread {
7982
url: String,
8083
},
@@ -320,6 +323,10 @@ pub enum NetworkResponse {
320323
StatusResolvedForQuote {
321324
result: Result<Status>,
322325
},
326+
StatusSourceFetched {
327+
status: Box<Status>,
328+
result: Result<crate::mastodon::StatusSource>,
329+
},
323330
AccountLookupResult {
324331
handle: String,
325332
result: Result<Account>,
@@ -755,6 +762,10 @@ fn network_loop(
755762
NetworkResponse::TimelineLoaded { timeline_type, result, max_id: None },
756763
);
757764
}
765+
Ok(NetworkCommand::FetchStatusSource { status }) => {
766+
let result = client.fetch_status_source(access_token, &status.id);
767+
send_response(responses, ui_waker, NetworkResponse::StatusSourceFetched { status, result });
768+
}
758769
Ok(NetworkCommand::ResolveStatusForThread { url }) => {
759770
let result = client
760771
.search(access_token, &url, SearchType::Statuses, Some(1), None)

src/responses.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,24 @@ pub fn process_network_responses(ctx: &mut NetworkResponseContext<'_>) {
485485
NetworkResponse::StatusResolvedForQuote { result: Ok(focus) } => {
486486
ui_tx.send(crate::commands::UiCommand::PromptForQuote(Box::new(focus))).unwrap();
487487
}
488+
NetworkResponse::StatusSourceFetched { mut status, result } => {
489+
let source_text = match result {
490+
Ok(source) => {
491+
if !source.spoiler_text.is_empty() {
492+
status.spoiler_text = source.spoiler_text;
493+
}
494+
Some(source.text)
495+
}
496+
Err(err) => {
497+
live_region.announce(&format!(
498+
"Could not fetch source text, editing with stripped HTML: {}",
499+
summarize_api_error(&err)
500+
));
501+
None
502+
}
503+
};
504+
crate::commands::run_edit_post_dialog(frame, state, &status, source_text.as_deref());
505+
}
488506
NetworkResponse::StatusResolvedForQuote { result: Err(err) } => {
489507
live_region.announce(&format!("Failed to resolve post for quote: {}", summarize_api_error(&err)));
490508
}

src/ui/dialogs/compose.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,7 @@ pub fn prompt_for_reply(
12221222
pub fn prompt_for_edit(
12231223
frame: &Frame,
12241224
status: &Status,
1225+
source_text: Option<&str>,
12251226
max_chars: Option<usize>,
12261227
poll_limits: &PollLimits,
12271228
enter_to_send: bool,
@@ -1253,7 +1254,7 @@ pub fn prompt_for_edit(
12531254
ComposeDialogConfig {
12541255
title_prefix: "Edit Post".to_string(),
12551256
ok_label: "Save".to_string(),
1256-
initial_content: status.display_text(),
1257+
initial_content: source_text.map(ToOwned::to_owned).unwrap_or_else(|| status.display_text()),
12571258
initial_cw,
12581259
initial_sensitive: status.sensitive,
12591260
initial_language: status.language.clone(),

0 commit comments

Comments
 (0)