zulip-api 0.0.8

Client library for interacting with the Zulip API
Documentation
use serde::{Deserialize, Serialize};

use crate::{field_access, impl_default, impl_display};

/// Represents a message draft.
///
/// Modified from `openapi-generator-cli` output:
///
/// ```shell,no_build,no_run
/// $ openapi-generator-cli generate -g rust -i ./zerver/openapi/zulip.yaml -o zulip-openapi --skip-validate-spec
/// ```
///
/// ```text
/// /*
/// * Zulip REST API
/// *
/// * Powerful open source group chat
/// *
/// * The version of the OpenAPI document: 1.0.0
/// *
/// * Generated by: https://openapi-generator.tech
/// */
/// ```
///
/// See [zerver/openapi/zulip.yaml](https://github.com/zulip/zulip/blob/main/zerver/openapi/zulip.yaml) for the original OpenAPI configuration.
///
/// Configuration slightly modified to work with the Rust generator of [`openapi-generator-cli`](https://openapi-generator.tech).
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Draft {
    #[serde(skip_serializing_if = "Option::is_none")]
    id: Option<i64>,
    #[serde(rename = "type")]
    draft_type: DraftType,
    to: Vec<u64>,
    topic: String,
    content: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    timestamp: Option<u64>,
}

impl Draft {
    /// Creates a new [Draft].
    pub const fn new() -> Self {
        Self {
            id: None,
            draft_type: DraftType::new(),
            to: Vec::new(),
            topic: String::new(),
            content: String::new(),
            timestamp: None,
        }
    }
}

field_access! {
    Draft {
        /// The unique ID of the draft.
        ///
        /// It will only used whenever the drafts are fetched.
        /// This field should not be specified when the draft is being created or edited.
        id: option { i64 },
        /// A Unix timestamp (seconds only) representing when the draft was last edited.
        ///
        /// When creating a draft, this key need not be present and it will be filled in automatically by the server.
        timestamp: option { u64 },
    }
}

field_access! {
    Draft {
        /// The type of the draft.
        ///
        /// Either unaddressed (empty string), `\"stream\"`, or `\"private\"` (for one-on-one and group direct messages).
        draft_type: DraftType,
    }
}

field_access! {
    Draft {
        /// An array of the tentative target audience IDs.
        ///
        /// For channel messages, this should contain exactly 1 ID, the ID of the target channel.
        /// For direct messages, this should be an array of target user IDs.
        /// For unaddressed drafts, this is ignored, and clients should send an empty array.
        to: cow { [u64] },
        /// For channel message drafts, the tentative topic name.
        ///
        /// For direct or unaddressed messages, this will be ignored and should ideally be the empty string.
        /// Should not contain null bytes.
        topic: cow { str },
        /// The body of the draft.
        ///
        /// Should not contain null bytes.
        content: cow { str },
    }
}

impl_default!(Draft);
impl_display!(Draft);

/// Represents the [Draft] type.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum DraftType {
    #[serde(rename = "")]
    Unaddressed,
    Stream,
    Private,
}

impl DraftType {
    /// Creates a new [DraftType].
    pub const fn new() -> Self {
        Self::Unaddressed
    }
}

impl_default!(DraftType);
impl_display!(DraftType);

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_draft() {
        let id = 1;
        let draft_type = DraftType::new();
        let to = [2u64];
        let topic = "test topic";
        let content = "test content";
        let timestamp = 3;

        let draft = Draft::new()
            .with_id(id)
            .with_draft_type(draft_type)
            .with_to(to.as_ref())
            .with_topic(topic)
            .with_content(content)
            .with_timestamp(timestamp);
        let draft_json = draft.to_string();

        assert_eq!(serde_json::to_string(&draft).unwrap(), draft_json);
        assert_eq!(serde_json::from_str::<Draft>(&draft_json).unwrap(), draft);

        assert_eq!(draft.id(), Some(id));
        assert_eq!(draft.draft_type(), draft_type);
        assert_eq!(draft.to(), to.as_ref());
        assert_eq!(draft.topic(), topic);
        assert_eq!(draft.content(), content);
        assert_eq!(draft.timestamp(), Some(timestamp));
    }
}