use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateMemoRequest {
pub content: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub visibility: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Memo {
#[serde(skip)]
pub id: i64,
pub name: String,
#[serde(default)]
pub state: String,
pub creator: String,
#[serde(rename = "createTime", deserialize_with = "parse_timestamp")]
pub created_ts: i64,
#[serde(rename = "updateTime", deserialize_with = "parse_timestamp", default)]
pub updated_ts: i64,
#[serde(default)]
pub content: String,
#[serde(default)]
pub visibility: String,
#[serde(default)]
pub tags: Vec<String>,
#[serde(default)]
pub attachments: Vec<Attachment>,
#[serde(default)]
pub pinned: bool,
}
impl Memo {
pub fn extract_id(name: &str) -> i64 {
name.rsplit('/')
.next()
.and_then(|s| s.parse::<i64>().ok())
.unwrap_or(0)
}
}
fn parse_timestamp<'de, D>(deserializer: D) -> Result<i64, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde_json::Value;
let value = Value::deserialize(deserializer)?;
match value {
Value::String(s) => {
if s.is_empty() {
return Ok(0);
}
chrono::DateTime::parse_from_rfc3339(&s)
.map(|dt| dt.timestamp_millis())
.or_else(|_| {
s.parse::<i64>()
.map(|ts| if ts < 10000000000 { ts * 1000 } else { ts })
})
.map_err(|_| serde::de::Error::custom(format!("Invalid timestamp format: {}", s)))
}
Value::Number(n) => {
let ts = n.as_i64().unwrap_or(0);
Ok(if ts < 10000000000 { ts * 1000 } else { ts })
}
Value::Null => Ok(0),
_ => Err(serde::de::Error::custom("Invalid timestamp type")),
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Attachment {
pub name: String,
#[serde(default)]
pub filename: String,
#[serde(rename = "type", default)]
pub attachment_type: String,
#[serde(default)]
pub size: String,
#[serde(default)]
pub external_link: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListMemosResponse {
#[serde(deserialize_with = "deserialize_memos")]
pub memos: Vec<Memo>,
#[serde(default)]
pub next_page_token: Option<String>,
}
fn deserialize_memos<'de, D>(deserializer: D) -> Result<Vec<Memo>, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut memos: Vec<Memo> = Vec::deserialize(deserializer)?;
for memo in &mut memos {
memo.id = Memo::extract_id(&memo.name);
}
Ok(memos)
}