Skip to main content

openlark_docs/
models.rs

1/// 文档服务通用数据模型
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6// use openlark_core::api::Response;
7
8/// 文档资源基础信息
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct DocumentBase {
11    /// 文档ID
12    pub document_id: String,
13    /// 文档标题
14    pub title: String,
15    /// 文档类型
16    pub doc_type: DocumentType,
17    /// 创建时间
18    pub create_time: DateTime<Utc>,
19    /// 修改时间
20    pub modify_time: DateTime<Utc>,
21    /// 创建者信息
22    pub creator: UserInfo,
23    /// 修改者信息
24    pub modifier: Option<UserInfo>,
25    /// 文档状态
26    pub status: DocumentStatus,
27}
28
29/// 文档类型枚举
30#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
31#[serde(rename_all = "snake_case")]
32pub enum DocumentType {
33    /// 文本文档
34    Doc,
35    /// 表格
36    Sheet,
37    /// 幻灯片
38    Slide,
39    /// 思维笔记
40    Mindnote,
41    /// 流程图
42    Flowchart,
43    /// 多人实时文档
44    Bitable,
45    /// Wiki页面
46    Wiki,
47    /// 文件夹
48    Folder,
49    /// 其他
50    Other(String),
51}
52
53/// 文档状态
54#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
55#[serde(rename_all = "snake_case")]
56pub enum DocumentStatus {
57    /// 正常
58    Normal,
59    /// 回收站
60    Recycle,
61    /// 删除
62    Deleted,
63    /// 加密
64    Encrypted,
65    /// 归档
66    Archived,
67}
68
69/// 用户信息
70#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
71pub struct UserInfo {
72    /// 用户ID
73    pub user_id: String,
74    /// 用户名
75    pub name: String,
76    /// 邮箱
77    pub email: Option<String>,
78    /// 头像URL
79    pub avatar_url: Option<String>,
80    /// 部门信息
81    pub department: Option<DepartmentInfo>,
82}
83
84/// 部门信息
85#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
86pub struct DepartmentInfo {
87    /// 部门ID
88    pub department_id: String,
89    /// 部门名称
90    pub name: String,
91}
92
93/// 文件信息
94#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
95pub struct FileInfo {
96    /// 文件ID
97    pub file_id: String,
98    /// 文件名
99    pub name: String,
100    /// 文件大小(字节)
101    pub size: u64,
102    /// MIME类型
103    pub mime_type: String,
104    /// 文件URL
105    pub url: String,
106    /// 下载Token
107    pub download_token: Option<String>,
108    /// 缩略图URL
109    pub thumbnail_url: Option<String>,
110}
111
112/// 权限信息
113#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
114pub struct Permission {
115    /// 权限类型
116    pub permission_type: PermissionType,
117    /// 是否可读
118    pub can_read: bool,
119    /// 是否可写
120    pub can_write: bool,
121    /// 是否可删除
122    pub can_delete: bool,
123    /// 是否可分享
124    pub can_share: bool,
125    /// 权限到期时间
126    pub expire_time: Option<DateTime<Utc>>,
127}
128
129/// 权限类型
130#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
131#[serde(rename_all = "snake_case")]
132pub enum PermissionType {
133    /// 所有者
134    Owner,
135    /// 管理员
136    Admin,
137    /// 编辑者
138    Editor,
139    /// 评论者
140    Commenter,
141    /// 查看者
142    Viewer,
143}
144
145/// 分享信息
146#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
147pub struct ShareInfo {
148    /// 分享链接
149    pub share_url: String,
150    /// 分享Token
151    pub share_token: String,
152    /// 权限类型
153    pub permission_type: PermissionType,
154    /// 是否需要密码
155    pub need_password: bool,
156    /// 过期时间
157    pub expire_time: Option<DateTime<Utc>>,
158    /// 访问次数限制
159    pub visit_limit: Option<u32>,
160    /// 当前访问次数
161    pub visit_count: u32,
162}
163
164/// 版本信息
165#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
166pub struct VersionInfo {
167    /// 版本号
168    pub version: i32,
169    /// 版本名称
170    pub version_name: String,
171    /// 创建时间
172    pub create_time: DateTime<Utc>,
173    /// 创建者
174    pub creator: UserInfo,
175    /// 版本描述
176    pub description: Option<String>,
177    /// 是否为当前版本
178    pub is_current: bool,
179    /// 文件大小
180    pub size: u64,
181}
182
183/// 搜索结果
184#[derive(Debug, Clone, Serialize, Deserialize)]
185pub struct SearchResult {
186    /// 文档信息
187    pub document: DocumentBase,
188    /// 匹配的片段
189    pub snippets: Vec<String>,
190    /// 相关度分数
191    pub score: f64,
192}
193
194/// 文档统计信息
195#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
196pub struct DocumentStats {
197    /// 浏览次数
198    pub view_count: u64,
199    /// 编辑次数
200    pub edit_count: u64,
201    /// 评论数量
202    pub comment_count: u64,
203    /// 分享次数
204    pub share_count: u64,
205    /// 下载次数
206    pub download_count: u64,
207    /// 最后统计时间
208    pub last_stats_time: DateTime<Utc>,
209}
210
211/// 文档操作记录
212#[derive(Debug, Clone, Serialize, Deserialize)]
213pub struct OperationRecord {
214    /// 记录ID
215    pub record_id: String,
216    /// 操作类型
217    pub operation_type: OperationType,
218    /// 操作时间
219    pub operation_time: DateTime<Utc>,
220    /// 操作者
221    pub operator: UserInfo,
222    /// 操作描述
223    pub description: Option<String>,
224    /// IP地址
225    pub ip_address: Option<String>,
226    /// 设备信息
227    pub device_info: Option<String>,
228}
229
230/// 操作类型
231#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
232#[serde(rename_all = "snake_case")]
233pub enum OperationType {
234    /// 创建
235    Create,
236    /// 读取
237    Read,
238    /// 更新
239    Update,
240    /// 删除
241    Delete,
242    /// 分享
243    Share,
244    /// 下载
245    Download,
246    /// 复制
247    Copy,
248    /// 移动
249    Move,
250    /// 重命名
251    Rename,
252    /// 权限变更
253    PermissionChange,
254    /// 其他
255    Other(String),
256}
257
258/// 文档导入/导出任务
259#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
260pub struct ImportExportTask {
261    /// 任务ID
262    pub task_id: String,
263    /// 任务类型
264    pub task_type: TaskType,
265    /// 任务状态
266    pub status: TaskStatus,
267    /// 进度百分比 (0-100)
268    pub progress: u8,
269    /// 开始时间
270    pub start_time: DateTime<Utc>,
271    /// 结束时间
272    pub end_time: Option<DateTime<Utc>>,
273    /// 错误信息
274    pub error_message: Option<String>,
275    /// 结果URL
276    pub result_url: Option<String>,
277}
278
279/// 任务类型
280#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
281#[serde(rename_all = "snake_case")]
282pub enum TaskType {
283    /// 导入
284    Import,
285    /// 导出
286    Export,
287    /// 转换
288    Convert,
289}
290
291/// 任务状态
292#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
293#[serde(rename_all = "snake_case")]
294pub enum TaskStatus {
295    /// 等待中
296    Pending,
297    /// 处理中
298    Processing,
299    /// 已完成
300    Completed,
301    /// 已失败
302    Failed,
303    /// 已取消
304    Canceled,
305}
306
307/// 通用响应结构
308#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
309pub struct CommonResponse<T: PartialEq> {
310    /// 是否成功
311    pub success: bool,
312    /// 响应数据
313    pub data: Option<T>,
314    /// 错误信息
315    pub error: Option<ErrorInfo>,
316    /// 请求ID
317    pub request_id: String,
318}
319
320/// 错误信息
321#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
322pub struct ErrorInfo {
323    /// 错误代码
324    pub code: i32,
325    /// 错误消息
326    pub message: String,
327    /// 错误详情
328    pub details: Option<HashMap<String, serde_json::Value>>,
329}
330
331/// 分页请求参数
332#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
333pub struct PageRequest {
334    /// 页码(从1开始)
335    pub page: u32,
336    /// 每页大小
337    pub page_size: u32,
338    /// 排序字段
339    pub sort_field: Option<String>,
340    /// 排序方向
341    pub sort_direction: Option<SortDirection>,
342}
343
344/// 排序方向
345#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
346#[serde(rename_all = "snake_case")]
347pub enum SortDirection {
348    /// 升序
349    Asc,
350    /// 降序
351    Desc,
352}
353
354/// 分页响应
355#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
356pub struct PageResponse<T: PartialEq> {
357    /// 数据列表
358    pub items: Vec<T>,
359    /// 总条数
360    pub total: u64,
361    /// 当前页码
362    pub page: u32,
363    /// 每页大小
364    pub page_size: u32,
365    /// 总页数
366    pub total_page: u32,
367    /// 是否有下一页
368    pub has_next: bool,
369}
370
371impl Default for PageRequest {
372    fn default() -> Self {
373        Self {
374            page: 1,
375            page_size: 20,
376            sort_field: None,
377            sort_direction: Some(SortDirection::Desc),
378        }
379    }
380}
381
382// Docs和Docx项目的特定模型
383// 注意:这些模型的定义在各自的模块中,这里不重复导入
384
385#[cfg(test)]
386mod tests {
387    use super::*;
388
389    fn test_roundtrip<T: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug>(
390        original: &T,
391    ) {
392        let json = serde_json::to_string(original).expect("序列化失败");
393        let deserialized: T = serde_json::from_str(&json).expect("反序列化失败");
394        assert_eq!(original, &deserialized, "roundtrip 后数据不一致");
395    }
396
397    #[test]
398    fn test_document_type_serialization() {
399        test_roundtrip(&DocumentType::Doc);
400        test_roundtrip(&DocumentType::Sheet);
401        test_roundtrip(&DocumentType::Other("custom".to_string()));
402    }
403
404    #[test]
405    fn test_document_status_serialization() {
406        test_roundtrip(&DocumentStatus::Normal);
407        test_roundtrip(&DocumentStatus::Archived);
408    }
409
410    #[test]
411    fn test_permission_type_serialization() {
412        test_roundtrip(&PermissionType::Owner);
413        test_roundtrip(&PermissionType::Viewer);
414    }
415
416    #[test]
417    fn test_operation_type_serialization() {
418        test_roundtrip(&OperationType::Create);
419        test_roundtrip(&OperationType::Other("custom_op".to_string()));
420    }
421
422    #[test]
423    fn test_task_type_serialization() {
424        test_roundtrip(&TaskType::Import);
425        test_roundtrip(&TaskType::Export);
426    }
427
428    #[test]
429    fn test_task_status_serialization() {
430        test_roundtrip(&TaskStatus::Pending);
431        test_roundtrip(&TaskStatus::Completed);
432    }
433
434    #[test]
435    fn test_sort_direction_serialization() {
436        test_roundtrip(&SortDirection::Asc);
437        test_roundtrip(&SortDirection::Desc);
438    }
439
440    #[test]
441    fn test_user_info_serialization() {
442        let user = UserInfo {
443            user_id: "user123".to_string(),
444            name: "测试用户".to_string(),
445            email: Some("test@example.com".to_string()),
446            avatar_url: None,
447            department: Some(DepartmentInfo {
448                department_id: "dept456".to_string(),
449                name: "技术部".to_string(),
450            }),
451        };
452        test_roundtrip(&user);
453    }
454
455    #[test]
456    fn test_department_info_serialization() {
457        let dept = DepartmentInfo {
458            department_id: "dept789".to_string(),
459            name: "产品部".to_string(),
460        };
461        test_roundtrip(&dept);
462    }
463
464    #[test]
465    fn test_file_info_serialization() {
466        let file = FileInfo {
467            file_id: "file123".to_string(),
468            name: "test.pdf".to_string(),
469            size: 1024000,
470            mime_type: "application/pdf".to_string(),
471            url: "https://example.com/file".to_string(),
472            download_token: Some("token123".to_string()),
473            thumbnail_url: None,
474        };
475        test_roundtrip(&file);
476    }
477
478    #[test]
479    fn test_permission_serialization() {
480        let perm = Permission {
481            permission_type: PermissionType::Editor,
482            can_read: true,
483            can_write: true,
484            can_delete: false,
485            can_share: true,
486            expire_time: None,
487        };
488        test_roundtrip(&perm);
489    }
490
491    #[test]
492    fn test_share_info_serialization() {
493        let share = ShareInfo {
494            share_url: "https://share.example.com/doc".to_string(),
495            share_token: "token456".to_string(),
496            permission_type: PermissionType::Viewer,
497            need_password: false,
498            expire_time: None,
499            visit_limit: Some(100),
500            visit_count: 10,
501        };
502        test_roundtrip(&share);
503    }
504
505    #[test]
506    fn test_version_info_serialization() {
507        let version = VersionInfo {
508            version: 1,
509            version_name: "v1.0".to_string(),
510            create_time: Utc::now(),
511            creator: UserInfo {
512                user_id: "user001".to_string(),
513                name: "张三".to_string(),
514                email: None,
515                avatar_url: None,
516                department: None,
517            },
518            description: Some("初始版本".to_string()),
519            is_current: true,
520            size: 2048,
521        };
522        test_roundtrip(&version);
523    }
524
525    #[test]
526    fn test_document_stats_serialization() {
527        let stats = DocumentStats {
528            view_count: 100,
529            edit_count: 20,
530            comment_count: 5,
531            share_count: 10,
532            download_count: 3,
533            last_stats_time: Utc::now(),
534        };
535        test_roundtrip(&stats);
536    }
537
538    #[test]
539    fn test_import_export_task_serialization() {
540        let task = ImportExportTask {
541            task_id: "task789".to_string(),
542            task_type: TaskType::Convert,
543            status: TaskStatus::Processing,
544            progress: 50,
545            start_time: Utc::now(),
546            end_time: None,
547            error_message: None,
548            result_url: Some("https://result.example.com".to_string()),
549        };
550        test_roundtrip(&task);
551    }
552
553    #[test]
554    fn test_error_info_serialization() {
555        let mut details = HashMap::new();
556        details.insert("field".to_string(), serde_json::json!("value"));
557
558        let error = ErrorInfo {
559            code: 404,
560            message: "Not Found".to_string(),
561            details: Some(details),
562        };
563        test_roundtrip(&error);
564    }
565
566    #[test]
567    fn test_page_request_serialization() {
568        let req = PageRequest {
569            page: 1,
570            page_size: 20,
571            sort_field: Some("create_time".to_string()),
572            sort_direction: Some(SortDirection::Desc),
573        };
574        test_roundtrip(&req);
575    }
576
577    #[test]
578    fn test_page_request_default() {
579        let default_req = PageRequest::default();
580        assert_eq!(default_req.page, 1);
581        assert_eq!(default_req.page_size, 20);
582    }
583
584    #[test]
585    fn test_common_response_serialization() {
586        let response: CommonResponse<String> = CommonResponse {
587            success: true,
588            data: Some("test data".to_string()),
589            error: None,
590            request_id: "req123".to_string(),
591        };
592        test_roundtrip(&response);
593    }
594
595    #[test]
596    fn test_page_response_serialization() {
597        let response: PageResponse<String> = PageResponse {
598            items: vec!["item1".to_string(), "item2".to_string()],
599            total: 100,
600            page: 1,
601            page_size: 20,
602            total_page: 5,
603            has_next: true,
604        };
605        test_roundtrip(&response);
606    }
607}