hey_sdk/services/topics.rs
1//! Trashing a topic, including the confirmation HEY asks for before it trashes a shared
2//! one.
3//!
4//! [`Topics::get_entries`] is paged by geared pagination, so its `page` is a cursor out of
5//! the previous answer's `Link` header rather than an offset: a number is ignored and
6//! answered with the first page. [`crate::Page::next_page`] carries the cursor to pass back.
7
8use crate::client::Response;
9use crate::error::Error;
10use crate::generated::routes;
11use crate::generated::types::MoveTopicRequestContent;
12
13pub use crate::generated::services::topics::*;
14
15impl Topics<'_> {
16 /// Moves a topic to a box, by the box's id. The generated [`Topics::move_topic`] takes
17 /// the request body; this takes the one thing it carries.
18 pub async fn move_to_box(&self, topic_id: i64, box_id: i64) -> Result<(), Error> {
19 self.move_topic(topic_id, &MoveTopicRequestContent { box_id })
20 .await
21 }
22
23 /// Trashes a topic.
24 ///
25 /// HEY will not trash a shared topic without being asked twice: it answers the removal
26 /// confirmation page instead, which comes back here as a usage error rather than as a
27 /// trashing that quietly did nothing. Confirming trashes the topic and removes your
28 /// access to it.
29 ///
30 /// The generated [`Topics::trash`] sends the same request from its parts, and follows
31 /// that redirect rather than reading it.
32 pub async fn trash_topic(&self, topic_id: i64, confirm_destroy: bool) -> Result<(), Error> {
33 let mut operation = self.client().operation(&routes::TRASH_TOPIC, &[&topic_id]);
34 operation.resource_id(topic_id);
35 // An empty confirm_destroy reads as truthy on the server and skips the
36 // confirmation, so it is sent only when it is asked for.
37 if confirm_destroy {
38 operation.query("confirm_destroy", 1);
39 }
40 operation.capture_redirects();
41
42 let response = self.client().execute(operation).await?;
43 if awaiting_confirmation(&response, topic_id) {
44 Err(Error::usage_with_hint(
45 format!("topic {topic_id} is shared; HEY wants confirmation before trashing it"),
46 "Call trash_topic with confirm_destroy = true to trash it and remove your access",
47 ))
48 } else {
49 Ok(())
50 }
51 }
52}
53
54/// Whether HEY answered by sending the caller to the topic's removal confirmation page,
55/// which is how it says it will not trash a shared topic unasked. Any other redirect is HEY
56/// sending the caller back to where the topic was, with the trashing done.
57fn awaiting_confirmation(response: &Response, topic_id: i64) -> bool {
58 match response.header("location") {
59 Some(location) => response
60 .url
61 .join(location)
62 .is_ok_and(|target| target.path() == format!("/topics/{topic_id}/removal/new")),
63 None => false,
64 }
65}