Skip to main content

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}