Add Gravatar email hashes
This commit is contained in:
parent
bbebe8b119
commit
82e70178d5
5 changed files with 102 additions and 12 deletions
29
Cargo.lock
generated
29
Cargo.lock
generated
|
@ -589,6 +589,12 @@ version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
|
checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.126"
|
version = "0.2.126"
|
||||||
|
@ -648,6 +654,12 @@ version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "md5"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
@ -971,9 +983,11 @@ name = "soudan"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-web",
|
"actix-web",
|
||||||
|
"md5",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"validator",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1112,6 +1126,21 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "validator"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f07b0a1390e01c0fc35ebb26b28ced33c9a3808f7f9fbe94d3cc01e233bfeed5"
|
||||||
|
dependencies = [
|
||||||
|
"idna",
|
||||||
|
"lazy_static",
|
||||||
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
|
|
@ -10,3 +10,5 @@ actix-web = "4"
|
||||||
rusqlite = "0.27.0"
|
rusqlite = "0.27.0"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
validator = "0.15.0"
|
||||||
|
md5 = "0.7.0"
|
||||||
|
|
|
@ -1,7 +1,48 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
// Master comment type that is stored in database
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct Comment {
|
pub struct Comment {
|
||||||
pub author: Option<String>, // None/null is Anonymous
|
pub author: Option<String>, // None/null is Anonymous
|
||||||
|
pub email: Option<String>,
|
||||||
pub text: String
|
pub text: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comment type for API responses
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct CommentSend {
|
||||||
|
pub author: Option<String>,
|
||||||
|
pub gravatar: Option<String>,
|
||||||
|
pub text: String
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comment type received containing new comment data
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct CommentReceive {
|
||||||
|
pub author: Option<String>,
|
||||||
|
pub email: Option<String>,
|
||||||
|
pub text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommentReceive {
|
||||||
|
pub fn to_master(&self) -> Comment {
|
||||||
|
Comment {
|
||||||
|
author: self.author.clone(),
|
||||||
|
email: self.email.clone(),
|
||||||
|
text: self.text.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use rusqlite::{params, Connection, Result};
|
use rusqlite::{params, Connection, Result};
|
||||||
use crate::comment::Comment;
|
use crate::comment::{Comment, CommentSend};
|
||||||
|
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
conn: Connection,
|
conn: Connection,
|
||||||
|
@ -11,6 +11,7 @@ impl Database {
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"CREATE TABLE comment (
|
"CREATE TABLE comment (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
|
email TEXT,
|
||||||
author TEXT,
|
author TEXT,
|
||||||
text TEXT NOT NULL
|
text TEXT NOT NULL
|
||||||
)",
|
)",
|
||||||
|
@ -21,11 +22,28 @@ impl Database {
|
||||||
|
|
||||||
pub fn get_comments(&self) -> Result<Vec<Comment>> {
|
pub fn get_comments(&self) -> Result<Vec<Comment>> {
|
||||||
self.conn
|
self.conn
|
||||||
.prepare("SELECT author, text FROM comment")?
|
.prepare("SELECT author, email, text FROM comment")?
|
||||||
.query_map([], |row| {
|
.query_map([], |row| {
|
||||||
Ok(Comment {
|
Ok(Comment {
|
||||||
author: row.get(0)?,
|
author: row.get(0)?,
|
||||||
text: row.get(1)?,
|
email: row.get(1)?,
|
||||||
|
text: row.get(2)?,
|
||||||
|
})
|
||||||
|
})?
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_send_comments(&self) -> Result<Vec<CommentSend>> {
|
||||||
|
self.conn
|
||||||
|
.prepare("SELECT author, email, text FROM comment")?
|
||||||
|
.query_map([], |row| {
|
||||||
|
Ok(CommentSend {
|
||||||
|
author: row.get(0)?,
|
||||||
|
gravatar: match row.get::<usize, Option<String>>(1)? {
|
||||||
|
Some(email) => Some(format!("{:x}", md5::compute(email.to_lowercase()))),
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
text: row.get(2)?,
|
||||||
})
|
})
|
||||||
})?
|
})?
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -33,8 +51,8 @@ impl Database {
|
||||||
|
|
||||||
pub fn create_comment(&self, comment: &Comment) -> Result<()> {
|
pub fn create_comment(&self, comment: &Comment) -> Result<()> {
|
||||||
self.conn.execute(
|
self.conn.execute(
|
||||||
"INSERT INTO comment (author, text) VALUES (?1, ?2)",
|
"INSERT INTO comment (author, email, text) VALUES (?1, ?2, ?3)",
|
||||||
params![&comment.author, &comment.text],
|
params![&comment.author, &comment.email, &comment.text],
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -1,5 +1,5 @@
|
||||||
mod comment;
|
mod comment;
|
||||||
pub use comment::Comment;
|
pub use comment::*;
|
||||||
|
|
||||||
mod database;
|
mod database;
|
||||||
pub use database::Database;
|
pub use database::Database;
|
||||||
|
@ -14,22 +14,22 @@ struct AppState {
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
async fn get_comments(data: web::Data<AppState>) -> impl Responder {
|
async fn get_comments(data: web::Data<AppState>) -> impl Responder {
|
||||||
let db = &data.db.lock().unwrap();
|
let db = &data.db.lock().unwrap();
|
||||||
HttpResponse::Ok().json(&db.get_comments().unwrap())
|
HttpResponse::Ok().json(&db.get_send_comments().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/")]
|
#[post("/")]
|
||||||
async fn post_comments(data: web::Data<AppState>, bytes: web::Bytes) -> impl Responder {
|
async fn post_comment(data: web::Data<AppState>, bytes: web::Bytes) -> impl Responder {
|
||||||
match String::from_utf8(bytes.to_vec()) {
|
match String::from_utf8(bytes.to_vec()) {
|
||||||
Ok(text) => {
|
Ok(text) => {
|
||||||
let db = match data.db.lock() {
|
let db = match data.db.lock() {
|
||||||
Ok(db) => db,
|
Ok(db) => db,
|
||||||
Err(_) => return HttpResponse::InternalServerError(),
|
Err(_) => return HttpResponse::InternalServerError(),
|
||||||
};
|
};
|
||||||
let comment: Comment = match serde_json::from_str(&text) {
|
let comment: CommentReceive = match serde_json::from_str(&text) {
|
||||||
Ok(comment) => comment,
|
Ok(comment) => comment,
|
||||||
Err(_) => return HttpResponse::BadRequest(),
|
Err(_) => return HttpResponse::BadRequest(),
|
||||||
};
|
};
|
||||||
db.create_comment(&comment).unwrap();
|
db.create_comment(&comment.to_master()).unwrap();
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
},
|
},
|
||||||
Err(_) => HttpResponse::BadRequest().into()
|
Err(_) => HttpResponse::BadRequest().into()
|
||||||
|
@ -43,7 +43,7 @@ async fn main() -> Result<(), std::io::Error> {
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
.service(get_comments)
|
.service(get_comments)
|
||||||
.service(post_comments)
|
.service(post_comment)
|
||||||
.app_data(state.clone())
|
.app_data(state.clone())
|
||||||
})
|
})
|
||||||
.bind(("127.0.0.1", 8080))?
|
.bind(("127.0.0.1", 8080))?
|
||||||
|
|
Loading…
Add table
Reference in a new issue