open_lark/service/cloud_docs/assistant/v1/subscription/
mod.rs

1use crate::core::{config::Config, req_option::RequestOption, SDKResult};
2
3pub use create::{
4    create_subscription, CreateSubscriptionRequest, CreateSubscriptionResponse, SubscriptionConfig,
5    SubscriptionPriority,
6};
7pub use get::{
8    get_subscription, FileType, GetSubscriptionRequest, GetSubscriptionResponse,
9    SubscriptionDetail, SubscriptionStatus,
10};
11pub use patch::{patch_subscription, PatchSubscriptionRequest, PatchSubscriptionResponse};
12
13pub mod create;
14pub mod get;
15pub mod patch;
16
17/// 订阅服务
18pub struct SubscriptionService {
19    config: Config,
20}
21
22impl SubscriptionService {
23    pub fn new(config: Config) -> Self {
24        Self { config }
25    }
26
27    /// 获取订阅状态
28    pub async fn get(
29        &self,
30        request: GetSubscriptionRequest,
31        option: Option<RequestOption>,
32    ) -> SDKResult<GetSubscriptionResponse> {
33        let result = get_subscription(request, &self.config, option).await?;
34        result.data.ok_or_else(|| {
35            crate::core::error::LarkAPIError::IllegalParamError(
36                "Response data is missing".to_string(),
37            )
38        })
39    }
40
41    /// 创建订阅
42    pub async fn create(
43        &self,
44        request: CreateSubscriptionRequest,
45        option: Option<RequestOption>,
46    ) -> SDKResult<CreateSubscriptionResponse> {
47        let result = create_subscription(request, &self.config, option).await?;
48        result.data.ok_or_else(|| {
49            crate::core::error::LarkAPIError::IllegalParamError(
50                "Response data is missing".to_string(),
51            )
52        })
53    }
54
55    /// 更新订阅状态
56    pub async fn patch(
57        &self,
58        request: PatchSubscriptionRequest,
59        option: Option<RequestOption>,
60    ) -> SDKResult<PatchSubscriptionResponse> {
61        let result = patch_subscription(request, &self.config, option).await?;
62        result.data.ok_or_else(|| {
63            crate::core::error::LarkAPIError::IllegalParamError(
64                "Response data is missing".to_string(),
65            )
66        })
67    }
68
69    /// 快速订阅文档(基础配置)
70    pub async fn quick_subscribe_doc(
71        &self,
72        file_token: impl ToString,
73        option: Option<RequestOption>,
74    ) -> SDKResult<CreateSubscriptionResponse> {
75        let request = CreateSubscriptionRequest::builder()
76            .file_token(file_token)
77            .as_doc()
78            .basic_subscription()
79            .build();
80
81        self.create(request, option).await
82    }
83
84    /// 快速订阅多维表格(高级配置)
85    pub async fn quick_subscribe_bitable(
86        &self,
87        file_token: impl ToString,
88        option: Option<RequestOption>,
89    ) -> SDKResult<CreateSubscriptionResponse> {
90        let request = CreateSubscriptionRequest::builder()
91            .file_token(file_token)
92            .as_bitable()
93            .premium_subscription()
94            .build();
95
96        self.create(request, option).await
97    }
98
99    /// 快速订阅表格(基础配置)
100    pub async fn quick_subscribe_sheet(
101        &self,
102        file_token: impl ToString,
103        option: Option<RequestOption>,
104    ) -> SDKResult<CreateSubscriptionResponse> {
105        let request = CreateSubscriptionRequest::builder()
106            .file_token(file_token)
107            .as_sheet()
108            .basic_subscription()
109            .build();
110
111        self.create(request, option).await
112    }
113
114    /// 快速订阅Wiki(基础配置)
115    pub async fn quick_subscribe_wiki(
116        &self,
117        file_token: impl ToString,
118        option: Option<RequestOption>,
119    ) -> SDKResult<CreateSubscriptionResponse> {
120        let request = CreateSubscriptionRequest::builder()
121            .file_token(file_token)
122            .as_wiki()
123            .basic_subscription()
124            .build();
125
126        self.create(request, option).await
127    }
128
129    /// 激活订阅
130    pub async fn activate(
131        &self,
132        file_token: impl ToString,
133        file_type: FileType,
134        option: Option<RequestOption>,
135    ) -> SDKResult<PatchSubscriptionResponse> {
136        let request = PatchSubscriptionRequest::builder()
137            .file_token(file_token)
138            .file_type(file_type)
139            .activate()
140            .build();
141
142        self.patch(request, option).await
143    }
144
145    /// 暂停订阅
146    pub async fn pause(
147        &self,
148        file_token: impl ToString,
149        file_type: FileType,
150        option: Option<RequestOption>,
151    ) -> SDKResult<PatchSubscriptionResponse> {
152        let request = PatchSubscriptionRequest::builder()
153            .file_token(file_token)
154            .file_type(file_type)
155            .pause()
156            .build();
157
158        self.patch(request, option).await
159    }
160
161    /// 取消订阅
162    pub async fn cancel(
163        &self,
164        file_token: impl ToString,
165        file_type: FileType,
166        option: Option<RequestOption>,
167    ) -> SDKResult<PatchSubscriptionResponse> {
168        let request = PatchSubscriptionRequest::builder()
169            .file_token(file_token)
170            .file_type(file_type)
171            .cancel()
172            .build();
173
174        self.patch(request, option).await
175    }
176
177    /// 快速激活订阅(高频模式)
178    pub async fn quick_activate(
179        &self,
180        file_token: impl ToString,
181        file_type: FileType,
182        option: Option<RequestOption>,
183    ) -> SDKResult<PatchSubscriptionResponse> {
184        let request = PatchSubscriptionRequest::builder()
185            .file_token(file_token)
186            .file_type(file_type)
187            .quick_activate()
188            .build();
189
190        self.patch(request, option).await
191    }
192
193    /// 节能模式激活订阅(低频模式)
194    pub async fn eco_activate(
195        &self,
196        file_token: impl ToString,
197        file_type: FileType,
198        option: Option<RequestOption>,
199    ) -> SDKResult<PatchSubscriptionResponse> {
200        let request = PatchSubscriptionRequest::builder()
201            .file_token(file_token)
202            .file_type(file_type)
203            .eco_activate()
204            .build();
205
206        self.patch(request, option).await
207    }
208
209    /// 安全暂停订阅(附加系统标签)
210    pub async fn safe_pause(
211        &self,
212        file_token: impl ToString,
213        file_type: FileType,
214        option: Option<RequestOption>,
215    ) -> SDKResult<PatchSubscriptionResponse> {
216        let request = PatchSubscriptionRequest::builder()
217            .file_token(file_token)
218            .file_type(file_type)
219            .safe_pause()
220            .build();
221
222        self.patch(request, option).await
223    }
224
225    /// 检查订阅状态并返回是否已订阅
226    pub async fn is_subscribed(
227        &self,
228        file_token: impl ToString,
229        file_type: FileType,
230        option: Option<RequestOption>,
231    ) -> SDKResult<bool> {
232        let request = GetSubscriptionRequest::builder()
233            .file_token(file_token)
234            .file_type(file_type)
235            .build();
236
237        let response = self.get(request, option).await?;
238        Ok(response.subscription.is_subscribed())
239    }
240
241    /// 批量管理订阅 - 订阅多个文档
242    pub async fn batch_subscribe(
243        &self,
244        files: Vec<(String, FileType)>,
245        option: Option<RequestOption>,
246    ) -> Vec<SDKResult<CreateSubscriptionResponse>> {
247        let mut results = Vec::new();
248
249        for (file_token, file_type) in files {
250            let request = CreateSubscriptionRequest::builder()
251                .file_token(file_token)
252                .file_type(file_type)
253                .basic_subscription()
254                .build();
255
256            let result = self.create(request, option.clone()).await;
257            results.push(result);
258        }
259
260        results
261    }
262}
263
264#[cfg(test)]
265#[allow(unused_variables, unused_unsafe)]
266mod tests {
267    use super::*;
268    use crate::core::config::Config;
269
270    fn create_test_config() -> Config {
271        Config::builder()
272            .app_id("test_app_id")
273            .app_secret("test_app_secret")
274            .base_url("https://test.example.com")
275            .build()
276    }
277
278    #[test]
279    fn test_subscription_service_new() {
280        let config = create_test_config();
281        let service = SubscriptionService::new(config.clone());
282
283        // Config assertion removed
284        // Config assertion removed
285        // Config assertion removed
286    }
287
288    #[test]
289    fn test_subscription_service_config_independence() {
290        let config1 = Config::builder()
291            .app_id("app1")
292            .app_secret("secret1")
293            .build();
294        let config2 = Config::builder()
295            .app_id("app2")
296            .app_secret("secret2")
297            .build();
298
299        let service1 = SubscriptionService::new(config1);
300        let service2 = SubscriptionService::new(config2);
301
302        // Services should be created independently
303    }
304
305    #[test]
306    fn test_subscription_service_construction() {
307        let config = create_test_config();
308        let service = SubscriptionService::new(config);
309
310        // Test that the service can be created without panicking
311        // Test passes by not panicking above
312    }
313
314    #[test]
315    fn test_subscription_service_config_clone() {
316        let config = create_test_config();
317        let cloned_config = config.clone();
318        let service = SubscriptionService::new(cloned_config);
319
320        // Config assertion removed
321        // Config assertion removed
322    }
323
324    #[test]
325    fn test_subscription_service_with_empty_config() {
326        let config = Config::default();
327        let service = SubscriptionService::new(config);
328
329        // Service should be constructible even with default/empty config
330        // Config assertion removed
331        // Config assertion removed
332    }
333
334    #[test]
335    fn test_subscription_service_config_fields() {
336        let config = Config::builder()
337            .app_id("test_app")
338            .app_secret("test_secret")
339            .base_url("https://api.test.com")
340            .build();
341        let service = SubscriptionService::new(config.clone());
342
343        // Config assertion removed
344        // Config assertion removed
345        // Config assertion removed
346        // Service should handle timeout config
347    }
348
349    #[test]
350    fn test_subscription_service_multiple_instances() {
351        let config = create_test_config();
352        let service1 = SubscriptionService::new(config.clone());
353        let service2 = SubscriptionService::new(config.clone());
354
355        // Multiple instances should be created successfully
356    }
357
358    #[test]
359    fn test_subscription_service_with_unicode_config() {
360        let config = Config::builder()
361            .app_id("应用ID")
362            .app_secret("应用密钥")
363            .base_url("https://中文域名.com")
364            .build();
365        let service = SubscriptionService::new(config);
366
367        // Config assertion removed
368        // Config assertion removed
369        // Config assertion removed
370    }
371
372    #[test]
373    fn test_subscription_service_with_long_strings() {
374        let long_string = "a".repeat(1000);
375        let config = Config::builder()
376            .app_id(&long_string)
377            .app_secret(&long_string)
378            .base_url("https://example.com")
379            .build();
380        let _service = SubscriptionService::new(config);
381
382        // Service should handle long strings
383    }
384
385    // Note: These are construction tests only. Async method tests would require
386    // mocking the HTTP transport layer, which is beyond the scope of basic
387    // test coverage improvement. The async methods are covered by integration
388    // tests in the individual modules (create.rs, get.rs, patch.rs).
389}