use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use openlark_core::api::Response;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DocumentType {
Doc,
Sheet,
Slide,
Mindnote,
Bitable,
Docx,
Other,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DocumentStatus {
Draft,
Published,
Archived,
Deleted,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PermissionType {
View,
Edit,
Admin,
Owner,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CommentType {
Normal,
Suggestion,
Question,
Solution,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Document {
pub document_id: String,
pub title: String,
pub document_type: DocumentType,
pub status: DocumentStatus,
pub owner_id: String,
pub owner_name: Option<String>,
pub create_time: DateTime<Utc>,
pub update_time: DateTime<Utc>,
pub version: i32,
pub size: i64,
pub description: Option<String>,
pub tags: Option<Vec<String>>,
pub cover_url: Option<String>,
pub preview_url: Option<String>,
pub share_url: Option<String>,
pub view_count: i32,
pub edit_count: i32,
pub comment_count: i32,
favorite_count: i32,
pub folder_id: Option<String>,
pub permissions: Option<DocumentPermissions>,
pub collaborators: Option<Vec<Collaborator>>,
pub extra_properties: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DocumentPermissions {
pub is_public: bool,
pub permissions: Vec<DocumentPermission>,
pub inherit_permissions: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DocumentPermission {
pub principal_id: String,
pub principal_type: PrincipalType,
pub permission_type: PermissionType,
pub expire_time: Option<DateTime<Utc>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PrincipalType {
User,
Group,
Department,
Organization,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Collaborator {
pub user_id: String,
pub name: String,
pub avatar: Option<String>,
pub email: Option<String>,
pub permission: PermissionType,
pub join_time: DateTime<Utc>,
pub last_active_time: Option<DateTime<Utc>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DocumentVersion {
pub version_id: String,
pub document_id: String,
pub version: i32,
pub title: String,
pub description: Option<String>,
pub creator_id: String,
pub creator_name: String,
pub create_time: DateTime<Utc>,
pub size: i64,
pub diff: Option<String>,
pub tags: Option<Vec<String>>,
pub is_major: bool,
pub status: VersionStatus,
pub notes: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum VersionStatus {
InProgress,
Completed,
Deprecated,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Folder {
pub folder_id: String,
pub name: String,
pub parent_folder_id: Option<String>,
pub owner_id: String,
pub owner_name: Option<String>,
pub description: Option<String>,
pub icon: Option<String>,
pub color: Option<String>,
pub create_time: DateTime<Utc>,
pub update_time: DateTime<Utc>,
pub document_count: i32,
pub subfolder_count: i32,
pub permissions: Option<FolderPermissions>,
pub order: Option<i32>,
pub status: FolderStatus,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct FolderPermissions {
pub is_public: bool,
pub permissions: Vec<FolderPermission>,
pub inherit_permissions: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FolderPermission {
pub principal_id: String,
pub principal_type: PrincipalType,
pub permission_type: FolderPermissionType,
pub expire_time: Option<DateTime<Utc>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum FolderPermissionType {
View,
Edit,
Admin,
Creator,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum FolderStatus {
Active,
Archived,
Deleted,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Comment {
pub comment_id: String,
pub document_id: String,
pub user_id: String,
pub user_name: String,
pub avatar: Option<String>,
pub content: String,
pub comment_type: CommentType,
pub parent_comment_id: Option<String>,
pub position: Option<CommentPosition>,
pub reference_count: i32,
pub like_count: i32,
pub is_resolved: bool,
pub create_time: DateTime<Utc>,
pub update_time: DateTime<Utc>,
pub replies: Option<Vec<Comment>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct CommentPosition {
pub page_number: Option<i32>,
pub x: Option<f64>,
pub y: Option<f64>,
pub selection: Option<TextSelection>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TextSelection {
pub start: TextPosition,
pub end: TextPosition,
pub selected_text: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TextPosition {
pub paragraph_index: i32,
pub offset: i32,
pub line: i32,
pub column: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DocumentTemplate {
pub template_id: String,
pub name: String,
pub description: Option<String>,
pub template_type: DocumentType,
pub category: Option<String>,
pub tags: Option<Vec<String>>,
pub cover_url: Option<String>,
pub preview_url: Option<String>,
pub creator_id: String,
pub creator_name: String,
pub is_public: bool,
pub usage_count: i32,
pub rating: Option<f64>,
pub create_time: DateTime<Utc>,
pub update_time: DateTime<Utc>,
pub content: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DocumentSearchResult {
pub document_id: String,
pub title: String,
pub document_type: DocumentType,
pub status: DocumentStatus,
pub owner_id: String,
pub owner_name: Option<String>,
pub description: Option<String>,
pub tags: Option<Vec<String>>,
pub create_time: DateTime<Utc>,
pub update_time: DateTime<Utc>,
pub size: i64,
pub relevance_score: f64,
pub highlights: Option<Vec<SearchHighlight>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SearchHighlight {
pub field: String,
pub fragments: Vec<String>,
pub ranges: Vec<HighlightRange>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct HighlightRange {
pub start: i32,
pub end: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DocumentRecommendation {
pub document_id: String,
pub title: String,
pub reason: String,
pub recommendation_type: RecommendationType,
pub score: f64,
pub recommend_time: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RecommendationType {
Collaboration,
Tag,
SearchHistory,
Popular,
Similar,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateDocumentRequest {
pub title: String,
pub document_type: DocumentType,
pub content: Option<serde_json::Value>,
pub description: Option<String>,
pub tags: Option<Vec<String>>,
pub folder_id: Option<String>,
pub permissions: Option<DocumentPermissions>,
pub collaborators: Option<Vec<Collaborator>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateDocumentRequest {
pub document_id: String,
pub title: Option<String>,
pub description: Option<String>,
pub tags: Option<Vec<String>>,
pub status: Option<DocumentStatus>,
pub folder_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QueryDocumentsRequest {
pub folder_id: Option<String>,
pub document_type: Option<DocumentType>,
pub status: Option<DocumentStatus>,
pub owner_id: Option<String>,
pub tags: Option<Vec<String>>,
pub keyword: Option<String>,
pub sort_by: Option<SortBy>,
pub sort_direction: Option<SortDirection>,
pub page_size: Option<i32>,
pub page_token: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SortBy {
CreateTime,
UpdateTime,
Title,
Size,
ViewCount,
EditCount,
CommentCount,
FavoriteCount,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SortDirection {
Asc,
Desc,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchDocumentsRequest {
pub query: String,
pub search_scope: Option<SearchScope>,
pub document_type: Option<DocumentType>,
pub status: Option<DocumentStatus>,
pub owner_id: Option<String>,
pub tags: Option<Vec<String>>,
pub search_type: Option<SearchType>,
pub sort_by: Option<SortBy>,
pub sort_direction: Option<SortDirection>,
pub page_size: Option<i32>,
pub page_token: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SearchScope {
Title,
Content,
Tags,
Description,
Author,
FullText,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SearchType {
Fuzzy,
Exact,
Regex,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateCommentRequest {
pub document_id: String,
pub content: String,
pub comment_type: CommentType,
pub parent_comment_id: Option<String>,
pub position: Option<CommentPosition>,
pub mentions: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QueryCommentsRequest {
pub document_id: String,
pub parent_comment_id: Option<String>,
pub comment_type: Option<CommentType>,
pub is_resolved: Option<bool>,
pub sort_by: Option<SortBy>,
pub sort_direction: Option<SortDirection>,
pub page_size: Option<i32>,
pub page_token: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PageResponse<T> {
pub items: Vec<T>,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub has_more: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub total: Option<i32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Response<T> {
pub code: i32,
pub msg: String,
pub data: Option<T>,
}
pub type DocumentListResponse = Response<PageResponse<Document>>;
pub type DocumentResponse = Response<Document>;
pub type FolderListResponse = Response<PageResponse<Folder>>;
pub type CommentListResponse = Response<PageResponse<Comment>>;
pub type SearchResponse = Response<PageResponse<DocumentSearchResult>>;
pub type RecommendResponse = Response<Vec<DocumentRecommendation>>;
pub type VersionListResponse = Response<PageResponse<DocumentVersion>>;
pub type TemplateListResponse = Response<PageResponse<DocumentTemplate>>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmptyResponse {
pub code: i32,
pub msg: String,
}
impl Default for DocumentType {
fn default() -> Self {
DocumentType::Doc
}
}
impl Default for DocumentStatus {
fn default() -> Self {
DocumentStatus::Draft
}
}
impl Default for PermissionType {
fn default() -> Self {
PermissionType::View
}
}
impl Default for CommentType {
fn default() -> Self {
CommentType::Normal
}
}
impl Default for PrincipalType {
fn default() -> Self {
PrincipalType::User
}
}
impl Default for VersionStatus {
fn default() -> Self {
VersionStatus::InProgress
}
}
impl Default for FolderStatus {
fn default() -> Self {
FolderStatus::Active
}
}
impl Default for FolderPermissionType {
fn default() -> Self {
FolderPermissionType::View
}
}
impl Default for SortBy {
fn default() -> Self {
SortBy::CreateTime
}
}
impl Default for SortDirection {
fn default() -> Self {
SortDirection::Desc
}
}
impl Default for SearchScope {
fn default() -> Self {
SearchScope::FullText
}
}
impl Default for SearchType {
fn default() -> Self {
SearchType::Fuzzy
}
}
impl Default for RecommendationType {
fn default() -> Self {
RecommendationType::Collaboration
}
}
impl Default for CreateDocumentRequest {
fn default() -> Self {
Self {
title: String::new(),
document_type: DocumentType::Doc,
content: None,
description: None,
tags: None,
folder_id: None,
permissions: None,
collaborators: None,
}
}
}
impl Default for UpdateDocumentRequest {
fn default() -> Self {
Self {
document_id: String::new(),
title: None,
description: None,
tags: None,
status: None,
folder_id: None,
}
}
}
impl Default for QueryDocumentsRequest {
fn default() -> Self {
Self {
folder_id: None,
document_type: None,
status: None,
owner_id: None,
tags: None,
keyword: None,
sort_by: None,
sort_direction: None,
page_size: None,
page_token: None,
}
}
}
impl Default for SearchDocumentsRequest {
fn default() -> Self {
Self {
query: String::new(),
search_scope: None,
document_type: None,
status: None,
owner_id: None,
tags: None,
search_type: None,
sort_by: None,
sort_direction: None,
page_size: None,
page_token: None,
}
}
}
impl Default for CreateCommentRequest {
fn default() -> Self {
Self {
document_id: String::new(),
content: String::new(),
comment_type: CommentType::Normal,
parent_comment_id: None,
position: None,
mentions: None,
}
}
}
impl Default for QueryCommentsRequest {
fn default() -> Self {
Self {
document_id: String::new(),
parent_comment_id: None,
comment_type: None,
is_resolved: None,
sort_by: None,
sort_direction: None,
page_size: None,
page_token: None,
}
}
}
impl Default for PageResponse<Document> {
fn default() -> Self {
Self {
items: vec![],
page_token: None,
has_more: Some(false),
total: Some(0),
}
}
}
impl Default for PageResponse<Folder> {
fn default() -> Self {
Self {
items: vec![],
page_token: None,
has_more: Some(false),
total: Some(0),
}
}
}
impl Default for PageResponse<Comment> {
fn default() -> Self {
Self {
items: vec![],
page_token: None,
has_more: Some(false),
total: Some(0),
}
}
}
impl Default for PageResponse<DocumentSearchResult> {
fn default() -> Self {
Self {
items: vec![],
page_token: None,
has_more: Some(false),
total: Some(0),
}
}
}
impl Default for Response<Document> {
fn default() -> Self {
Self {
code: 0,
msg: String::new(),
data: None,
}
}
}
impl Default for Response<EmptyResponse> {
fn default() -> Self {
Self {
code: 0,
msg: String::new(),
data: Some(EmptyResponse::default()),
}
}
}
impl Default for EmptyResponse {
fn default() -> Self {
Self {
code: 0,
msg: String::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum FolderContentType {
Folder,
Document,
All,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct CommentReaction {
pub reaction_id: String,
pub comment_id: String,
pub user_id: String,
pub reaction_type: String,
pub create_time: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchDateRange {
pub start_date: DateTime<Utc>,
pub end_date: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SearchSortBy {
Relevance,
CreateTime,
UpdateTime,
Title,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RecommendType {
Collaboration,
Popular,
Related,
Recent,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TemplateParameter {
pub name: String,
pub param_type: String,
pub description: Option<String>,
pub required: bool,
pub default_value: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct BatchFailureItem {
pub item_id: String,
pub error_code: i32,
pub error_message: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct BatchOperationResult {
pub success_count: i32,
pub failure_count: i32,
pub success_items: Vec<String>,
pub failure_items: Vec<BatchFailureItem>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct VersionDiff {
pub from_version: i32,
pub to_version: i32,
pub diff_type: String,
pub diff_content: String,
pub changed_lines: i32,
pub added_lines: i32,
pub deleted_lines: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SearchResult {
pub items: Vec<SearchItem>,
pub total: i32,
pub search_time: f64,
pub suggestions: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SearchItem {
pub document_id: String,
pub title: String,
pub document_type: DocumentType,
pub owner_id: String,
pub update_time: DateTime<Utc>,
pub snippet: Option<String>,
pub highlights: Option<Vec<String>>,
pub score: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SearchHistoryItem {
pub keyword: String,
pub search_time: DateTime<Utc>,
pub result_count: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct RecommendResult {
pub items: Vec<RecommendItem>,
pub recommend_type: RecommendType,
pub reason: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct RecommendItem {
pub document_id: String,
pub title: String,
pub document_type: DocumentType,
pub owner_id: String,
pub update_time: DateTime<Utc>,
pub score: f64,
pub reason: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct FolderContent {
pub id: String,
pub name: String,
pub content_type: FolderContentType,
pub owner_id: String,
pub create_time: DateTime<Utc>,
pub update_time: DateTime<Utc>,
pub size: Option<i64>,
pub document_type: Option<DocumentType>,
}
impl Default for FolderContentType {
fn default() -> Self {
FolderContentType::All
}
}
impl Default for SearchSortBy {
fn default() -> Self {
SearchSortBy::Relevance
}
}
impl Default for RecommendType {
fn default() -> Self {
RecommendType::Collaboration
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json;
#[test]
fn test_serialization_roundtrip() {
let json = r#"{"test": "value"}"#;
assert!(serde_json::from_str::<serde_json::Value>(json).is_ok());
}
#[test]
fn test_deserialization_from_json() {
let json = r#"{"field": "data"}"#;
let value: serde_json::Value = serde_json::from_str(json).unwrap();
assert_eq!(value["field"], "data");
}
}