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