support customized metadata
parent
4995de8372
commit
8fe31281f0
87
src/sn.rs
87
src/sn.rs
|
@ -72,6 +72,72 @@ async fn get_actions(_req: Request, url: Url) -> MyResult<Response> {
|
|||
).internal_err()
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CustomMetadata {
|
||||
url: Option<String>,
|
||||
timestamp: Option<String> // Should be something `js_sys::Date::parse` could handle
|
||||
}
|
||||
|
||||
struct Metadata {
|
||||
url: String,
|
||||
has_custom_url: bool,
|
||||
timestamp: u64, // Seconds
|
||||
has_custom_timestamp: bool
|
||||
}
|
||||
|
||||
// You can customize metadata by adding something like
|
||||
//
|
||||
// ```json
|
||||
// {
|
||||
// "url": "xxx-xxx-xxx",
|
||||
// "timestamp": "YYYY-mm-dd"
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// to the beginning of your article
|
||||
// Normally when you update a post, the timestamp and URL will not be updated,
|
||||
// but when you have custom metadata, they will always be updated.
|
||||
// When the URL is updated, the old URL will automatically 301 to the new one
|
||||
fn parse_custom_metadata_from_content(text: String) -> (Option<CustomMetadata>, String) {
|
||||
if !text.starts_with("```json\n") {
|
||||
(None, text)
|
||||
} else {
|
||||
match text.find("```\n\n") {
|
||||
None => (None, text),
|
||||
Some(pos) => {
|
||||
let json = serde_json::from_str(&text[8..pos]).ok();
|
||||
return (json, text[pos + 5..].to_owned())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate metadata from uuid and title
|
||||
// Fill in default value if custom value not present
|
||||
fn build_metadata(custom: Option<CustomMetadata>, uuid: &str, title: &str) -> Metadata {
|
||||
// Default values
|
||||
let mut ret = Metadata {
|
||||
url: title_to_url(&uuid, &title),
|
||||
has_custom_url: false,
|
||||
timestamp: Date::now() as u64 / 1000, // Seconds
|
||||
has_custom_timestamp: false
|
||||
};
|
||||
|
||||
if let Some(custom) = custom {
|
||||
if let Some(url) = custom.url {
|
||||
ret.url = url;
|
||||
ret.has_custom_url = true;
|
||||
}
|
||||
|
||||
if let Some(date) = custom.timestamp {
|
||||
ret.timestamp = Date::parse(&date) as u64 / 1000; // Seconds
|
||||
ret.has_custom_timestamp = true;
|
||||
}
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
async fn create_or_update_post(req: Request, url: Url) -> MyResult<Response> {
|
||||
verify_secret!(url, params);
|
||||
if req.method() != "POST" {
|
||||
|
@ -88,27 +154,34 @@ async fn create_or_update_post(req: Request, url: Url) -> MyResult<Response> {
|
|||
return Err(Error::BadRequest("At least one item must be supplied".into()));
|
||||
}
|
||||
|
||||
// TODO: we should support customizing timestamp and URL from text
|
||||
// and if there are option detected in text, it always overrides
|
||||
// whatever was stored before
|
||||
// If the URL is changed via this way, we should make sure the old
|
||||
// URL actually 301's to the new URL
|
||||
let uuid = data.items[0].uuid.clone();
|
||||
let text = data.items[0].content.text.clone();
|
||||
let title = data.items[0].content.title.clone();
|
||||
let (custom_metadata, text) = parse_custom_metadata_from_content(text);
|
||||
let metadata = build_metadata(custom_metadata, &uuid, &title);
|
||||
let post = match blog::Post::find_by_uuid(&uuid).await {
|
||||
Ok(mut post) => {
|
||||
post.content = text;
|
||||
post.title = title;
|
||||
|
||||
// Update metadata if custom ones are present
|
||||
if metadata.has_custom_url {
|
||||
post.url = metadata.url;
|
||||
}
|
||||
|
||||
if metadata.has_custom_timestamp {
|
||||
post.timestamp = metadata.timestamp;
|
||||
}
|
||||
|
||||
post
|
||||
},
|
||||
Err(_) => {
|
||||
blog::Post {
|
||||
url: title_to_url(&uuid, &title),
|
||||
url: metadata.url,
|
||||
uuid: uuid,
|
||||
title: title,
|
||||
content: text,
|
||||
timestamp: Date::now() as u64 / 1000 // Seconds
|
||||
timestamp: metadata.timestamp
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue