diff --git a/src/apis/routes.rs b/src/apis/routes.rs index 9b909abe..93209c28 100644 --- a/src/apis/routes.rs +++ b/src/apis/routes.rs @@ -105,6 +105,13 @@ pub async fn delete_torrent_from_whitelist_handler( } } +pub async fn reload_whitelist_handler(State(tracker): State>) -> Response { + match tracker.load_whitelist().await { + Ok(..) => response_ok(), + Err(..) => response_err("failed to reload whitelist".to_string()), + } +} + /// Serde deserialization decorator to map empty Strings to None, fn empty_string_as_none<'de, D, T>(de: D) -> Result, D::Error> where diff --git a/src/apis/server.rs b/src/apis/server.rs index e03eae55..fb0e4b37 100644 --- a/src/apis/server.rs +++ b/src/apis/server.rs @@ -12,11 +12,12 @@ use warp::hyper; use super::middlewares::auth::auth; use super::routes::{ add_torrent_to_whitelist_handler, delete_torrent_from_whitelist_handler, get_stats_handler, get_torrent_handler, - get_torrents_handler, + get_torrents_handler, reload_whitelist_handler, }; use crate::tracker; pub fn start(socket_addr: SocketAddr, tracker: &Arc) -> impl Future> { + // todo: duplicate routes definition. See `start_tls` function. let app = Router::new() // Stats .route("/stats", get(get_stats_handler).with_state(tracker.clone())) @@ -32,6 +33,11 @@ pub fn start(socket_addr: SocketAddr, tracker: &Arc) -> impl F "/whitelist/:info_hash", delete(delete_torrent_from_whitelist_handler).with_state(tracker.clone()), ) + // Whitelist command + .route( + "/whitelist/:info_hash", + get(reload_whitelist_handler).with_state(tracker.clone()), + ) .layer(middleware::from_fn_with_state(tracker.config.clone(), auth)); let server = axum::Server::bind(&socket_addr).serve(app.into_make_service()); @@ -47,6 +53,7 @@ pub fn start_tls( ssl_config: RustlsConfig, tracker: &Arc, ) -> impl Future> { + // todo: duplicate routes definition. See `start` function. let app = Router::new() // Stats .route("/stats", get(get_stats_handler).with_state(tracker.clone())) @@ -62,6 +69,11 @@ pub fn start_tls( "/whitelist/:info_hash", delete(delete_torrent_from_whitelist_handler).with_state(tracker.clone()), ) + // Whitelist command + .route( + "/whitelist/:info_hash", + get(reload_whitelist_handler).with_state(tracker.clone()), + ) .layer(middleware::from_fn_with_state(tracker.config.clone(), auth)); let handle = Handle::new(); diff --git a/tests/api/asserts.rs b/tests/api/asserts.rs index 6bf493bc..0a2b3fad 100644 --- a/tests/api/asserts.rs +++ b/tests/api/asserts.rs @@ -1,3 +1,5 @@ +// code-review: should we use macros to return the exact line where the assert fails? + use reqwest::Response; pub async fn assert_torrent_not_known(response: Response) { diff --git a/tests/tracker_api.rs b/tests/tracker_api.rs index 0acf7e42..37a6033c 100644 --- a/tests/tracker_api.rs +++ b/tests/tracker_api.rs @@ -950,8 +950,8 @@ mod tracker_apis { use torrust_tracker::protocol::info_hash::InfoHash; use crate::api::asserts::{ - assert_failed_to_remove_torrent_from_whitelist, assert_failed_to_whitelist_torrent, assert_token_not_valid, - assert_unauthorized, + assert_failed_to_reload_whitelist, assert_failed_to_remove_torrent_from_whitelist, + assert_failed_to_whitelist_torrent, assert_token_not_valid, assert_unauthorized, }; use crate::api::client::Client; use crate::api::connection_info::{connection_with_invalid_token, connection_with_no_token}; @@ -1080,5 +1080,47 @@ mod tracker_apis { assert_unauthorized(response).await; } + + #[tokio::test] + async fn should_allow_reload_the_whitelist_from_the_database() { + let api_server = start_default_api(&Version::Axum).await; + + let hash = "9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d".to_owned(); + let info_hash = InfoHash::from_str(&hash).unwrap(); + api_server.tracker.add_torrent_to_whitelist(&info_hash).await.unwrap(); + + let response = Client::new(api_server.get_connection_info(), &Version::Axum) + .reload_whitelist() + .await; + + assert_eq!(response.status(), 200); + /* This assert fails because the whitelist has not been reloaded yet. + We could add a new endpoint GET /api/whitelist/:info_hash to check if a torrent + is whitelisted and use that endpoint to check if the torrent is still there after reloading. + assert!( + !(api_server + .tracker + .is_info_hash_whitelisted(&InfoHash::from_str(&info_hash).unwrap()) + .await) + ); + */ + } + + #[tokio::test] + async fn should_return_an_error_when_the_whitelist_cannot_be_reloaded_from_the_database() { + let api_server = start_default_api(&Version::Axum).await; + + let hash = "9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d".to_owned(); + let info_hash = InfoHash::from_str(&hash).unwrap(); + api_server.tracker.add_torrent_to_whitelist(&info_hash).await.unwrap(); + + force_database_error(&api_server.tracker); + + let response = Client::new(api_server.get_connection_info(), &Version::Axum) + .reload_whitelist() + .await; + + assert_failed_to_reload_whitelist(response).await; + } } }