From 0bfad25d3d06f03cef559477f94a2234c96f5117 Mon Sep 17 00:00:00 2001 From: glyph Date: Thu, 24 Mar 2022 13:41:49 +0200 Subject: [PATCH] add follow, unfollow, block and unblock routes and sbot helper functions --- peach-web/src/private_router.rs | 16 ++++ peach-web/src/routes/scuttlebutt/block.rs | 42 ++++++++++ peach-web/src/routes/scuttlebutt/follow.rs | 42 ++++++++++ peach-web/src/routes/scuttlebutt/mod.rs | 4 + peach-web/src/routes/scuttlebutt/search.rs | 2 +- peach-web/src/routes/scuttlebutt/unblock.rs | 42 ++++++++++ peach-web/src/routes/scuttlebutt/unfollow.rs | 42 ++++++++++ peach-web/src/routes/status/scuttlebutt.rs | 2 +- peach-web/src/utils/sbot.rs | 85 +++++++++++++++++++- 9 files changed, 271 insertions(+), 6 deletions(-) create mode 100644 peach-web/src/routes/scuttlebutt/block.rs create mode 100644 peach-web/src/routes/scuttlebutt/follow.rs create mode 100644 peach-web/src/routes/scuttlebutt/unblock.rs create mode 100644 peach-web/src/routes/scuttlebutt/unfollow.rs diff --git a/peach-web/src/private_router.rs b/peach-web/src/private_router.rs index 6b72a26..975eb75 100644 --- a/peach-web/src/private_router.rs +++ b/peach-web/src/private_router.rs @@ -43,10 +43,18 @@ pub fn mount_peachpub_routes( Response::html(routes::guide::build_template()) }, + (POST) (/scuttlebutt/block) => { + routes::scuttlebutt::block::handle_form(request) + }, + (GET) (/scuttlebutt/blocks) => { Response::html(routes::scuttlebutt::blocks::build_template()) }, + (POST) (/scuttlebutt/follow) => { + routes::scuttlebutt::follow::handle_form(request) + }, + (GET) (/scuttlebutt/follows) => { Response::html(routes::scuttlebutt::follows::build_template()) }, @@ -111,6 +119,14 @@ pub fn mount_peachpub_routes( routes::scuttlebutt::search::handle_form(request) }, + (POST) (/scuttlebutt/unblock) => { + routes::scuttlebutt::unblock::handle_form(request) + }, + + (POST) (/scuttlebutt/unfollow) => { + routes::scuttlebutt::unfollow::handle_form(request) + }, + (GET) (/settings) => { Response::html(routes::settings::menu::build_template()) }, diff --git a/peach-web/src/routes/scuttlebutt/block.rs b/peach-web/src/routes/scuttlebutt/block.rs new file mode 100644 index 0000000..176133c --- /dev/null +++ b/peach-web/src/routes/scuttlebutt/block.rs @@ -0,0 +1,42 @@ +use peach_lib::sbot::SbotStatus; +use rouille::{post_input, try_or_400, Request, Response}; + +use crate::utils::{flash::FlashResponse, sbot}; + +// ROUTE: /scuttlebutt/block + +/// Block a Scuttlebutt profile specified by the given public key. +/// +/// Parse the public key from the submitted form and publish a contact message. +/// Redirect to the appropriate profile page with a flash message describing +/// the outcome of the action (may be successful or unsuccessful). +pub fn handle_form(request: &Request) -> Response { + // query the request body for form data + // return a 400 error if the admin_id field is missing + let data = try_or_400!(post_input!(request, { + public_key: String, + })); + + let (flash_name, flash_msg) = match SbotStatus::read() { + Ok(status) if status.state == Some("active".to_string()) => { + match sbot::block_peer(&data.public_key) { + Ok(success_msg) => ( + "flash_name=success".to_string(), + format!("flash_msg={}", success_msg), + ), + Err(error_msg) => ( + "flash_name=error".to_string(), + format!("flash_msg={}", error_msg), + ), + } + } + _ => ( + "flash_name=warning".to_string(), + "Social interactions are unavailable.".to_string(), + ), + }; + + let url = format!("/scuttlebutt/profile/{}", data.public_key); + + Response::redirect_303(url).add_flash(flash_name, flash_msg) +} diff --git a/peach-web/src/routes/scuttlebutt/follow.rs b/peach-web/src/routes/scuttlebutt/follow.rs new file mode 100644 index 0000000..a73d47b --- /dev/null +++ b/peach-web/src/routes/scuttlebutt/follow.rs @@ -0,0 +1,42 @@ +use peach_lib::sbot::SbotStatus; +use rouille::{post_input, try_or_400, Request, Response}; + +use crate::utils::{flash::FlashResponse, sbot}; + +// ROUTE: /scuttlebutt/follow + +/// Follow a Scuttlebutt profile specified by the given public key. +/// +/// Parse the public key from the submitted form and publish a contact message. +/// Redirect to the appropriate profile page with a flash message describing +/// the outcome of the action (may be successful or unsuccessful). +pub fn handle_form(request: &Request) -> Response { + // query the request body for form data + // return a 400 error if the admin_id field is missing + let data = try_or_400!(post_input!(request, { + public_key: String, + })); + + let (flash_name, flash_msg) = match SbotStatus::read() { + Ok(status) if status.state == Some("active".to_string()) => { + match sbot::follow_peer(&data.public_key) { + Ok(success_msg) => ( + "flash_name=success".to_string(), + format!("flash_msg={}", success_msg), + ), + Err(error_msg) => ( + "flash_name=error".to_string(), + format!("flash_msg={}", error_msg), + ), + } + } + _ => ( + "flash_name=warning".to_string(), + "Social interactions are unavailable.".to_string(), + ), + }; + + let url = format!("/scuttlebutt/profile/{}", data.public_key); + + Response::redirect_303(url).add_flash(flash_name, flash_msg) +} diff --git a/peach-web/src/routes/scuttlebutt/mod.rs b/peach-web/src/routes/scuttlebutt/mod.rs index 6f77fd3..bea4722 100644 --- a/peach-web/src/routes/scuttlebutt/mod.rs +++ b/peach-web/src/routes/scuttlebutt/mod.rs @@ -1,4 +1,6 @@ +pub mod block; pub mod blocks; +pub mod follow; pub mod follows; pub mod friends; pub mod invites; @@ -8,3 +10,5 @@ pub mod profile; pub mod profile_update; pub mod publish; pub mod search; +pub mod unblock; +pub mod unfollow; diff --git a/peach-web/src/routes/scuttlebutt/search.rs b/peach-web/src/routes/scuttlebutt/search.rs index eb71acb..01bebf5 100644 --- a/peach-web/src/routes/scuttlebutt/search.rs +++ b/peach-web/src/routes/scuttlebutt/search.rs @@ -57,7 +57,7 @@ pub fn handle_form(request: &Request) -> Response { match sbot::validate_public_key(&data.public_key) { Ok(_) => { - let url = format!("/scuttlebutt/profile?={}", &data.public_key); + let url = format!("/scuttlebutt/profile/{}", &data.public_key); Response::redirect_303(url) } Err(err) => { diff --git a/peach-web/src/routes/scuttlebutt/unblock.rs b/peach-web/src/routes/scuttlebutt/unblock.rs new file mode 100644 index 0000000..7ebf7f2 --- /dev/null +++ b/peach-web/src/routes/scuttlebutt/unblock.rs @@ -0,0 +1,42 @@ +use peach_lib::sbot::SbotStatus; +use rouille::{post_input, try_or_400, Request, Response}; + +use crate::utils::{flash::FlashResponse, sbot}; + +// ROUTE: /scuttlebutt/unblock + +/// Unblock a Scuttlebutt profile specified by the given public key. +/// +/// Parse the public key from the submitted form and publish a contact message. +/// Redirect to the appropriate profile page with a flash message describing +/// the outcome of the action (may be successful or unsuccessful). +pub fn handle_form(request: &Request) -> Response { + // query the request body for form data + // return a 400 error if the admin_id field is missing + let data = try_or_400!(post_input!(request, { + public_key: String, + })); + + let (flash_name, flash_msg) = match SbotStatus::read() { + Ok(status) if status.state == Some("active".to_string()) => { + match sbot::unblock_peer(&data.public_key) { + Ok(success_msg) => ( + "flash_name=success".to_string(), + format!("flash_msg={}", success_msg), + ), + Err(error_msg) => ( + "flash_name=error".to_string(), + format!("flash_msg={}", error_msg), + ), + } + } + _ => ( + "flash_name=warning".to_string(), + "Social interactions are unavailable.".to_string(), + ), + }; + + let url = format!("/scuttlebutt/profile/{}", data.public_key); + + Response::redirect_303(url).add_flash(flash_name, flash_msg) +} diff --git a/peach-web/src/routes/scuttlebutt/unfollow.rs b/peach-web/src/routes/scuttlebutt/unfollow.rs new file mode 100644 index 0000000..a043f06 --- /dev/null +++ b/peach-web/src/routes/scuttlebutt/unfollow.rs @@ -0,0 +1,42 @@ +use peach_lib::sbot::SbotStatus; +use rouille::{post_input, try_or_400, Request, Response}; + +use crate::utils::{flash::FlashResponse, sbot}; + +// ROUTE: /scuttlebutt/unfollow + +/// Unfollow a Scuttlebutt profile specified by the given public key. +/// +/// Parse the public key from the submitted form and publish a contact message. +/// Redirect to the appropriate profile page with a flash message describing +/// the outcome of the action (may be successful or unsuccessful). +pub fn handle_form(request: &Request) -> Response { + // query the request body for form data + // return a 400 error if the admin_id field is missing + let data = try_or_400!(post_input!(request, { + public_key: String, + })); + + let (flash_name, flash_msg) = match SbotStatus::read() { + Ok(status) if status.state == Some("active".to_string()) => { + match sbot::unfollow_peer(&data.public_key) { + Ok(success_msg) => ( + "flash_name=success".to_string(), + format!("flash_msg={}", success_msg), + ), + Err(error_msg) => ( + "flash_name=error".to_string(), + format!("flash_msg={}", error_msg), + ), + } + } + _ => ( + "flash_name=warning".to_string(), + "Social interactions are unavailable.".to_string(), + ), + }; + + let url = format!("/scuttlebutt/profile/{}", data.public_key); + + Response::redirect_303(url).add_flash(flash_name, flash_msg) +} diff --git a/peach-web/src/routes/status/scuttlebutt.rs b/peach-web/src/routes/status/scuttlebutt.rs index 083703f..e25aa57 100644 --- a/peach-web/src/routes/status/scuttlebutt.rs +++ b/peach-web/src/routes/status/scuttlebutt.rs @@ -75,7 +75,7 @@ fn memory_element(memory: Option) -> Markup { memory_rounded.to_string(), "icon icon-active", "label-medium font-normal", - "label-small font-normal", + "label-small font-gray", ) } _ => ( diff --git a/peach-web/src/utils/sbot.rs b/peach-web/src/utils/sbot.rs index 3a0bb74..b170b7b 100644 --- a/peach-web/src/utils/sbot.rs +++ b/peach-web/src/utils/sbot.rs @@ -130,11 +130,16 @@ pub fn latest_sequence_number() -> Result> { let history_stream = sbot_client.create_history_stream(id).await?; let mut msgs: Vec = history_stream.try_collect().await?; - // reverse the list of messages so we can easily reference the latest one - msgs.reverse(); + // there will be zero messages when the sbot is run for the first time + if msgs.is_empty() { + Ok(0) + } else { + // reverse the list of messages so we can easily reference the latest one + msgs.reverse(); - // return the sequence number of the latest msg - Ok(msgs[0].sequence) + // return the sequence number of the latest msg + Ok(msgs[0].sequence) + } }) } @@ -353,6 +358,78 @@ pub fn update_profile_info( }) } +/// Follow a peer. +pub fn follow_peer(public_key: &str) -> Result { + // retrieve latest go-sbot configuration parameters + let sbot_config = SbotConfig::read().ok(); + + task::block_on(async { + let mut sbot_client = init_sbot_with_config(&sbot_config) + .await + .map_err(|e| e.to_string())?; + + debug!("Following a Scuttlebutt peer"); + match sbot_client.follow(public_key).await { + Ok(_) => Ok("Followed peer".to_string()), + Err(e) => Err(format!("Failed to follow peer: {}", e)), + } + }) +} + +/// Unfollow a peer. +pub fn unfollow_peer(public_key: &str) -> Result { + // retrieve latest go-sbot configuration parameters + let sbot_config = SbotConfig::read().ok(); + + task::block_on(async { + let mut sbot_client = init_sbot_with_config(&sbot_config) + .await + .map_err(|e| e.to_string())?; + + debug!("Unfollowing a Scuttlebutt peer"); + match sbot_client.unfollow(public_key).await { + Ok(_) => Ok("Unfollowed peer".to_string()), + Err(e) => Err(format!("Failed to unfollow peer: {}", e)), + } + }) +} + +/// Block a peer. +pub fn block_peer(public_key: &str) -> Result { + // retrieve latest go-sbot configuration parameters + let sbot_config = SbotConfig::read().ok(); + + task::block_on(async { + let mut sbot_client = init_sbot_with_config(&sbot_config) + .await + .map_err(|e| e.to_string())?; + + debug!("Blocking a Scuttlebutt peer"); + match sbot_client.block(public_key).await { + Ok(_) => Ok("Blocked peer".to_string()), + Err(e) => Err(format!("Failed to block peer: {}", e)), + } + }) +} + +/// Unblock a peer. +pub fn unblock_peer(public_key: &str) -> Result { + // retrieve latest go-sbot configuration parameters + let sbot_config = SbotConfig::read().ok(); + + task::block_on(async { + let mut sbot_client = init_sbot_with_config(&sbot_config) + .await + .map_err(|e| e.to_string())?; + + debug!("Unblocking a Scuttlebutt peer"); + match sbot_client.unblock(public_key).await { + Ok(_) => Ok("Unblocked peer".to_string()), + Err(e) => Err(format!("Failed to unblock peer: {}", e)), + } + }) +} + /// Retrieve a list of peers blocked by the local public key. pub fn get_blocks_list() -> Result>, Box> { // retrieve latest go-sbot configuration parameters