aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--src/stream.rs2
-rw-r--r--src/stream/datetime.rs93
-rw-r--r--src/stream/streamitem.rs11
4 files changed, 107 insertions, 0 deletions
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 <haraldei@anduin.net>
+ *
+ * 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<NaiveDateTime>
+}
+
+/*
+ * 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<D>(deserializer: D) -> Result<Self, D::Error>
+ 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<E>(self, s: &str) -> Result<Self::Value, E>
+ 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,