openlark-docs 0.17.0

飞书开放平台云文档服务模块 - 文档、表格、知识库API (202 APIs, 100% 覆盖,不含旧版本)
Documentation
//! 查询云文档事件订阅状态
//!
//! 查询文件的订阅状态。
//!
//! docPath: https://open.feishu.cn/document/docs/drive-v1/event/get_subscribe

use openlark_core::{
    SDKResult,
    api::{ApiRequest, ApiResponseTrait, ResponseFormat},
    config::Config,
    http::Transport,
    validate_required,
};
use serde::{Deserialize, Serialize};

use crate::common::{api_endpoints::DriveApi, api_utils::*};

/// 获取文件的订阅状态请求
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetSubscribeRequest {
    #[serde(skip)]
    config: Config,
    /// 文件token
    pub file_token: String,
    /// 文件类型
    pub file_type: String,
    /// 订阅类型
    pub event_type: Option<String>,
}

impl GetSubscribeRequest {
    /// 创建获取文件订阅状态请求
    ///
    /// # 参数
    /// * `config` - 配置
    /// * `file_token` - 文件token
    /// * `file_type` - 文件类型(doc/docx/sheet/bitable/file/folder/slides)
    pub fn new(
        config: Config,
        file_token: impl Into<String>,
        file_type: impl Into<String>,
    ) -> Self {
        Self {
            config,
            file_token: file_token.into(),
            file_type: file_type.into(),
            event_type: None,
        }
    }

    /// 设置订阅类型
    pub fn event_type(mut self, event_type: impl Into<String>) -> Self {
        self.event_type = Some(event_type.into());
        self
    }

    /// 执行请求。
    pub async fn execute(self) -> SDKResult<GetSubscribeResponse> {
        self.execute_with_options(openlark_core::req_option::RequestOption::default())
            .await
    }

    /// 使用指定请求选项执行请求。
    pub async fn execute_with_options(
        self,
        option: openlark_core::req_option::RequestOption,
    ) -> SDKResult<GetSubscribeResponse> {
        // ===== 参数校验 =====
        validate_required!(self.file_token, "file_token 不能为空");
        validate_required!(self.file_type, "file_type 不能为空");
        match self.file_type.as_str() {
            "doc" | "docx" | "sheet" | "bitable" | "file" | "folder" | "slides" => {}
            _ => {
                return Err(openlark_core::error::validation_error(
                    "file_type",
                    "file_type 仅支持 doc/docx/sheet/bitable/file/folder/slides",
                ));
            }
        }

        // 文档约束:仅当 file_type 为 folder 时,允许传 event_type,且必须为 file.created_in_folder_v1
        if self.file_type == "folder" {
            match self.event_type.as_deref() {
                Some("file.created_in_folder_v1") => {}
                Some(_) => {
                    return Err(openlark_core::error::validation_error(
                        "event_type",
                        "当 file_type=folder 时,event_type 必须为 file.created_in_folder_v1",
                    ));
                }
                None => {
                    return Err(openlark_core::error::validation_error(
                        "event_type",
                        "当 file_type=folder 时,event_type 不能为空(必须为 file.created_in_folder_v1)",
                    ));
                }
            }
        } else if self.event_type.is_some() {
            return Err(openlark_core::error::validation_error(
                "event_type",
                "当 file_type 不为 folder 时,请勿传入 event_type",
            ));
        }

        // ===== 构建请求 =====
        let api_endpoint = DriveApi::GetFileSubscribe(self.file_token.clone());
        let mut request = ApiRequest::<GetSubscribeResponse>::get(&api_endpoint.to_url());

        request = request.query("file_type", &self.file_type);
        if let Some(et) = &self.event_type {
            request = request.query("event_type", et);
        }

        // ===== 发送请求 =====
        let response = Transport::request(request, &self.config, Some(option)).await?;
        extract_response_data(response, "订阅文件")
    }
}

/// 获取文件订阅状态响应
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetSubscribeResponse {
    /// 是否已订阅
    pub is_subscribe: bool,
}

impl ApiResponseTrait for GetSubscribeResponse {
    fn data_format() -> ResponseFormat {
        ResponseFormat::Data
    }
}

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

    /// 测试构建器模式
    #[test]
    fn test_get_subscribe_request_builder() {
        let config = Config::default();
        let request = GetSubscribeRequest::new(config, "file_token", "docx");

        assert_eq!(request.file_token, "file_token");
        assert_eq!(request.file_type, "docx");
        assert!(request.event_type.is_none());
    }

    /// 测试响应trait实现
    #[test]
    fn test_response_trait() {
        assert_eq!(GetSubscribeResponse::data_format(), ResponseFormat::Data);
    }

    /// 测试设置event_type
    #[test]
    fn test_get_subscribe_with_event_type() {
        let config = Config::default();
        let request = GetSubscribeRequest::new(config, "folder_token", "folder")
            .event_type("file.created_in_folder_v1");

        assert_eq!(
            request.event_type,
            Some("file.created_in_folder_v1".to_string())
        );
    }

    /// 测试响应数据结构
    #[test]
    fn test_subscribe_response_data() {
        let response = GetSubscribeResponse { is_subscribe: true };

        assert!(response.is_subscribe);
    }

    /// 测试未订阅状态
    #[test]
    fn test_not_subscribed_status() {
        let response = GetSubscribeResponse {
            is_subscribe: false,
        };

        assert!(!response.is_subscribe);
    }

    /// 测试folder类型查询
    #[test]
    fn test_get_subscribe_folder_type() {
        let config = Config::default();
        let request = GetSubscribeRequest::new(config, "folder_token", "folder");

        assert_eq!(request.file_type, "folder");
    }
}