From d9fa0a00889e40baf5289a65e17d47727b7c506e Mon Sep 17 00:00:00 2001 From: Harald Eilertsen Date: Sat, 13 Jan 2024 13:00:25 +0100 Subject: Add stream::DateTime struct As the date and time returned in the json data from the zot stream api's neither contains any timezone information, nor follow the RFC3339 format expected by Chrono, we need to make our own date time type, and handle deserialization ourselves. --- Cargo.toml | 1 + src/stream.rs | 2 ++ src/stream/datetime.rs | 93 ++++++++++++++++++++++++++++++++++++++++++++++++ src/stream/streamitem.rs | 11 ++++++ 4 files changed, 107 insertions(+) create mode 100644 src/stream/datetime.rs diff --git a/Cargo.toml b/Cargo.toml index a271637..4b76f68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ authors = ["haraldei"] edition = "2021" [dependencies] +chrono = "0.4.0" clap = "2.33.0" dotenv = "0.15" reqwest = { version = "0.11", features = ["default-tls", "multipart"] } diff --git a/src/stream.rs b/src/stream.rs index 438ef0f..0348822 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -11,9 +11,11 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ +mod datetime; mod streamitem; mod verb; +pub use datetime::DateTime; pub use streamitem::{ StreamItem, StreamItemEncoding, diff --git a/src/stream/datetime.rs b/src/stream/datetime.rs new file mode 100644 index 0000000..8b67e78 --- /dev/null +++ b/src/stream/datetime.rs @@ -0,0 +1,93 @@ +/** + * Date and time representation in the stream. + * + * SPDX-FileCopyrightText: 2023 Eilertsens Kodeknekkeri + * SPDX-FileCopyrightText: 2023 Harald Eilertsen + * + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +use chrono::NaiveDateTime; +use serde::Deserialize; + +/** + * Handle date and time. + * + * This is mainly a wrapper around the chrono::NaiveDateTime struct, + * as the date and time returned by the json data from the zot stream + * API's does not contain any timezone information. + */ +#[derive(Debug, PartialEq)] +pub struct DateTime { + datetime: Option +} + +/* + * Implement Display for the DateTime type, so that it will display + * using the correct time and date format by default. + */ +impl std::fmt::Display for DateTime { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.datetime { + Some(dt) => write!(f, "{}", dt.format("%Y-%m-%d %H:%M:%S")), + None => write!(f, "0000-00-00 00:00:00"), + } + } +} + +/* + * Since the date and time format returned in the json from the + * stream API, does not conform to the RFC3339 format expected by + * the default chrono deserializer, we have to implement our own + * deserializer. + */ +impl<'de> Deserialize<'de> for DateTime { + fn deserialize(deserializer: D) -> Result + where + D: serde::de::Deserializer<'de>, + { + Ok(deserializer.deserialize_str(DateTimeVisitor)?) + } +} + +struct DateTimeVisitor; + +impl<'de> serde::de::Visitor<'de> for DateTimeVisitor { + type Value = DateTime; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "a date and time formatted string") + } + + fn visit_str(self, s: &str) -> Result + where + E: serde::de::Error, + { + let datetime = if s == "0000-00-00 00:00:00" { + None + } else { + Some(NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S") + .map_err(|_| E::custom(format!("invalid date time format: {}", s)))?) + }; + + Ok(Self::Value{ datetime }) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_deserialize_datetime() { + let tests = vec![ + r#""0000-00-00 00:00:00""#, + r#""2016-12-17 13:37:00""#, + ]; + + for test in tests { + let datetime: DateTime = serde_json::from_str(test).unwrap(); + assert_eq!(test.trim_matches('"'), datetime.to_string()); + } + } +} diff --git a/src/stream/streamitem.rs b/src/stream/streamitem.rs index 1934dfe..514cae3 100644 --- a/src/stream/streamitem.rs +++ b/src/stream/streamitem.rs @@ -7,6 +7,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ +use super::datetime::DateTime; use super::verb::Verb; use serde::Deserialize; @@ -32,6 +33,16 @@ pub struct StreamItem { pub item_type: StreamItemType, pub encoding: StreamItemEncoding, + /* + * Date and time fields for when the item was + * created, last edited or commented, as well as + * when/if it expires. + */ + pub created: DateTime, + pub edited: DateTime, + pub expires: DateTime, + pub commented: DateTime, + pub verb: Verb, pub title: String, -- cgit v1.2.3