Skip to main content

hey_sdk/services/
journal.rs

1//! The journal entry a day holds, read and written as its content.
2//!
3//! A day has at most one entry. HEY answers it as a calendar recording carrying the full
4//! text (`content`) and the rich-text HTML (`content_html`); a day with no entry answers
5//! 204 and no body, which reads here as `None`.
6
7use crate::error::Error;
8use crate::generated::routes;
9use crate::generated::types::{JournalEntryPayload, Recording, UpdateJournalEntryRequestContent};
10use crate::operation::Operation;
11
12pub use crate::generated::services::journal::*;
13
14impl Journal<'_> {
15    /// The rich-text HTML of the day's journal entry, falling back to its plain text, or
16    /// `None` when the day has no entry. `day` is `YYYY-MM-DD`.
17    ///
18    /// The fallback covers an empty `content_html` as well as a missing one: HEY serves the
19    /// key blank on an entry it has no rendered body for, and blank is not the entry.
20    pub async fn get_content(&self, day: &str) -> Result<Option<String>, Error> {
21        let mut operation = self.client().operation(&routes::GET_JOURNAL_ENTRY, &[&day]);
22        operation.operation_name("GetJournalContent");
23        let entry = self.recording(operation).await?;
24        Ok(entry.and_then(|entry| {
25            entry
26                .content_html
27                .filter(|html| !html.is_empty())
28                .or(entry.content)
29        }))
30    }
31
32    /// The day's journal entry, or `None` when it has none. The generated
33    /// [`Journal::get_entry`] reads the same route but takes the empty answer for a day
34    /// without an entry as a body it could not decode.
35    pub async fn entry(&self, day: &str) -> Result<Option<Recording>, Error> {
36        let operation = self.client().operation(&routes::GET_JOURNAL_ENTRY, &[&day]);
37        self.recording(operation).await
38    }
39
40    /// Writes the day's journal entry, creating it if needed, and answers it as a
41    /// recording. Empty content removes the entry, which HEY answers with nothing, so the
42    /// result is `None`.
43    pub async fn update_content(
44        &self,
45        day: &str,
46        content: &str,
47    ) -> Result<Option<Recording>, Error> {
48        let body = UpdateJournalEntryRequestContent {
49            calendar_journal_entry: JournalEntryPayload {
50                content: content.to_string(),
51            },
52        };
53        let mut operation = self
54            .client()
55            .operation(&routes::UPDATE_JOURNAL_ENTRY, &[&day]);
56        operation.json(&body)?;
57        self.recording(operation).await
58    }
59
60    async fn recording(&self, operation: Operation) -> Result<Option<Recording>, Error> {
61        let response = self.client().execute(operation).await?;
62        if response.body.is_empty() {
63            Ok(None)
64        } else {
65            response.json().map(Some)
66        }
67    }
68}