use crate::core::{
api_req::ApiRequest,
api_resp::{ApiResponseTrait, ResponseFormat},
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Calendar {
pub calendar_id: Option<String>,
pub summary: Option<String>,
pub description: Option<String>,
pub permissions: Option<CalendarPermission>,
pub color: Option<i32>,
pub r#type: Option<CalendarType>,
pub summary_info: Option<CalendarSummaryInfo>,
pub is_primary: Option<bool>,
pub role: Option<CalendarRole>,
pub create_time: Option<String>,
pub is_deleted: Option<bool>,
pub is_third_party: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CalendarPermission {
pub access_role: Option<CalendarAccessRole>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CalendarAccessRole {
Unknown,
None,
FreeBusyReader,
Reader,
Writer,
Owner,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CalendarType {
Unknown,
Primary,
Shared,
Google,
Resource,
Exchange,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CalendarSummaryInfo {
pub color: Option<i32>,
pub summary: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CalendarRole {
Unknown,
None,
FreeBusyReader,
Reader,
Writer,
Owner,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CalendarEvent {
pub event_id: Option<String>,
pub organizer_calendar_id: Option<String>,
pub summary: Option<String>,
pub description: Option<String>,
pub start_time: Option<TimeInfo>,
pub end_time: Option<TimeInfo>,
pub is_all_day: Option<bool>,
pub recurrence: Option<String>,
pub reminders: Option<Vec<Reminder>>,
pub attendees: Option<Vec<EventAttendee>>,
pub meeting_rooms: Option<Vec<MeetingRoom>>,
pub location: Option<Location>,
pub color: Option<i32>,
pub status: Option<EventStatus>,
pub is_free_busy: Option<bool>,
pub creator: Option<EventCreator>,
pub organizer: Option<EventOrganizer>,
pub create_time: Option<String>,
pub update_time: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimeInfo {
pub timestamp: Option<String>,
pub date: Option<String>,
pub timezone: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Reminder {
pub minutes: Option<i32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventAttendee {
pub r#type: Option<AttendeeType>,
pub attendee_id: Option<String>,
pub rsvp_status: Option<RsvpStatus>,
pub is_optional: Option<bool>,
pub is_organizer: Option<bool>,
pub is_external: Option<bool>,
pub display_name: Option<String>,
pub chat_id: Option<String>,
pub room_id: Option<String>,
pub third_party_email: Option<String>,
pub operate_id: Option<String>,
pub resource_customization: Option<Vec<ResourceCustomization>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AttendeeType {
User,
Chat,
Resource,
ThirdParty,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RsvpStatus {
NeedsAction,
Accept,
Decline,
Tentative,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MeetingRoom {
pub room_id: Option<String>,
pub display_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Location {
pub name: Option<String>,
pub address: Option<String>,
pub latitude: Option<f64>,
pub longitude: Option<f64>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EventStatus {
Tentative,
Confirmed,
Cancelled,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventCreator {
pub user_id: Option<String>,
pub display_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventOrganizer {
pub user_id: Option<String>,
pub display_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourceCustomization {
pub index_id: Option<String>,
pub input_content: Option<String>,
pub options: Option<Vec<ResourceCustomizationOption>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourceCustomizationOption {
pub option_key: Option<String>,
pub others_option: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CalendarAcl {
pub acl_id: Option<String>,
pub role: Option<CalendarRole>,
pub scope: Option<AclScope>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AclScope {
pub r#type: Option<AclScopeType>,
pub user_id: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AclScopeType {
User,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmptyResponse {}
impl ApiResponseTrait for EmptyResponse {
fn data_format() -> ResponseFormat {
ResponseFormat::Data
}
}
#[derive(Default, Clone)]
pub struct BaseCalendarRequest {
pub api_req: ApiRequest,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum UserIdType {
OpenId,
UnionId,
UserId,
}
impl std::fmt::Display for UserIdType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
UserIdType::OpenId => write!(f, "open_id"),
UserIdType::UnionId => write!(f, "union_id"),
UserIdType::UserId => write!(f, "user_id"),
}
}
}
#[cfg(test)]
#[allow(unused_variables, unused_unsafe)]
mod tests {
use super::*;
#[test]
fn test_calendar_access_role_serialization() {
let role = CalendarAccessRole::Writer;
let serialized = serde_json::to_string(&role).unwrap();
assert_eq!(serialized, "\"writer\"");
let deserialized: CalendarAccessRole = serde_json::from_str(&serialized).unwrap();
assert_eq!(role, deserialized);
}
#[test]
fn test_calendar_type_serialization() {
let calendar_type = CalendarType::Primary;
let serialized = serde_json::to_string(&calendar_type).unwrap();
assert_eq!(serialized, "\"primary\"");
let deserialized: CalendarType = serde_json::from_str(&serialized).unwrap();
assert_eq!(calendar_type, deserialized);
}
#[test]
fn test_calendar_role_serialization() {
let role = CalendarRole::Owner;
let serialized = serde_json::to_string(&role).unwrap();
assert_eq!(serialized, "\"owner\"");
let deserialized: CalendarRole = serde_json::from_str(&serialized).unwrap();
assert_eq!(role, deserialized);
}
#[test]
fn test_user_id_type_display() {
assert_eq!(UserIdType::OpenId.to_string(), "open_id");
assert_eq!(UserIdType::UnionId.to_string(), "union_id");
assert_eq!(UserIdType::UserId.to_string(), "user_id");
}
#[test]
fn test_user_id_type_serialization() {
let user_id_type = UserIdType::UserId;
let serialized = serde_json::to_string(&user_id_type).unwrap();
assert_eq!(serialized, "\"user_id\"");
let deserialized: UserIdType = serde_json::from_str(&serialized).unwrap();
assert_eq!(user_id_type, deserialized);
}
#[test]
fn test_calendar_serialization() {
let calendar = Calendar {
calendar_id: Some("cal_123".to_string()),
summary: Some("工作日历".to_string()),
description: Some("团队工作安排日历".to_string()),
permissions: Some(CalendarPermission {
access_role: Some(CalendarAccessRole::Writer),
}),
color: Some(1),
r#type: Some(CalendarType::Primary),
summary_info: Some(CalendarSummaryInfo {
color: Some(2),
summary: Some("摘要信息".to_string()),
}),
is_primary: Some(true),
role: Some(CalendarRole::Owner),
create_time: Some("2024-01-01T00:00:00Z".to_string()),
is_deleted: Some(false),
is_third_party: Some(false),
};
let serialized = serde_json::to_string(&calendar).unwrap();
let deserialized: Calendar = serde_json::from_str(&serialized).unwrap();
assert_eq!(calendar.calendar_id, deserialized.calendar_id);
assert_eq!(calendar.summary, deserialized.summary);
assert_eq!(calendar.description, deserialized.description);
assert_eq!(calendar.is_primary, deserialized.is_primary);
assert_eq!(calendar.is_deleted, deserialized.is_deleted);
}
#[test]
fn test_calendar_event_serialization() {
let event = CalendarEvent {
event_id: Some("event_123".to_string()),
organizer_calendar_id: Some("cal_123".to_string()),
summary: Some("团队会议".to_string()),
description: Some("讨论项目进展".to_string()),
start_time: Some(TimeInfo {
timestamp: Some("1640995200".to_string()),
date: None,
timezone: Some("Asia/Shanghai".to_string()),
}),
end_time: Some(TimeInfo {
timestamp: Some("1640998800".to_string()),
date: None,
timezone: Some("Asia/Shanghai".to_string()),
}),
is_all_day: Some(false),
recurrence: Some("FREQ=WEEKLY;BYDAY=MO".to_string()),
reminders: Some(vec![Reminder { minutes: Some(15) }]),
attendees: Some(vec![EventAttendee {
r#type: Some(AttendeeType::User),
attendee_id: Some("user_123".to_string()),
rsvp_status: Some(RsvpStatus::Accept),
is_optional: Some(false),
is_organizer: Some(true),
is_external: Some(false),
display_name: Some("张三".to_string()),
chat_id: None,
room_id: None,
third_party_email: None,
operate_id: None,
resource_customization: None,
}]),
meeting_rooms: Some(vec![MeetingRoom {
room_id: Some("room_123".to_string()),
display_name: Some("会议室A".to_string()),
}]),
location: Some(Location {
name: Some("北京office".to_string()),
address: Some("北京市朝阳区".to_string()),
latitude: Some(39.9042),
longitude: Some(116.4074),
}),
color: Some(3),
status: Some(EventStatus::Confirmed),
is_free_busy: Some(false),
creator: Some(EventCreator {
user_id: Some("user_123".to_string()),
display_name: Some("张三".to_string()),
}),
organizer: Some(EventOrganizer {
user_id: Some("user_123".to_string()),
display_name: Some("张三".to_string()),
}),
create_time: Some("2024-01-01T00:00:00Z".to_string()),
update_time: Some("2024-01-01T01:00:00Z".to_string()),
};
let serialized = serde_json::to_string(&event).unwrap();
let deserialized: CalendarEvent = serde_json::from_str(&serialized).unwrap();
assert_eq!(event.event_id, deserialized.event_id);
assert_eq!(event.summary, deserialized.summary);
assert_eq!(event.description, deserialized.description);
assert_eq!(event.is_all_day, deserialized.is_all_day);
assert_eq!(
event.attendees.as_ref().unwrap().len(),
deserialized.attendees.as_ref().unwrap().len()
);
assert_eq!(
event.meeting_rooms.as_ref().unwrap().len(),
deserialized.meeting_rooms.as_ref().unwrap().len()
);
}
#[test]
fn test_time_info_serialization() {
let time_info = TimeInfo {
timestamp: Some("1640995200".to_string()),
date: Some("2022-01-01".to_string()),
timezone: Some("Asia/Shanghai".to_string()),
};
let serialized = serde_json::to_string(&time_info).unwrap();
let deserialized: TimeInfo = serde_json::from_str(&serialized).unwrap();
assert_eq!(time_info.timestamp, deserialized.timestamp);
assert_eq!(time_info.date, deserialized.date);
assert_eq!(time_info.timezone, deserialized.timezone);
}
#[test]
fn test_event_attendee_serialization() {
let attendee = EventAttendee {
r#type: Some(AttendeeType::User),
attendee_id: Some("user_456".to_string()),
rsvp_status: Some(RsvpStatus::Tentative),
is_optional: Some(true),
is_organizer: Some(false),
is_external: Some(true),
display_name: Some("李四".to_string()),
chat_id: Some("chat_123".to_string()),
room_id: None,
third_party_email: Some("lisi@external.com".to_string()),
operate_id: Some("operate_123".to_string()),
resource_customization: Some(vec![ResourceCustomization {
index_id: Some("index_1".to_string()),
input_content: Some("特殊需求".to_string()),
options: Some(vec![ResourceCustomizationOption {
option_key: Some("key_1".to_string()),
others_option: Some("其他选项".to_string()),
}]),
}]),
};
let serialized = serde_json::to_string(&attendee).unwrap();
let deserialized: EventAttendee = serde_json::from_str(&serialized).unwrap();
assert_eq!(attendee.attendee_id, deserialized.attendee_id);
assert_eq!(attendee.display_name, deserialized.display_name);
assert_eq!(attendee.is_optional, deserialized.is_optional);
assert_eq!(attendee.is_external, deserialized.is_external);
assert_eq!(attendee.third_party_email, deserialized.third_party_email);
assert_eq!(
attendee.resource_customization.as_ref().unwrap().len(),
deserialized.resource_customization.as_ref().unwrap().len()
);
}
#[test]
fn test_attendee_type_serialization() {
let types = vec![
AttendeeType::User,
AttendeeType::Chat,
AttendeeType::Resource,
AttendeeType::ThirdParty,
];
for attendee_type in types {
let serialized = serde_json::to_string(&attendee_type).unwrap();
let deserialized: AttendeeType = serde_json::from_str(&serialized).unwrap();
assert_eq!(attendee_type, deserialized);
}
}
#[test]
fn test_rsvp_status_serialization() {
let statuses = vec![
RsvpStatus::NeedsAction,
RsvpStatus::Accept,
RsvpStatus::Decline,
RsvpStatus::Tentative,
];
for status in statuses {
let serialized = serde_json::to_string(&status).unwrap();
let deserialized: RsvpStatus = serde_json::from_str(&serialized).unwrap();
assert_eq!(status, deserialized);
}
}
#[test]
fn test_event_status_serialization() {
let statuses = vec![
EventStatus::Tentative,
EventStatus::Confirmed,
EventStatus::Cancelled,
];
for status in statuses {
let serialized = serde_json::to_string(&status).unwrap();
let deserialized: EventStatus = serde_json::from_str(&serialized).unwrap();
assert_eq!(status, deserialized);
}
}
#[test]
fn test_meeting_room_serialization() {
let room = MeetingRoom {
room_id: Some("room_456".to_string()),
display_name: Some("大会议室".to_string()),
};
let serialized = serde_json::to_string(&room).unwrap();
let deserialized: MeetingRoom = serde_json::from_str(&serialized).unwrap();
assert_eq!(room.room_id, deserialized.room_id);
assert_eq!(room.display_name, deserialized.display_name);
}
#[test]
fn test_location_serialization() {
let location = Location {
name: Some("上海办公室".to_string()),
address: Some("上海市浦东新区".to_string()),
latitude: Some(31.2304),
longitude: Some(121.4737),
};
let serialized = serde_json::to_string(&location).unwrap();
let deserialized: Location = serde_json::from_str(&serialized).unwrap();
assert_eq!(location.name, deserialized.name);
assert_eq!(location.address, deserialized.address);
assert_eq!(location.latitude, deserialized.latitude);
assert_eq!(location.longitude, deserialized.longitude);
}
#[test]
fn test_calendar_acl_serialization() {
let acl = CalendarAcl {
acl_id: Some("acl_123".to_string()),
role: Some(CalendarRole::Reader),
scope: Some(AclScope {
r#type: Some(AclScopeType::User),
user_id: Some("user_789".to_string()),
}),
};
let serialized = serde_json::to_string(&acl).unwrap();
let deserialized: CalendarAcl = serde_json::from_str(&serialized).unwrap();
assert_eq!(acl.acl_id, deserialized.acl_id);
assert_eq!(
acl.scope.as_ref().unwrap().user_id,
deserialized.scope.as_ref().unwrap().user_id
);
}
#[test]
fn test_resource_customization_serialization() {
let customization = ResourceCustomization {
index_id: Some("custom_1".to_string()),
input_content: Some("自定义内容".to_string()),
options: Some(vec![
ResourceCustomizationOption {
option_key: Some("option_1".to_string()),
others_option: Some("选项1".to_string()),
},
ResourceCustomizationOption {
option_key: Some("option_2".to_string()),
others_option: Some("选项2".to_string()),
},
]),
};
let serialized = serde_json::to_string(&customization).unwrap();
let deserialized: ResourceCustomization = serde_json::from_str(&serialized).unwrap();
assert_eq!(customization.index_id, deserialized.index_id);
assert_eq!(customization.input_content, deserialized.input_content);
assert_eq!(
customization.options.as_ref().unwrap().len(),
deserialized.options.as_ref().unwrap().len()
);
}
#[test]
fn test_empty_response_serialization() {
let response = EmptyResponse {};
let serialized = serde_json::to_string(&response).unwrap();
let _deserialized: EmptyResponse = serde_json::from_str(&serialized).unwrap();
assert_eq!(serialized, "{}");
}
#[test]
fn test_empty_response_data_format() {
assert_eq!(EmptyResponse::data_format(), ResponseFormat::Data);
}
#[test]
fn test_models_with_none_values() {
let calendar = Calendar {
calendar_id: None,
summary: None,
description: None,
permissions: None,
color: None,
r#type: None,
summary_info: None,
is_primary: None,
role: None,
create_time: None,
is_deleted: None,
is_third_party: None,
};
let serialized = serde_json::to_string(&calendar).unwrap();
let deserialized: Calendar = serde_json::from_str(&serialized).unwrap();
assert!(deserialized.calendar_id.is_none());
assert!(deserialized.summary.is_none());
assert!(deserialized.description.is_none());
assert!(deserialized.permissions.is_none());
assert!(deserialized.is_primary.is_none());
}
#[test]
fn test_debug_trait_for_models() {
let calendar_type = CalendarType::Shared;
let debug_string = format!("{:?}", calendar_type);
assert!(debug_string.contains("Shared"));
let reminder = Reminder { minutes: Some(30) };
let debug_string = format!("{:?}", reminder);
assert!(debug_string.contains("Reminder"));
assert!(debug_string.contains("30"));
}
#[test]
fn test_all_calendar_access_roles() {
let roles = vec![
CalendarAccessRole::Unknown,
CalendarAccessRole::None,
CalendarAccessRole::FreeBusyReader,
CalendarAccessRole::Reader,
CalendarAccessRole::Writer,
CalendarAccessRole::Owner,
];
for role in roles {
let serialized = serde_json::to_string(&role).unwrap();
let deserialized: CalendarAccessRole = serde_json::from_str(&serialized).unwrap();
assert_eq!(role, deserialized);
}
}
#[test]
fn test_all_calendar_types() {
let types = vec![
CalendarType::Unknown,
CalendarType::Primary,
CalendarType::Shared,
CalendarType::Google,
CalendarType::Resource,
CalendarType::Exchange,
];
for calendar_type in types {
let serialized = serde_json::to_string(&calendar_type).unwrap();
let deserialized: CalendarType = serde_json::from_str(&serialized).unwrap();
assert_eq!(calendar_type, deserialized);
}
}
#[test]
fn test_all_calendar_roles() {
let roles = vec![
CalendarRole::Unknown,
CalendarRole::None,
CalendarRole::FreeBusyReader,
CalendarRole::Reader,
CalendarRole::Writer,
CalendarRole::Owner,
];
for role in roles {
let serialized = serde_json::to_string(&role).unwrap();
let deserialized: CalendarRole = serde_json::from_str(&serialized).unwrap();
assert_eq!(role, deserialized);
}
}
#[test]
fn test_base_calendar_request_default() {
let request = BaseCalendarRequest::default();
assert!(!request.api_req.api_path.is_empty() || request.api_req.api_path.is_empty());
}
#[test]
fn test_complex_calendar_event_with_all_fields() {
let event = CalendarEvent {
event_id: Some("complex_event_123".to_string()),
organizer_calendar_id: Some("cal_org_123".to_string()),
summary: Some("复杂的团队会议".to_string()),
description: Some("包含所有字段的复杂会议".to_string()),
start_time: Some(TimeInfo {
timestamp: Some("1640995200".to_string()),
date: None,
timezone: Some("Asia/Shanghai".to_string()),
}),
end_time: Some(TimeInfo {
timestamp: Some("1640998800".to_string()),
date: None,
timezone: Some("Asia/Shanghai".to_string()),
}),
is_all_day: Some(false),
recurrence: Some("FREQ=DAILY;COUNT=5".to_string()),
reminders: Some(vec![
Reminder { minutes: Some(15) },
Reminder { minutes: Some(30) },
]),
attendees: Some(vec![
EventAttendee {
r#type: Some(AttendeeType::User),
attendee_id: Some("user_123".to_string()),
rsvp_status: Some(RsvpStatus::Accept),
is_optional: Some(false),
is_organizer: Some(true),
is_external: Some(false),
display_name: Some("组织者".to_string()),
chat_id: None,
room_id: None,
third_party_email: None,
operate_id: None,
resource_customization: None,
},
EventAttendee {
r#type: Some(AttendeeType::ThirdParty),
attendee_id: None,
rsvp_status: Some(RsvpStatus::NeedsAction),
is_optional: Some(true),
is_organizer: Some(false),
is_external: Some(true),
display_name: Some("外部参与者".to_string()),
chat_id: None,
room_id: None,
third_party_email: Some("external@example.com".to_string()),
operate_id: Some("op_123".to_string()),
resource_customization: Some(vec![ResourceCustomization {
index_id: Some("res_1".to_string()),
input_content: Some("外部资源".to_string()),
options: None,
}]),
},
]),
meeting_rooms: Some(vec![
MeetingRoom {
room_id: Some("room_a".to_string()),
display_name: Some("会议室A".to_string()),
},
MeetingRoom {
room_id: Some("room_b".to_string()),
display_name: Some("会议室B".to_string()),
},
]),
location: Some(Location {
name: Some("多功能会议厅".to_string()),
address: Some("北京市海淀区中关村".to_string()),
latitude: Some(39.9896),
longitude: Some(116.3062),
}),
color: Some(5),
status: Some(EventStatus::Confirmed),
is_free_busy: Some(true),
creator: Some(EventCreator {
user_id: Some("creator_123".to_string()),
display_name: Some("创建者".to_string()),
}),
organizer: Some(EventOrganizer {
user_id: Some("organizer_123".to_string()),
display_name: Some("组织者".to_string()),
}),
create_time: Some("2024-01-01T00:00:00Z".to_string()),
update_time: Some("2024-01-01T12:00:00Z".to_string()),
};
let serialized = serde_json::to_string(&event).unwrap();
let deserialized: CalendarEvent = serde_json::from_str(&serialized).unwrap();
assert_eq!(event.event_id, deserialized.event_id);
assert_eq!(event.attendees.as_ref().unwrap().len(), 2);
assert_eq!(event.meeting_rooms.as_ref().unwrap().len(), 2);
assert_eq!(event.reminders.as_ref().unwrap().len(), 2);
assert_eq!(deserialized.attendees.as_ref().unwrap().len(), 2);
assert_eq!(deserialized.meeting_rooms.as_ref().unwrap().len(), 2);
assert_eq!(deserialized.reminders.as_ref().unwrap().len(), 2);
}
}