Keep track of creation&modification times

This commit is contained in:
Dawid Ciężarkiewicz 2020-05-15 00:56:07 -07:00
parent 6b0d80937a
commit 2e564195be
6 changed files with 114 additions and 29 deletions

31
Cargo.lock generated
View File

@ -143,6 +143,17 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "chrono"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2"
dependencies = [
"num-integer",
"num-traits",
"time",
]
[[package]]
name = "clap"
version = "2.33.0"
@ -683,6 +694,25 @@ dependencies = [
"winapi 0.3.8",
]
[[package]]
name = "num-integer"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
dependencies = [
"autocfg 1.0.0",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
dependencies = [
"autocfg 1.0.0",
]
[[package]]
name = "opaque-debug"
version = "0.2.3"
@ -1197,6 +1227,7 @@ dependencies = [
"anyhow",
"async-trait",
"blake2",
"chrono",
"digest",
"env_logger",
"hex",

View File

@ -33,3 +33,4 @@ async-trait = "0.1.30"
serde = "*"
serde_derive = "*"
horrorshow = "*"
chrono = "*"

View File

@ -173,7 +173,9 @@ async fn handle_post(
};
let page = write.get(post_id.to_owned()).await?;
let page = page.with_new_source_body(&get_rid_of_windows_newlines(form.get_body()?.to_owned()));
let mut page =
page.with_new_source_body(&get_rid_of_windows_newlines(form.get_body()?.to_owned()));
page.update_modification_time();
write.put(&page).await?;

View File

@ -1,7 +1,9 @@
pub mod store;
use crate::util;
#[allow(unused)]
use anyhow::Result;
use chrono::prelude::*;
use lazy_static::lazy_static;
use std::collections::HashSet;
pub use store::{InMemoryStore, Store, StoreMut};
@ -14,11 +16,13 @@ pub type TagRef<'a> = &'a str;
pub type IdRef<'a> = &'a str;
const TAGWIKI_PAGE_ID_KEY: &str = "tagwiki-page-id";
const TAGWIKI_CREATION_TIME_KEY: &str = "tagwiki-creation-time";
const TAGWIKI_MODIFICATION_TIME_KEY: &str = "tagwiki-modification-time";
#[derive(Debug, Default, Clone)]
pub struct Source(String);
#[derive(Debug, Default, Clone)]
#[derive(Debug, Clone)]
pub struct Parsed {
pub source: Source,
pub source_body: String,
@ -50,18 +54,33 @@ fn split_headers_and_body(source: &Source) -> (&str, &str) {
}
}
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone)]
pub struct Headers {
pub id: String,
pub all: String,
pub creation_time: chrono::DateTime<FixedOffset>,
pub modification_time: chrono::DateTime<FixedOffset>,
pub other: String,
}
impl Default for Headers {
fn default() -> Self {
Self {
id: util::random_string(16),
creation_time: util::now(),
modification_time: util::now(),
other: "".into(),
}
}
}
impl Headers {
fn parse(headers_str: &str, source: &Source) -> Headers {
let mut id = None;
let mut creation = None;
let mut modification = None;
let mut other = String::new();
for line in headers_str.lines() {
match line.split(":").collect::<Vec<_>>().as_slice() {
match line.splitn(2, ":").collect::<Vec<_>>().as_slice() {
[key, value] => {
let key = key.trim();
let value = value.trim();
@ -69,38 +88,62 @@ impl Headers {
TAGWIKI_PAGE_ID_KEY => {
id = Some(value.to_owned());
}
_ => {}
TAGWIKI_CREATION_TIME_KEY => {
let time = chrono::DateTime::<FixedOffset>::parse_from_rfc3339(value);
creation = time.ok();
}
TAGWIKI_MODIFICATION_TIME_KEY => {
let time = chrono::DateTime::<FixedOffset>::parse_from_rfc3339(value);
modification = time.ok();
}
_ => {
other.push_str(line);
other.push_str("\n")
}
}
}
_ => {}
_ => {
other.push_str(line);
other.push_str("\n")
}
}
}
match id {
Some(id) => Self {
id,
all: headers_str.to_owned(),
},
None => {
let mut hasher = blake2::Blake2b::new();
hasher.input(&source.0);
let res = hasher.result();
let id = hex::encode(&res.as_slice()[0..16]);
let id = id.unwrap_or_else(|| {
let mut hasher = blake2::Blake2b::new();
hasher.input(&source.0);
let res = hasher.result();
hex::encode(&res.as_slice()[0..16])
});
let mut all = String::new();
all.push_str(TAGWIKI_PAGE_ID_KEY);
all.push_str(": ");
all.push_str(&id);
all.push_str("\n");
all.push_str(headers_str);
let creation: DateTime<chrono::offset::FixedOffset> =
creation.unwrap_or_else(|| util::now());
Self { id, all }
}
let modification = modification.unwrap_or_else(|| util::now());
Self {
other,
id,
creation_time: creation,
modification_time: modification,
}
}
fn to_markdown_string(&self) -> String {
"<!---\n".to_string() + &self.all + "\n-->\n"
"<!---\n".to_string()
+ &format!("{}: {}\n", TAGWIKI_PAGE_ID_KEY, self.id)
+ &format!(
"{}: {}\n",
TAGWIKI_CREATION_TIME_KEY,
self.creation_time.to_rfc3339()
)
+ &format!(
"{}: {}\n",
TAGWIKI_MODIFICATION_TIME_KEY,
self.modification_time.to_rfc3339()
)
+ &self.other
+ "-->\n"
}
}
@ -186,6 +229,10 @@ impl Parsed {
}
}
pub fn update_modification_time(&mut self) {
self.headers.modification_time = util::now();
}
pub fn with_new_source_body(&self, new_body_source: &str) -> Self {
Self::from_headers_and_body(self.headers.clone(), new_body_source.to_owned())
}

View File

@ -108,9 +108,7 @@ impl FsStore {
tokio::task::spawn_blocking(move || -> Result<()> {
let mut file = std::fs::File::create(&tmp_path)?;
file.write_all(b"<!---\n")?;
file.write_all(page.headers.all.as_bytes())?;
file.write_all(b"\n-->\n")?;
file.write_all(page.headers.to_markdown_string().as_bytes())?;
file.write_all(page.source_body.as_bytes())?;
file.flush()?;

View File

@ -7,3 +7,9 @@ pub fn random_string(len: usize) -> String {
.take(len)
.collect()
}
/// Now with a fixed offset of the current system timezone
pub fn now() -> chrono::DateTime<chrono::offset::FixedOffset> {
let date = chrono::offset::Local::now();
date.with_timezone(&date.offset())
}