mirror of
https://github.com/Lumither/nocturne.git
synced 2026-10-17 10:26:21 +00:00
feat(blog::components::check_update) impl handle_create()
This commit is contained in:
10 files changed
+202
-17
No files matched your search
@@ -1,2 +1,3 @@
|
||||
pub const DEFAULT_TIME_FORMAT: &str = "%Y-%m-%dT%H:%M:%S%z";
|
||||
pub const DEFAULT_DATE_FORMAT: &str = "%Y-%m-%d%zT%H%M%S";
|
||||
|
||||
pub const DEFAULT_NAIVE_DATE_FORMAT: &str = "%Y-%m-%d";
|
||||
@@ -1,12 +1,23 @@
|
||||
use crate::modules::blog::components::check_update::changes::{
|
||||
Change, Create, Delete, Move, Update,
|
||||
use crate::modules::blog::components::check_update::{
|
||||
changes::{Change, Create, Delete, Move, Update},
|
||||
error::Error,
|
||||
utils::{parse_naive_date_str, parse_post_identifier},
|
||||
};
|
||||
use macros::dev_consume;
|
||||
|
||||
use futures::{
|
||||
future::{join_all, BoxFuture},
|
||||
FutureExt,
|
||||
future::{BoxFuture, join_all},
|
||||
};
|
||||
use sqlx::PgPool;
|
||||
use sqlx::{query, PgPool, Postgres, Row, Transaction};
|
||||
use tracing::error;
|
||||
|
||||
const DELETE_POST_BY_ID: &str = include_str!("sql/delete_post_by_id.sql");
|
||||
const GET_TAG_ID: &str = include_str!("sql/get_tag_id.sql");
|
||||
const GET_CATEGORY_ID: &str = include_str!("sql/get_category_id.sql");
|
||||
const CREATE_RETURN_TAG_ID: &str = include_str!("sql/create_return_tag_id.sql");
|
||||
const CREATE_RETURN_CATEGORY_ID: &str = include_str!("sql/create_return_category_id.sql");
|
||||
const CREATE_POST: &str = include_str!("sql/create_post.sql");
|
||||
|
||||
pub async fn apply_deltas(db_conn: &PgPool, changes: Vec<Change>) {
|
||||
let handlers = changes
|
||||
@@ -23,17 +34,148 @@ pub async fn apply_deltas(db_conn: &PgPool, changes: Vec<Change>) {
|
||||
}
|
||||
|
||||
async fn handle_delete(db: &PgPool, del: Delete) {
|
||||
todo!()
|
||||
if let Err(e) = query(DELETE_POST_BY_ID).bind(del.uuid).execute(db).await {
|
||||
error!(
|
||||
"failed to delete post: {}, {}",
|
||||
del.uuid.to_string(),
|
||||
e.to_string()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_move(db: &PgPool, mv: Move) {
|
||||
let identifier = parse_post_identifier(&mv.to).unwrap();
|
||||
|
||||
dev_consume!(db, mv, identifier);
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn handle_update(db: &PgPool, update: Update) {
|
||||
dev_consume!(db, update);
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn handle_create(db: &PgPool, create: Create) {
|
||||
todo!()
|
||||
let mut tx = db.begin().await.unwrap();
|
||||
|
||||
let identifier = parse_post_identifier(&create.path).unwrap();
|
||||
|
||||
let tags_json = create.payload.meta["tags"].clone();
|
||||
let tags: Vec<_> = if let Some(tags) = tags_json.as_array() {
|
||||
tags.iter().filter_map(|tag| tag.as_str()).collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
let mut tag_ids = vec![];
|
||||
for tag in tags {
|
||||
match get_or_create_tag_id(&mut tx, tag).await {
|
||||
Ok(tid) => tag_ids.push(tid),
|
||||
Err(e) => {
|
||||
error!("failed to fetch or create tag ({}): {}", tag, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let category_json = create.payload.meta["category"].clone();
|
||||
let category = category_json.as_str().unwrap_or("Uncategorized");
|
||||
let category_id = match get_or_create_category_id(&mut tx, category).await {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
error!(
|
||||
"failed to fetch category id for post {}: {}",
|
||||
&identifier, e
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let meta = create.payload.meta;
|
||||
let post_id = create.uuid;
|
||||
let post_identifier = &identifier;
|
||||
let post_title = meta
|
||||
.get("title")
|
||||
.map(|t| t.as_str().unwrap())
|
||||
.unwrap_or("Untitled");
|
||||
let post_subtitle = meta
|
||||
.get("sub_title")
|
||||
.map(|t| t.as_str().unwrap())
|
||||
.unwrap_or("");
|
||||
let post_date_created = if let Some(Some(date)) = meta
|
||||
.get("date")
|
||||
.map(|d| parse_naive_date_str(d.as_str().unwrap_or("")))
|
||||
{
|
||||
date
|
||||
} else {
|
||||
error!("failed to parse `date` for post: {}", post_identifier);
|
||||
return;
|
||||
};
|
||||
let post_date_updated = meta
|
||||
.get("update")
|
||||
.map(|d| parse_naive_date_str(d.as_str().unwrap_or("")))
|
||||
.unwrap_or(None);
|
||||
let post_status = meta.get("status").map(|v| v.as_str()).unwrap_or(None);
|
||||
let post_content = create.payload.content;
|
||||
|
||||
if let Err(e) = query(CREATE_POST)
|
||||
.bind(post_id)
|
||||
.bind(post_identifier)
|
||||
.bind(post_title)
|
||||
.bind(post_subtitle)
|
||||
.bind(post_date_created)
|
||||
.bind(post_date_updated)
|
||||
.bind(post_status)
|
||||
.bind(post_content)
|
||||
.bind(category_id)
|
||||
.bind(tag_ids)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
{
|
||||
error!("failed to insert post {}: {}", &identifier, e);
|
||||
return;
|
||||
}
|
||||
|
||||
tx.commit().await.unwrap();
|
||||
}
|
||||
|
||||
async fn get_or_create_tag_id(
|
||||
db: &mut Transaction<'_, Postgres>,
|
||||
tag_name: &str,
|
||||
) -> Result<i32, Error> {
|
||||
get_create_id(db, tag_name, GET_TAG_ID, CREATE_RETURN_TAG_ID).await
|
||||
}
|
||||
|
||||
async fn get_or_create_category_id(
|
||||
db: &mut Transaction<'_, Postgres>,
|
||||
category_name: &str,
|
||||
) -> Result<i32, Error> {
|
||||
get_create_id(
|
||||
db,
|
||||
category_name,
|
||||
GET_CATEGORY_ID,
|
||||
CREATE_RETURN_CATEGORY_ID,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_create_id(
|
||||
db: &mut Transaction<'_, Postgres>,
|
||||
field_name: &str,
|
||||
fetch_query: &str,
|
||||
create_fetch_query: &str,
|
||||
) -> Result<i32, Error> {
|
||||
if let Some(id) = query(fetch_query)
|
||||
.bind(field_name)
|
||||
.fetch_optional(&mut **db)
|
||||
.await?
|
||||
{
|
||||
Ok(id.get("id"))
|
||||
} else {
|
||||
let id = query(create_fetch_query)
|
||||
.bind(field_name)
|
||||
.fetch_one(&mut **db)
|
||||
.await?
|
||||
.get("id");
|
||||
Ok(id)
|
||||
}
|
||||
}
|
||||
@@ -6,15 +6,15 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
constants::config::general::{default_value, var_name},
|
||||
modules::blog::components::check_update::{pull::fetch_deltas, utils::expand_path},
|
||||
modules::blog::components::check_update::{
|
||||
apply::apply_deltas, pull::fetch_deltas, utils::expand_path,
|
||||
},
|
||||
scheduler::task_func::AsyncTaskFunc,
|
||||
};
|
||||
use macros::panic_with_log;
|
||||
|
||||
use crate::modules::blog::components::check_update::apply::apply_deltas;
|
||||
use sqlx::PgPool;
|
||||
use tracing::log::error;
|
||||
use tracing::{Level, trace, warn};
|
||||
use tracing::{log::error, trace, warn, Level};
|
||||
|
||||
// mod error;
|
||||
// mod index;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
INSERT INTO posts
|
||||
(id, identifier, title, subtitle, date_created, date_updated, status, content, category)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9);
|
||||
|
||||
INSERT INTO post_tag (post, tag)
|
||||
SELECT $1, tag
|
||||
FROM UNNEST($10) AS t(tag);
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
INSERT INTO categories(name)
|
||||
VALUES ($1)
|
||||
RETURNING id;
|
||||
@@ -0,0 +1,3 @@
|
||||
INSERT INTO tags(name)
|
||||
VALUES ($1)
|
||||
RETURNING id;
|
||||
@@ -0,0 +1,3 @@
|
||||
SELECT id
|
||||
FROM categories
|
||||
WHERE name = $1;
|
||||
@@ -0,0 +1,3 @@
|
||||
SELECT id
|
||||
FROM tags
|
||||
WHERE name = $1;
|
||||
@@ -1,10 +1,11 @@
|
||||
use std::path::Path;
|
||||
|
||||
use crate::constants::{
|
||||
config::general::{default_value, var_name},
|
||||
time::DEFAULT_DATE_FORMAT,
|
||||
time::DEFAULT_NAIVE_DATE_FORMAT,
|
||||
};
|
||||
|
||||
// use crate::modules::blog::components::check_update::index::index_file;
|
||||
use chrono::{DateTime, FixedOffset, ParseResult};
|
||||
use chrono::NaiveDate;
|
||||
use dirs::home_dir;
|
||||
use tracing::warn;
|
||||
|
||||
@@ -30,6 +31,28 @@ pub fn expand_path(path: String) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_date(date_str: &str) -> ParseResult<DateTime<FixedOffset>> {
|
||||
DateTime::parse_from_str(format!("{}T120000", date_str).as_str(), DEFAULT_DATE_FORMAT)
|
||||
pub fn parse_post_identifier(path: &Path) -> Option<String> {
|
||||
if let Some(comp) = path.components().nth_back(1) {
|
||||
comp.as_os_str().to_str().map(|s| s.to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_naive_date_str(date_str: &str) -> Option<NaiveDate> {
|
||||
NaiveDate::parse_from_str(date_str, DEFAULT_NAIVE_DATE_FORMAT).ok()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::modules::blog::components::check_update::utils::parse_naive_date_str;
|
||||
use chrono::NaiveDate;
|
||||
|
||||
#[test]
|
||||
fn test_parse_naive_date() {
|
||||
assert_eq!(
|
||||
Some(NaiveDate::from_ymd(2015, 1, 1)),
|
||||
parse_naive_date_str("2015-1-01")
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user