comment_app_backend 0.1.0

Serves comments through Restful APIs
Documentation
use warp::Filter;
use std::collections::HashMap;

use super::handlers;
use super::models::{comment::Comment, reply::Reply, upvote::Upvote, downvote::Downvote};
use super::db::DbConn;

/// Comment filters combined
pub fn comments(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    list_comments( db_conn.clone() )
        .or( more_comments( db_conn.clone() ) )
        .or( comments_create( db_conn.clone() ) )
        .or( comments_update( db_conn.clone() ) )
        .or( comments_delete( db_conn.clone() ) )
        .or( get_comment( db_conn.clone() ) )
        .or( update_comment_status( db_conn.clone() ) )
        .or( update_comment_message( db_conn.clone() ) )
        .or( comments_total( db_conn.clone() ) )
    .or( replies_create( db_conn.clone() ) )
        .or( list_replies( db_conn.clone() ) )
        .or( replies_update( db_conn.clone() ) )
        .or( replies_delete( db_conn.clone() ) )
        .or( get_reply( db_conn.clone() ) )
        .or( update_reply_message( db_conn.clone() ) )
    //.or( get_commenter( db_conn.clone() ) )
    //    .or( get_session_user( db_conn.clone() ) )
    //.or( get_avatar() )  
        .or( upvotes_create( db_conn.clone() ) )
        .or( upvotes_delete( db_conn.clone() ) )
        .or( upvotes_total( db_conn.clone() ) )
        .or( downvotes_create( db_conn.clone() ) )
        .or( downvotes_delete( db_conn.clone() ) )
        .or( downvotes_total( db_conn.clone() ) )
}

/// GET /comments  -> get all comments
pub fn list_comments(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("comments")
        .and(warp::get())
        .and(with_db_conn(db_conn))
        .and_then(handlers::list_comments)
}

/// GET /more_comments/count  -> get all comments
pub fn more_comments(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("more_comments" / usize)
        .and(warp::get())
        .and(with_db_conn(db_conn))
        .and_then(handlers::more_comments)
}

/// POST /comments with JSON body 
pub fn comments_create(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("comments")
        .and(warp::post())
        .and(json_comment_body())
        .and(with_db_conn(db_conn))
        .and_then(handlers::add_comment)
}

/// PUT /comments/:uid with JSON body 
pub fn comments_update(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("comments" / String)
        .and(warp::put())
        .and(json_comment_body())
        .and(with_db_conn(db_conn))
        .and_then(handlers::update_comment)
}

/// PUT /comment/:status/:uid with JSON body; status are: disable, enable, trash, spam
pub fn update_comment_status(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("comment" / String / String)
        .and(warp::put())
        .and(with_db_conn(db_conn))
        .and_then(handlers::update_comment_status)
}

/// PUT /comment_message/:uid with JSON body
pub fn update_comment_message(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("comment_message" / String)
        .and(warp::put())
        .and(json_message_body())
        .and(with_db_conn(db_conn))
        .and_then(handlers::update_comment_message)
}

/// DELETE /comments/:uid
pub fn comments_delete(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    // make one of the endpoints admin-only to show how authentication filters are used
    let admin_only = warp::header::exact("authorization", "Bearer admin");
    warp::path!("comments" / String)
        // It is important to put the auth check _after_ the path filters. 
        // If we put the auth check before, the request `PUT /todos/invalid-string`
        // would try this filter and reject because the authorization header 
        // doesn't match, rather because the param is wrong for that other path. 
        .and(admin_only)
        .and(warp::delete())
        .and(with_db_conn(db_conn))
        .and_then(handlers::delete_comment)
}

/// GET /comments/:uid 
pub fn get_comment(
    db_conn: DbConn
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("comments" / String)
        .and(warp::get())
        .and(with_db_conn(db_conn))
        .and_then(handlers::get_comment)
}

fn with_db_conn(db_conn: DbConn) -> impl Filter<Extract = (DbConn,), Error = std::convert::Infallible> + Clone {
    warp::any().map(move || db_conn.clone())
}

fn json_comment_body() -> impl Filter<Extract = (Comment,), Error = warp::Rejection> + Clone {
    // When accepting a body, we want a JSON body 
    // (and to reject huge payloads)... 
    warp::body::content_length_limit(1024 * 16).and(warp::body::json()) 
}

fn json_message_body() -> impl Filter<Extract = (HashMap<String, String>,), Error = warp::Rejection> + Clone {
    warp::body::content_length_limit(1024 * 16).and(warp::body::json())
}

/// GET /comments_total  -> get total number of comments
pub fn comments_total(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("comments_total")
        .and(warp::get())
        .and(with_db_conn(db_conn))
        .and_then(handlers::comments_total)
}

/// POST /replies with JSON body 
pub fn replies_create(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("replies")
        .and(warp::post())
        .and(json_reply_body())
        .and(with_db_conn(db_conn))
        .and_then(handlers::add_reply)
}

fn json_reply_body() -> impl Filter<Extract = (Reply,), Error = warp::Rejection> + Clone {
    // When accepting a body, we want a JSON body 
    // (and to reject huge payloads)... 
    warp::body::content_length_limit(1024 * 16).and( warp::body::json() ) 
}

/// GET /replies/comment_id  -> get all replies
pub fn list_replies(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("replies" / String)
        .and(warp::get())
        .and(with_db_conn(db_conn))
        .and_then(handlers::list_replies)
}

/// PUT /replies/:uid with JSON body 
pub fn replies_update(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("replies" / String)
        .and(warp::put())
        .and(json_reply_body())
        .and(with_db_conn(db_conn))
        .and_then(handlers::update_reply)
}

/// PUT /reply_message/:uid with JSON body
pub fn update_reply_message(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("reply_message" / String)
        .and(warp::put())
        .and(json_message_body())
        .and(with_db_conn(db_conn))
        .and_then(handlers::update_reply_message)
}

/// DELETE /replies/:uid
pub fn replies_delete(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    // make one of the endpoints admin-only to show how authentication filters are used
    let admin_only = warp::header::exact("authorization", "Bearer admin");
    warp::path!("replies" / String)
        // It is important to put the auth check _after_ the path filters. 
        // If we put the auth check before, the request `PUT /todos/invalid-string`
        // would try this filter and reject because the authorization header 
        // doesn't match, rather because the param is wrong for that other path. 
        .and(admin_only)
        .and(warp::delete())
        .and(with_db_conn(db_conn))
        .and_then(handlers::delete_reply)
}

/// GET /reply/:uid 
pub fn get_reply(
    db_conn: DbConn
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("reply" / String)
        .and(warp::get())
        .and(with_db_conn(db_conn))
        .and_then(handlers::get_reply)
}

/*
/// GET /commenter/:uid 
pub fn get_commenter(
    db_conn: DbConn
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("commenter" / String)
        .and(warp::get())
        .and(with_db_conn(db_conn))
        .and_then(handlers::get_commenter)
}

/// GET /session_user 
pub fn get_session_user(
    db_conn: DbConn
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("session_user")
        .and(warp::get())
        .and(with_db_conn(db_conn))
        .and_then(handlers::get_session_user)
}

/// GET /get_avatar
pub fn get_avatar() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("avatar" / String)
        .and(warp::get())
        .and_then(handlers::get_avatar)
}
*/

/// POST /upvotes with JSON body 
pub fn upvotes_create(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("upvotes")
        .and(warp::post())
        .and(json_upvote_body())
        .and(with_db_conn(db_conn))
        .and_then(handlers::add_upvote)
}

fn json_upvote_body() -> impl Filter<Extract = (Upvote,), Error = warp::Rejection> + Clone {
    // When accepting a body, we want a JSON body 
    // (and to reject huge payloads)... 
    warp::body::content_length_limit(1024 * 16).and(warp::body::json()) 
}

/// DELETE /upvotes/:comment_id/:user_id
pub fn upvotes_delete(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    // make one of the endpoints admin-only to show how authentication filters are used
    let admin_only = warp::header::exact("authorization", "Bearer admin");
    warp::path!("upvotes" / String / String)
        // It is important to put the auth check _after_ the path filters. 
        // If we put the auth check before, the request `PUT /todos/invalid-string`
        // would try this filter and reject because the authorization header 
        // doesn't match, rather because the param is wrong for that other path. 
        .and(admin_only)
        .and(warp::delete())
        .and(with_db_conn(db_conn))
        .and_then(handlers::delete_upvote)
}

/// GET /upvotes_total/:comment_id  -> get total number of upvotes
pub fn upvotes_total(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("upvotes_total" / String)
        .and(warp::get())
        .and(with_db_conn(db_conn))
        .and_then(handlers::upvotes_total)
}

/// POST /downvotes with JSON body 
pub fn downvotes_create(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("downvotes")
        .and(warp::post())
        .and(json_downvote_body())
        .and(with_db_conn(db_conn))
        .and_then(handlers::add_downvote)
}

fn json_downvote_body() -> impl Filter<Extract = (Downvote,), Error = warp::Rejection> + Clone {
    // When accepting a body, we want a JSON body 
    // (and to reject huge payloads)... 
    warp::body::content_length_limit(1024 * 16).and(warp::body::json()) 
}

/// DELETE /downvotes/:comment_id/:user_id
pub fn downvotes_delete(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    // make one of the endpoints admin-only to show how authentication filters are used
    let admin_only = warp::header::exact("authorization", "Bearer admin");
    warp::path!("downvotes" / String / String)
        // It is important to put the auth check _after_ the path filters. 
        // If we put the auth check before, the request `PUT /todos/invalid-string`
        // would try this filter and reject because the authorization header 
        // doesn't match, rather because the param is wrong for that other path. 
        .and(admin_only)
        .and(warp::delete())
        .and(with_db_conn(db_conn))
        .and_then(handlers::delete_downvote)
}

/// GET /downvotes_total/:comment_id  -> get total number of downvotes
pub fn downvotes_total(
    db_conn: DbConn,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("downvotes_total" / String)
        .and(warp::get())
        .and(with_db_conn(db_conn))
        .and_then(handlers::downvotes_total)
}