Add vote_exists and additional delete/get vote count handler
This commit is contained in:
parent
f81b29c5e9
commit
c77e58f21b
4 changed files with 90 additions and 10 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct CreateVoteRequest {}
|
pub struct VotesAndDidVote {
|
||||||
|
pub vote_count: i64,
|
||||||
#[derive(Serialize)]
|
pub voted: bool,
|
||||||
pub struct VoteResponse {}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,26 @@
|
||||||
use axum::{
|
use axum::{
|
||||||
Router,
|
Json, Router,
|
||||||
extract::{Path, State},
|
extract::{Path, State},
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
routing::post,
|
routing::{delete, get, post},
|
||||||
};
|
};
|
||||||
use axum_extra::extract::{CookieJar, cookie::Cookie};
|
use axum_extra::extract::{CookieJar, cookie::Cookie};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{state::AppState, votes::repository::insert_new_vote};
|
use crate::{
|
||||||
|
state::AppState,
|
||||||
|
votes::{
|
||||||
|
repository::{delete_vote, insert_new_vote},
|
||||||
|
service::get_votes_and_voted,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
pub fn router() -> Router<AppState> {
|
pub fn router() -> Router<AppState> {
|
||||||
Router::new().route("/posts/{slug}/vote", post(upvote_handler))
|
Router::new()
|
||||||
|
.route("/posts/{slug}/vote", post(upvote_handler))
|
||||||
|
.route("/posts/{slug}/vote", delete(downvote_handler))
|
||||||
|
.route("/posts/{slug}/votes", get(get_votes_and_voted_handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_or_init_voter_id(jar: CookieJar) -> (CookieJar, Uuid) {
|
fn get_or_init_voter_id(jar: CookieJar) -> (CookieJar, Uuid) {
|
||||||
|
|
@ -51,6 +60,37 @@ async fn upvote_handler(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn downvote_handler(
|
||||||
|
jar: CookieJar,
|
||||||
|
Path(slug): Path<String>,
|
||||||
|
State(state): State<AppState>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let (jar, voter_id) = get_or_init_voter_id(jar);
|
||||||
|
|
||||||
|
match delete_vote(&slug, &voter_id, &state.db).await {
|
||||||
|
Ok(()) => (StatusCode::OK, jar, "Successfully upvoted"),
|
||||||
|
Err(err) => {
|
||||||
|
println!("{err}");
|
||||||
|
(StatusCode::INTERNAL_SERVER_ERROR, jar, "Failed to upvote")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_votes_and_voted_handler(
|
||||||
|
jar: CookieJar,
|
||||||
|
Path(slug): Path<String>,
|
||||||
|
State(state): State<AppState>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let (jar, voter_id) = get_or_init_voter_id(jar);
|
||||||
|
match get_votes_and_voted(&slug, &voter_id, &state.db).await {
|
||||||
|
Ok(votes_and_voted) => (StatusCode::OK, jar, Json(votes_and_voted)).into_response(),
|
||||||
|
Err(err) => {
|
||||||
|
println!("{err}");
|
||||||
|
(StatusCode::INTERNAL_SERVER_ERROR, jar, "Failed to upvote").into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use axum::{
|
use axum::{
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,4 @@ pub mod dto;
|
||||||
pub mod handlers;
|
pub mod handlers;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
pub mod repository;
|
pub mod repository;
|
||||||
|
pub mod service;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,14 @@ use uuid::Uuid;
|
||||||
|
|
||||||
use crate::votes::model::BestSlugs;
|
use crate::votes::model::BestSlugs;
|
||||||
|
|
||||||
|
pub async fn vote_exists(slug: &str, voter_id: &Uuid, db: &PgPool) -> Result<bool> {
|
||||||
|
let count: i64 = query_scalar("select count(*) from votes where slug=$1 and voter_id=$2")
|
||||||
|
.bind(slug)
|
||||||
|
.bind(voter_id)
|
||||||
|
.fetch_one(db)
|
||||||
|
.await?;
|
||||||
|
Ok(count > 0)
|
||||||
|
}
|
||||||
pub async fn insert_new_vote(slug: &str, voter_id: &Uuid, db: &PgPool) -> Result<()> {
|
pub async fn insert_new_vote(slug: &str, voter_id: &Uuid, db: &PgPool) -> Result<()> {
|
||||||
query(
|
query(
|
||||||
r#"insert into votes (slug, voter_id)
|
r#"insert into votes (slug, voter_id)
|
||||||
|
|
@ -61,7 +69,7 @@ mod postgres_tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
test_helpers::db::test_pool,
|
test_helpers::db::test_pool,
|
||||||
votes::repository::{
|
votes::repository::{
|
||||||
delete_vote, get_top_n_slugs, get_vote_count_for_slug, insert_new_vote,
|
delete_vote, get_top_n_slugs, get_vote_count_for_slug, insert_new_vote, vote_exists,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -230,4 +238,35 @@ mod postgres_tests {
|
||||||
|
|
||||||
cleanup(&db, &votes).await;
|
cleanup(&db, &votes).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
pub async fn vote_exists_test() {
|
||||||
|
let db = test_pool().await;
|
||||||
|
let votes = vec![
|
||||||
|
(
|
||||||
|
"vote_exists_test_blog_post1".to_string(),
|
||||||
|
Uuid::from_u128(0x1),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"vote_exists_test_blog_post2".to_string(),
|
||||||
|
Uuid::from_u128(0x2),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"vote_exists_test_blog_post3".to_string(),
|
||||||
|
Uuid::from_u128(0x3),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
cleanup(&db, &votes).await;
|
||||||
|
|
||||||
|
insert_new_vote(&votes[0].0, &votes[0].1, &db)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
insert_new_vote(&votes[1].0, &votes[1].1, &db)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(vote_exists(&votes[0].0, &votes[0].1, &db).await.unwrap());
|
||||||
|
assert!(vote_exists(&votes[1].0, &votes[1].1, &db).await.unwrap());
|
||||||
|
assert!(!vote_exists(&votes[2].0, &votes[2].1, &db).await.unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue