Refactor comment serialization/deserialization
This commit is contained in:
parent
f153625d1a
commit
6419b6357c
5 changed files with 30 additions and 58 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -324,6 +324,7 @@ dependencies = [
|
|||
"libc",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"time 0.1.44",
|
||||
"winapi",
|
||||
]
|
||||
|
|
|
@ -13,4 +13,4 @@ serde = { version = "1", features = ["derive"] }
|
|||
serde_json = "1"
|
||||
validator = { version = "0.15.0", features = ["derive"] }
|
||||
md5 = "0.7.0"
|
||||
chrono = "0.4.19"
|
||||
chrono = { version = "0.4.19", features = ["serde"] }
|
||||
|
|
|
@ -1,54 +1,31 @@
|
|||
use chrono::NaiveDateTime;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use chrono::serde::ts_seconds_option;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
use validator::Validate;
|
||||
|
||||
// Master comment type that is stored in database
|
||||
#[derive(Serialize, Deserialize, Validate)]
|
||||
pub struct Comment {
|
||||
pub author: Option<String>, // None/null is Anonymous
|
||||
pub email: Option<String>,
|
||||
pub text: String,
|
||||
pub timestamp: Option<NaiveDateTime>,
|
||||
}
|
||||
|
||||
impl Comment {
|
||||
pub fn send(&self) -> CommentSend {
|
||||
CommentSend {
|
||||
author: self.author.clone(),
|
||||
gravatar: match self.email.clone() {
|
||||
Some(email) => Some(format!("{:x}", md5::compute(email.to_lowercase()))),
|
||||
None => None,
|
||||
},
|
||||
text: self.text.clone(),
|
||||
timestamp: self.timestamp.unwrap().timestamp(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Comment type for API responses
|
||||
#[derive(Serialize)]
|
||||
pub struct CommentSend {
|
||||
pub author: Option<String>,
|
||||
pub gravatar: Option<String>,
|
||||
pub text: String,
|
||||
pub timestamp: i64,
|
||||
}
|
||||
|
||||
// Comment type received containing new comment data
|
||||
#[derive(Deserialize, Validate)]
|
||||
pub struct CommentReceive {
|
||||
pub author: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub author: Option<String>, // None is Anonymous
|
||||
#[serde(rename(serialize = "gravatar"))]
|
||||
#[serde(serialize_with = "serialize_gravatar")]
|
||||
#[validate(email)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub email: Option<String>,
|
||||
#[validate(length(min = 1))]
|
||||
pub text: String,
|
||||
#[serde(default)]
|
||||
#[serde(with = "ts_seconds_option")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub timestamp: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl CommentReceive {
|
||||
pub fn to_master(&self) -> Comment {
|
||||
Comment {
|
||||
author: self.author.clone(),
|
||||
email: self.email.clone(),
|
||||
text: self.text.clone(),
|
||||
timestamp: None,
|
||||
}
|
||||
fn serialize_gravatar<S>(email: &Option<String>, s: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
match email {
|
||||
Some(email) => s.serialize_some(&format!("{:x}", md5::compute(email.to_lowercase()))),
|
||||
None => s.serialize_none(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::comment::{Comment, CommentSend};
|
||||
use chrono::NaiveDateTime;
|
||||
use crate::Comment;
|
||||
use rusqlite::{params, Connection, Result};
|
||||
|
||||
pub struct Database {
|
||||
|
@ -25,20 +24,15 @@ impl Database {
|
|||
Ok(Self { conn })
|
||||
}
|
||||
|
||||
pub fn get_send_comments(&self) -> Result<Vec<CommentSend>> {
|
||||
pub fn get_comments(&self) -> Result<Vec<Comment>> {
|
||||
self.conn
|
||||
.prepare("SELECT author, email, text, timestamp FROM comment ORDER BY timestamp DESC")?
|
||||
.query_map([], |row| {
|
||||
let timestamp: NaiveDateTime = row.get(3)?;
|
||||
let timestamp = timestamp.timestamp();
|
||||
Ok(CommentSend {
|
||||
Ok(Comment {
|
||||
author: row.get(0)?,
|
||||
gravatar: match row.get::<usize, Option<String>>(1)? {
|
||||
Some(email) => Some(format!("{:x}", md5::compute(email.to_lowercase()))),
|
||||
None => None,
|
||||
},
|
||||
email: row.get(1)?,
|
||||
text: row.get(2)?,
|
||||
timestamp: timestamp,
|
||||
timestamp: row.get(3)?,
|
||||
})
|
||||
})?
|
||||
.collect()
|
||||
|
|
|
@ -19,7 +19,7 @@ async fn get_comments(data: web::Data<AppState>) -> impl Responder {
|
|||
Ok(db) => db,
|
||||
Err(_) => return HttpResponse::InternalServerError().into(),
|
||||
};
|
||||
HttpResponse::Ok().json(&db.get_send_comments().unwrap())
|
||||
HttpResponse::Ok().json(&db.get_comments().unwrap())
|
||||
}
|
||||
|
||||
#[post("/")]
|
||||
|
@ -30,14 +30,14 @@ async fn post_comment(data: web::Data<AppState>, bytes: web::Bytes) -> impl Resp
|
|||
Ok(db) => db,
|
||||
Err(_) => return HttpResponse::InternalServerError(),
|
||||
};
|
||||
let comment: CommentReceive = match serde_json::from_str(&text) {
|
||||
let comment: Comment = match serde_json::from_str(&text) {
|
||||
Ok(comment) => comment,
|
||||
Err(_) => return HttpResponse::BadRequest(),
|
||||
};
|
||||
if comment.validate().is_err() {
|
||||
return HttpResponse::BadRequest();
|
||||
}
|
||||
db.create_comment(&comment.to_master()).unwrap();
|
||||
db.create_comment(&comment).unwrap();
|
||||
HttpResponse::Ok()
|
||||
}
|
||||
Err(_) => HttpResponse::BadRequest().into(),
|
||||
|
|
Loading…
Add table
Reference in a new issue