add block list and implement (un)follow and (un)block
This commit is contained in:
parent
a38394054d
commit
020d18731b
|
@ -26,7 +26,98 @@ pub async fn init_sbot_with_config(
|
||||||
|
|
||||||
// CONTEXT STRUCTS AND BUILDERS
|
// CONTEXT STRUCTS AND BUILDERS
|
||||||
|
|
||||||
// peers who follow the local account
|
// peers who are blocked by the local account
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct BlocksContext {
|
||||||
|
pub back: Option<String>,
|
||||||
|
pub flash_name: Option<String>,
|
||||||
|
pub flash_msg: Option<String>,
|
||||||
|
pub title: Option<String>,
|
||||||
|
pub theme: Option<String>,
|
||||||
|
pub sbot_config: Option<SbotConfig>,
|
||||||
|
pub sbot_status: Option<SbotStatus>,
|
||||||
|
pub peers: Option<Vec<HashMap<String, String>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlocksContext {
|
||||||
|
pub fn default() -> Self {
|
||||||
|
BlocksContext {
|
||||||
|
back: Some("/scuttlebutt/peers".to_string()),
|
||||||
|
flash_name: None,
|
||||||
|
flash_msg: None,
|
||||||
|
title: Some("Blocks".to_string()),
|
||||||
|
theme: None,
|
||||||
|
sbot_config: None,
|
||||||
|
sbot_status: None,
|
||||||
|
peers: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn build() -> Result<Self, PeachWebError> {
|
||||||
|
let mut context = Self::default();
|
||||||
|
|
||||||
|
// retrieve current ui theme
|
||||||
|
context.theme = Some(utils::get_theme());
|
||||||
|
|
||||||
|
// retrieve go-sbot systemd process status
|
||||||
|
let sbot_status = SbotStatus::read()?;
|
||||||
|
|
||||||
|
// we only want to try and interact with the sbot if it's active
|
||||||
|
if sbot_status.state == Some("active".to_string()) {
|
||||||
|
// retrieve latest go-sbot configuration parameters
|
||||||
|
let sbot_config = SbotConfig::read().ok();
|
||||||
|
|
||||||
|
let mut sbot_client = init_sbot_with_config(&sbot_config).await?;
|
||||||
|
|
||||||
|
let blocks = sbot_client.get_blocks().await?;
|
||||||
|
|
||||||
|
// we'll use this to store the profile info for each peer who follows us
|
||||||
|
let mut peer_info = Vec::new();
|
||||||
|
|
||||||
|
if !blocks.is_empty() {
|
||||||
|
for peer in blocks.iter() {
|
||||||
|
// trim whitespace (including newline characters) and
|
||||||
|
// remove the inverted-commas around the id
|
||||||
|
let key = peer.trim().replace('"', "");
|
||||||
|
// retrieve the profile info for the given peer
|
||||||
|
let mut info = sbot_client.get_profile_info(&key).await?;
|
||||||
|
// insert the public key of the peer into the info hashmap
|
||||||
|
info.insert("id".to_string(), key.to_string());
|
||||||
|
// retrieve the profile image blob id for the given peer
|
||||||
|
if let Some(blob_id) = info.get("image") {
|
||||||
|
// look-up the path for the image blob
|
||||||
|
if let Ok(blob_path) = blobs::get_blob_path(&blob_id) {
|
||||||
|
// insert the image blob path of the peer into the info hashmap
|
||||||
|
info.insert("blob_path".to_string(), blob_path.to_string());
|
||||||
|
// check if the blob is in the blobstore
|
||||||
|
// set a flag in the info hashmap
|
||||||
|
match utils::blob_is_stored_locally(&blob_path).await {
|
||||||
|
Ok(exists) if exists == true => {
|
||||||
|
info.insert("blob_exists".to_string(), "true".to_string())
|
||||||
|
}
|
||||||
|
_ => info.insert("blob_exists".to_string(), "false".to_string()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// push profile info to peer_list vec
|
||||||
|
peer_info.push(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
context.peers = Some(peer_info)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// the sbot is not currently active; return a helpful message
|
||||||
|
context.flash_name = Some("warning".to_string());
|
||||||
|
context.flash_msg = Some("The Sbot is currently inactive. As a result, peer data cannot be retrieved. Visit the Scuttlebutt settings menu to start the Sbot and then try again".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
context.sbot_status = Some(sbot_status);
|
||||||
|
|
||||||
|
Ok(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// peers who are followed by the local account
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct FollowsContext {
|
pub struct FollowsContext {
|
||||||
pub back: Option<String>,
|
pub back: Option<String>,
|
||||||
|
@ -108,7 +199,7 @@ impl FollowsContext {
|
||||||
} else {
|
} else {
|
||||||
// the sbot is not currently active; return a helpful message
|
// the sbot is not currently active; return a helpful message
|
||||||
context.flash_name = Some("warning".to_string());
|
context.flash_name = Some("warning".to_string());
|
||||||
context.flash_msg = Some("The Sbot is currently inactive. As a result, profile data cannot be retrieved. Visit the Scuttlebutt settings menu to start the Sbot and then try again".to_string());
|
context.flash_msg = Some("The Sbot is currently inactive. As a result, peer data cannot be retrieved. Visit the Scuttlebutt settings menu to start the Sbot and then try again".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
context.sbot_status = Some(sbot_status);
|
context.sbot_status = Some(sbot_status);
|
||||||
|
@ -214,7 +305,7 @@ impl FriendsContext {
|
||||||
} else {
|
} else {
|
||||||
// the sbot is not currently active; return a helpful message
|
// the sbot is not currently active; return a helpful message
|
||||||
context.flash_name = Some("warning".to_string());
|
context.flash_name = Some("warning".to_string());
|
||||||
context.flash_msg = Some("The Sbot is currently inactive. As a result, profile data cannot be retrieved. Visit the Scuttlebutt settings menu to start the Sbot and then try again".to_string());
|
context.flash_msg = Some("The Sbot is currently inactive. As a result, peer data cannot be retrieved. Visit the Scuttlebutt settings menu to start the Sbot and then try again".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
context.sbot_status = Some(sbot_status);
|
context.sbot_status = Some(sbot_status);
|
||||||
|
|
|
@ -84,6 +84,7 @@ pub fn mount_peachpub_routes(rocket: Rocket<Build>) -> Rocket<Build> {
|
||||||
follow,
|
follow,
|
||||||
unfollow,
|
unfollow,
|
||||||
block,
|
block,
|
||||||
|
unblock,
|
||||||
publish,
|
publish,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,7 +16,7 @@ use rocket_dyn_templates::{tera::Context, Template};
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{
|
context::{
|
||||||
sbot,
|
sbot,
|
||||||
sbot::{FollowsContext, FriendsContext, ProfileContext},
|
sbot::{BlocksContext, FollowsContext, FriendsContext, ProfileContext},
|
||||||
},
|
},
|
||||||
routes::authentication::Authenticated,
|
routes::authentication::Authenticated,
|
||||||
utils,
|
utils,
|
||||||
|
@ -141,7 +141,7 @@ pub fn private(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
||||||
context.flash_msg = Some(flash.message().to_string());
|
context.flash_msg = Some(flash.message().to_string());
|
||||||
};
|
};
|
||||||
|
|
||||||
Template::render("scuttlebutt/messages", &context)
|
Template::render("scuttlebutt/private", &context)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HELPERS AND ROUTES FOR /search
|
// HELPERS AND ROUTES FOR /search
|
||||||
|
@ -172,55 +172,63 @@ pub fn search(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, FromForm)]
|
#[derive(Debug, FromForm)]
|
||||||
pub struct Search {
|
pub struct Peer {
|
||||||
|
// public key
|
||||||
pub public_key: String,
|
pub public_key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Accept the peer search form and redirect to the profile for that peer.
|
fn validate_public_key(public_key: &str, redirect_url: String) -> Result<(), Flash<Redirect>> {
|
||||||
#[post("/search", data = "<search>")]
|
|
||||||
pub async fn search_post(search: Form<Search>, _auth: Authenticated) -> Flash<Redirect> {
|
|
||||||
let public_key = &search.public_key;
|
|
||||||
|
|
||||||
let search_url = "/scuttlebutt/search";
|
|
||||||
|
|
||||||
// validate the key before redirecting to profile url
|
|
||||||
|
|
||||||
// ensure the id starts with the correct sigil link
|
// ensure the id starts with the correct sigil link
|
||||||
if !public_key.starts_with('@') {
|
if !public_key.starts_with('@') {
|
||||||
return Flash::error(
|
return Err(Flash::error(
|
||||||
Redirect::to(search_url),
|
Redirect::to(redirect_url),
|
||||||
"Invalid key: expected '@' sigil as first character",
|
"Invalid key: expected '@' sigil as first character",
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the dot index denoting the start of the algorithm definition tag
|
// find the dot index denoting the start of the algorithm definition tag
|
||||||
let dot_index = match public_key.rfind('.') {
|
let dot_index = match public_key.rfind('.') {
|
||||||
Some(index) => index,
|
Some(index) => index,
|
||||||
None => {
|
None => {
|
||||||
return Flash::error(
|
return Err(Flash::error(
|
||||||
Redirect::to(search_url),
|
Redirect::to(redirect_url),
|
||||||
"Invalid key: no dot index was found",
|
"Invalid key: no dot index was found",
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// check hashing algorithm (must end with ".ed25519")
|
// check hashing algorithm (must end with ".ed25519")
|
||||||
if !&public_key.ends_with(".ed25519") {
|
if !&public_key.ends_with(".ed25519") {
|
||||||
return Flash::error(
|
return Err(Flash::error(
|
||||||
Redirect::to(search_url),
|
Redirect::to(redirect_url),
|
||||||
"Invalid key: hashing algorithm must be ed25519",
|
"Invalid key: hashing algorithm must be ed25519",
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// obtain the base64 portion (substring) of the public key
|
// obtain the base64 portion (substring) of the public key
|
||||||
let base64_str = &public_key[1..dot_index];
|
let base64_str = &public_key[1..dot_index];
|
||||||
|
|
||||||
// length of a base64 encoded ed25519 public key
|
// length of a base64 encoded ed25519 public key
|
||||||
if !base64_str.len() == 44 {
|
if base64_str.len() != 44 {
|
||||||
return Flash::error(
|
return Err(Flash::error(
|
||||||
Redirect::to(search_url),
|
Redirect::to(redirect_url),
|
||||||
"Invalid key: base64 data length is incorrect",
|
"Invalid key: base64 data length is incorrect",
|
||||||
);
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accept the peer search form and redirect to the profile for that peer.
|
||||||
|
#[post("/search", data = "<peer>")]
|
||||||
|
pub async fn search_post(peer: Form<Peer>, _auth: Authenticated) -> Flash<Redirect> {
|
||||||
|
let public_key = &peer.public_key;
|
||||||
|
|
||||||
|
let search_url = "/scuttlebutt/search".to_string();
|
||||||
|
|
||||||
|
// validate the key before redirecting to profile url
|
||||||
|
if let Err(flash) = validate_public_key(&public_key, search_url) {
|
||||||
|
return flash;
|
||||||
}
|
}
|
||||||
|
|
||||||
// key has not been validated and we can redirect to the profile page
|
// key has not been validated and we can redirect to the profile page
|
||||||
|
@ -276,8 +284,15 @@ pub async fn publish(post: Form<Post>, _auth: Authenticated) -> Flash<Redirect>
|
||||||
let url = uri!("/scuttlebutt", profile(None::<String>));
|
let url = uri!("/scuttlebutt", profile(None::<String>));
|
||||||
|
|
||||||
// retrieve go-sbot systemd process status
|
// retrieve go-sbot systemd process status
|
||||||
// TODO: handle unwrap properly
|
let sbot_status = match SbotStatus::read() {
|
||||||
let sbot_status = SbotStatus::read().unwrap();
|
Ok(status) => status,
|
||||||
|
Err(e) => {
|
||||||
|
return Flash::error(
|
||||||
|
Redirect::to(url),
|
||||||
|
format!("Failed to read sbot status: {}", e),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// we only want to try and interact with the sbot if it's active
|
// we only want to try and interact with the sbot if it's active
|
||||||
if sbot_status.state == Some("active".to_string()) {
|
if sbot_status.state == Some("active".to_string()) {
|
||||||
|
@ -310,25 +325,53 @@ pub async fn publish(post: Form<Post>, _auth: Authenticated) -> Flash<Redirect>
|
||||||
|
|
||||||
// HELPERS AND ROUTES FOR /follow
|
// HELPERS AND ROUTES FOR /follow
|
||||||
|
|
||||||
#[derive(Debug, FromForm)]
|
|
||||||
pub struct PublicKey {
|
|
||||||
pub key: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Follow a Scuttlebutt profile specified by the given public key.
|
/// Follow a Scuttlebutt profile specified by the given public key.
|
||||||
/// Redirects to the appropriate profile page with a flash message describing
|
/// Redirects to the appropriate profile page with a flash message describing
|
||||||
/// the outcome of the action (may be successful or unsuccessful).
|
/// the outcome of the action (may be successful or unsuccessful).
|
||||||
#[post("/follow", data = "<pub_key>")]
|
#[post("/follow", data = "<peer>")]
|
||||||
pub fn follow(pub_key: Form<PublicKey>, _auth: Authenticated) -> Flash<Redirect> {
|
pub async fn follow(peer: Form<Peer>, _auth: Authenticated) -> Flash<Redirect> {
|
||||||
let public_key = &pub_key.key;
|
let public_key = &peer.public_key;
|
||||||
// perform the sbotcli follow action using &pub_key.0
|
|
||||||
// if successful, redirect to profile page with provided public key and flash "success"
|
|
||||||
// if error, redirect to profile page with provided public key and flash "error"
|
|
||||||
// redirect to the profile template with provided public key
|
|
||||||
let profile_url = uri!("/scuttlebutt", profile(Some(public_key)));
|
|
||||||
let success_msg = format!("Followed {}", public_key);
|
|
||||||
|
|
||||||
Flash::success(Redirect::to(profile_url), success_msg)
|
let url = uri!("/scuttlebutt", profile(Some(public_key)));
|
||||||
|
|
||||||
|
// retrieve go-sbot systemd process status
|
||||||
|
let sbot_status = match SbotStatus::read() {
|
||||||
|
Ok(status) => status,
|
||||||
|
Err(e) => {
|
||||||
|
return Flash::error(
|
||||||
|
Redirect::to(url),
|
||||||
|
format!("Failed to read sbot status: {}", e),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// we only want to try and interact with the sbot if it's active
|
||||||
|
if sbot_status.state == Some("active".to_string()) {
|
||||||
|
// retrieve latest go-sbot configuration parameters
|
||||||
|
let sbot_config = SbotConfig::read().ok();
|
||||||
|
|
||||||
|
// initialise sbot connection with ip:port and shscap from config file
|
||||||
|
match sbot::init_sbot_with_config(&sbot_config).await {
|
||||||
|
Ok(mut sbot_client) => {
|
||||||
|
debug!("Following Scuttlebutt peer");
|
||||||
|
match sbot_client.follow(public_key).await {
|
||||||
|
Ok(_) => Flash::success(Redirect::to(url), format!("Followed peer")),
|
||||||
|
Err(e) => {
|
||||||
|
Flash::error(Redirect::to(url), format!("Failed to follow peer: {}", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Flash::error(
|
||||||
|
Redirect::to(url),
|
||||||
|
format!("Failed to initialise sbot: {}", e),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Flash::warning(
|
||||||
|
Redirect::to(url),
|
||||||
|
"The Sbot is currently inactive. As a result, follow messages cannot be published. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HELPERS AND ROUTES FOR /unfollow
|
// HELPERS AND ROUTES FOR /unfollow
|
||||||
|
@ -336,17 +379,50 @@ pub fn follow(pub_key: Form<PublicKey>, _auth: Authenticated) -> Flash<Redirect>
|
||||||
/// Unfollow a Scuttlebutt profile specified by the given public key.
|
/// Unfollow a Scuttlebutt profile specified by the given public key.
|
||||||
/// Redirects to the appropriate profile page with a flash message describing
|
/// Redirects to the appropriate profile page with a flash message describing
|
||||||
/// the outcome of the action (may be successful or unsuccessful).
|
/// the outcome of the action (may be successful or unsuccessful).
|
||||||
#[post("/unfollow", data = "<pub_key>")]
|
#[post("/unfollow", data = "<peer>")]
|
||||||
pub fn unfollow(pub_key: Form<PublicKey>, _auth: Authenticated) -> Flash<Redirect> {
|
pub async fn unfollow(peer: Form<Peer>, _auth: Authenticated) -> Flash<Redirect> {
|
||||||
let public_key = &pub_key.key;
|
let public_key = &peer.public_key;
|
||||||
// perform the sbotcli unfollow action using &pub_key.0
|
|
||||||
// if successful, redirect to profile page with provided public key and flash "success"
|
|
||||||
// if error, redirect to profile page with provided public key and flash "error"
|
|
||||||
// redirect to the profile template with provided public key
|
|
||||||
let profile_url = uri!("/scuttlebutt", profile(Some(public_key)));
|
|
||||||
let success_msg = format!("Unfollowed {}", public_key);
|
|
||||||
|
|
||||||
Flash::success(Redirect::to(profile_url), success_msg)
|
let url = uri!("/scuttlebutt", profile(Some(public_key)));
|
||||||
|
|
||||||
|
// retrieve go-sbot systemd process status
|
||||||
|
let sbot_status = match SbotStatus::read() {
|
||||||
|
Ok(status) => status,
|
||||||
|
Err(e) => {
|
||||||
|
return Flash::error(
|
||||||
|
Redirect::to(url),
|
||||||
|
format!("Failed to read sbot status: {}", e),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// we only want to try and interact with the sbot if it's active
|
||||||
|
if sbot_status.state == Some("active".to_string()) {
|
||||||
|
// retrieve latest go-sbot configuration parameters
|
||||||
|
let sbot_config = SbotConfig::read().ok();
|
||||||
|
|
||||||
|
// initialise sbot connection with ip:port and shscap from config file
|
||||||
|
match sbot::init_sbot_with_config(&sbot_config).await {
|
||||||
|
Ok(mut sbot_client) => {
|
||||||
|
debug!("Unfollowing Scuttlebutt peer");
|
||||||
|
match sbot_client.unfollow(public_key).await {
|
||||||
|
Ok(_) => Flash::success(Redirect::to(url), format!("Unfollowed peer")),
|
||||||
|
Err(e) => {
|
||||||
|
Flash::error(Redirect::to(url), format!("Failed to unfollow peer: {}", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Flash::error(
|
||||||
|
Redirect::to(url),
|
||||||
|
format!("Failed to initialise sbot: {}", e),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Flash::warning(
|
||||||
|
Redirect::to(url),
|
||||||
|
"The Sbot is currently inactive. As a result, follow messages cannot be published. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HELPERS AND ROUTES FOR /block
|
// HELPERS AND ROUTES FOR /block
|
||||||
|
@ -354,17 +430,101 @@ pub fn unfollow(pub_key: Form<PublicKey>, _auth: Authenticated) -> Flash<Redirec
|
||||||
/// Block a Scuttlebutt profile specified by the given public key.
|
/// Block a Scuttlebutt profile specified by the given public key.
|
||||||
/// Redirects to the appropriate profile page with a flash message describing
|
/// Redirects to the appropriate profile page with a flash message describing
|
||||||
/// the outcome of the action (may be successful or unsuccessful).
|
/// the outcome of the action (may be successful or unsuccessful).
|
||||||
#[post("/block", data = "<pub_key>")]
|
#[post("/block", data = "<peer>")]
|
||||||
pub fn block(pub_key: Form<PublicKey>, _auth: Authenticated) -> Flash<Redirect> {
|
pub async fn block(peer: Form<Peer>, _auth: Authenticated) -> Flash<Redirect> {
|
||||||
let public_key = &pub_key.key;
|
let public_key = &peer.public_key;
|
||||||
// perform the sbotcli block action using &pub_key.0
|
|
||||||
// if successful, redirect to profile page with provided public key and flash "success"
|
|
||||||
// if error, redirect to profile page with provided public key and flash "error"
|
|
||||||
// redirect to the profile template with provided public key
|
|
||||||
let profile_url = uri!("/scuttlebutt", profile(Some(public_key)));
|
|
||||||
let success_msg = format!("Blocked {}", public_key);
|
|
||||||
|
|
||||||
Flash::success(Redirect::to(profile_url), success_msg)
|
let url = uri!("/scuttlebutt", profile(Some(public_key)));
|
||||||
|
|
||||||
|
// retrieve go-sbot systemd process status
|
||||||
|
let sbot_status = match SbotStatus::read() {
|
||||||
|
Ok(status) => status,
|
||||||
|
Err(e) => {
|
||||||
|
return Flash::error(
|
||||||
|
Redirect::to(url),
|
||||||
|
format!("Failed to read sbot status: {}", e),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// we only want to try and interact with the sbot if it's active
|
||||||
|
if sbot_status.state == Some("active".to_string()) {
|
||||||
|
// retrieve latest go-sbot configuration parameters
|
||||||
|
let sbot_config = SbotConfig::read().ok();
|
||||||
|
|
||||||
|
// initialise sbot connection with ip:port and shscap from config file
|
||||||
|
match sbot::init_sbot_with_config(&sbot_config).await {
|
||||||
|
Ok(mut sbot_client) => {
|
||||||
|
debug!("Blocking Scuttlebutt peer");
|
||||||
|
match sbot_client.block(public_key).await {
|
||||||
|
Ok(_) => Flash::success(Redirect::to(url), format!("Blocked peer")),
|
||||||
|
Err(e) => {
|
||||||
|
Flash::error(Redirect::to(url), format!("Failed to block peer: {}", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Flash::error(
|
||||||
|
Redirect::to(url),
|
||||||
|
format!("Failed to initialise sbot: {}", e),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Flash::warning(
|
||||||
|
Redirect::to(url),
|
||||||
|
"The Sbot is currently inactive. As a result, follow messages cannot be published. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HELPERS AND ROUTES FOR /unblock
|
||||||
|
|
||||||
|
/// Unblock a Scuttlebutt profile specified by the given public key.
|
||||||
|
/// Redirects to the appropriate profile page with a flash message describing
|
||||||
|
/// the outcome of the action (may be successful or unsuccessful).
|
||||||
|
#[post("/unblock", data = "<peer>")]
|
||||||
|
pub async fn unblock(peer: Form<Peer>, _auth: Authenticated) -> Flash<Redirect> {
|
||||||
|
let public_key = &peer.public_key;
|
||||||
|
|
||||||
|
let url = uri!("/scuttlebutt", profile(Some(public_key)));
|
||||||
|
|
||||||
|
// retrieve go-sbot systemd process status
|
||||||
|
let sbot_status = match SbotStatus::read() {
|
||||||
|
Ok(status) => status,
|
||||||
|
Err(e) => {
|
||||||
|
return Flash::error(
|
||||||
|
Redirect::to(url),
|
||||||
|
format!("Failed to read sbot status: {}", e),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// we only want to try and interact with the sbot if it's active
|
||||||
|
if sbot_status.state == Some("active".to_string()) {
|
||||||
|
// retrieve latest go-sbot configuration parameters
|
||||||
|
let sbot_config = SbotConfig::read().ok();
|
||||||
|
|
||||||
|
// initialise sbot connection with ip:port and shscap from config file
|
||||||
|
match sbot::init_sbot_with_config(&sbot_config).await {
|
||||||
|
Ok(mut sbot_client) => {
|
||||||
|
debug!("Unblocking Scuttlebutt peer");
|
||||||
|
match sbot_client.unblock(public_key).await {
|
||||||
|
Ok(_) => Flash::success(Redirect::to(url), format!("Unblocked peer")),
|
||||||
|
Err(e) => {
|
||||||
|
Flash::error(Redirect::to(url), format!("Failed to unblock peer: {}", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Flash::error(
|
||||||
|
Redirect::to(url),
|
||||||
|
format!("Failed to initialise sbot: {}", e),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Flash::warning(
|
||||||
|
Redirect::to(url),
|
||||||
|
"The Sbot is currently inactive. As a result, follow messages cannot be published. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ROUTES FOR /profile
|
// ROUTES FOR /profile
|
||||||
|
@ -644,39 +804,16 @@ pub async fn follows(flash: Option<FlashMessage<'_>>, _auth: Authenticated) -> T
|
||||||
|
|
||||||
// HELPERS AND ROUTES FOR /blocks
|
// HELPERS AND ROUTES FOR /blocks
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
/// A list of blocks (peers we've blocked previously), with each list item
|
||||||
pub struct BlocksContext {
|
/// displaying the name, image and public key of the peer.
|
||||||
pub back: Option<String>,
|
|
||||||
pub flash_name: Option<String>,
|
|
||||||
pub flash_msg: Option<String>,
|
|
||||||
pub title: Option<String>,
|
|
||||||
pub theme: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BlocksContext {
|
|
||||||
pub fn build() -> BlocksContext {
|
|
||||||
BlocksContext {
|
|
||||||
back: None,
|
|
||||||
flash_name: None,
|
|
||||||
flash_msg: None,
|
|
||||||
title: None,
|
|
||||||
theme: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A list of blocks (peers we've blocked previously), with each list item displaying the name, image and public
|
|
||||||
/// key of the peer.
|
|
||||||
#[get("/blocks")]
|
#[get("/blocks")]
|
||||||
pub fn blocks(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
pub async fn blocks(flash: Option<FlashMessage<'_>>, _auth: Authenticated) -> Template {
|
||||||
// retrieve current ui theme
|
// build the blocks context object
|
||||||
let theme = utils::get_theme();
|
let context = BlocksContext::build().await;
|
||||||
|
|
||||||
let mut context = BlocksContext::build();
|
|
||||||
context.back = Some("/scuttlebutt/peers".to_string());
|
|
||||||
context.title = Some("Blocks".to_string());
|
|
||||||
context.theme = Some(theme);
|
|
||||||
|
|
||||||
|
match context {
|
||||||
|
// we were able to build the context without errors
|
||||||
|
Ok(mut context) => {
|
||||||
// check to see if there is a flash message to display
|
// check to see if there is a flash message to display
|
||||||
if let Some(flash) = flash {
|
if let Some(flash) = flash {
|
||||||
// add flash message contents to the context object
|
// add flash message contents to the context object
|
||||||
|
@ -685,4 +822,15 @@ pub fn blocks(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
||||||
};
|
};
|
||||||
|
|
||||||
Template::render("scuttlebutt/peers_list", &context)
|
Template::render("scuttlebutt/peers_list", &context)
|
||||||
|
}
|
||||||
|
// an error occurred while building the context
|
||||||
|
Err(e) => {
|
||||||
|
// build the default context and pass along the error message
|
||||||
|
let mut context = BlocksContext::default();
|
||||||
|
context.flash_name = Some("error".to_string());
|
||||||
|
context.flash_msg = Some(e.to_string());
|
||||||
|
|
||||||
|
Template::render("scuttlebutt/peers_list", &context)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,16 +38,28 @@
|
||||||
<!-- TODO: each of these buttons needs to be a form with a public key -->
|
<!-- TODO: each of these buttons needs to be a form with a public key -->
|
||||||
<div id="buttons" style="margin-top: 2rem;">
|
<div id="buttons" style="margin-top: 2rem;">
|
||||||
{% if following == false %}
|
{% if following == false %}
|
||||||
<a id="followPeer" class="button button-primary center" href="/scuttlebutt/follow" title="Follow Peer">Follow</a>
|
<form id="followForm" action="/scuttlebutt/follow" method="post">
|
||||||
|
<input type="hidden" id="publicKey" name="public_key" value="{{ id }}">
|
||||||
|
<input id="followPeer" class="button button-primary center" type="submit" title="Follow Peer" value="Follow">
|
||||||
|
</form>
|
||||||
{% elif following == true %}
|
{% elif following == true %}
|
||||||
<a id="unfollowPeer" class="button button-primary center" href="/scuttlebutt/unfollow" title="Unfollow Peer">Unfollow</a>
|
<form id="unfollowForm" action="/scuttlebutt/unfollow" method="post">
|
||||||
|
<input type="hidden" id="publicKey" name="public_key" value="{{ id }}">
|
||||||
|
<input id="unfollowPeer" class="button button-primary center" type="submit" title="Unfollow Peer" value="Unfollow">
|
||||||
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>Unable to determine follow state</p>
|
<p>Unable to determine follow state</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if blocking == false %}
|
{% if blocking == false %}
|
||||||
<a id="blockPeer" class="button button-warning center" href="/scuttlebutt/block" title="Block Peer">Block</a>
|
<form id="blockForm" action="/scuttlebutt/block" method="post">
|
||||||
|
<input type="hidden" id="publicKey" name="public_key" value="{{ id }}">
|
||||||
|
<input id="blockPeer" class="button button-primary center" type="submit" title="Block Peer" value="Block">
|
||||||
|
</form>
|
||||||
{% elif blocking == true %}
|
{% elif blocking == true %}
|
||||||
<a id="unblockPeer" class="button button-warning center" href="/scuttlebutt/unblock" title="Unblock Peer">Unblock</a>
|
<form id="unblockForm" action="/scuttlebutt/unblock" method="post">
|
||||||
|
<input type="hidden" id="publicKey" name="public_key" value="{{ id }}">
|
||||||
|
<input id="unblockPeer" class="button button-primary center" type="submit" title="Unblock Peer" value="Unblock">
|
||||||
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>Unable to determine block state</p>
|
<p>Unable to determine block state</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
{%- extends "nav" -%}
|
{%- extends "nav" -%}
|
||||||
{%- block card %}
|
{%- block card %}
|
||||||
{# ASSIGN VARIABLES #}
|
|
||||||
{# ---------------- #}
|
|
||||||
<!-- PEER SEARCH FORM -->
|
<!-- PEER SEARCH FORM -->
|
||||||
<div class="card center">
|
<div class="card center">
|
||||||
<form id="sbotConfig" class="center" action="/scuttlebutt/search" method="post">
|
<form id="sbotConfig" class="center" action="/scuttlebutt/search" method="post">
|
||||||
<div class="center" style="display: flex; flex-direction: column; margin-bottom: 2rem;" title="Public key (ID) of a peer">
|
<div class="center" style="display: flex; flex-direction: column; margin-bottom: 2rem;" title="Public key (ID) of a peer">
|
||||||
<label for="publicKey" class="label-small font-gray">PUBLIC KEY</label>
|
<label for="publicKey" class="label-small font-gray">PUBLIC KEY</label>
|
||||||
<input type="text" id="publicKey" name="public_key" placeholder="@xYz...=.sha256">
|
<input type="text" id="publicKey" name="public_key" placeholder="@xYz...=.ed25519" autofocus>
|
||||||
</div>
|
</div>
|
||||||
<!-- BUTTONS -->
|
<!-- BUTTONS -->
|
||||||
<input id="search" class="button button-primary center" type="submit" title="Search for peer" value="Search">
|
<input id="search" class="button button-primary center" type="submit" title="Search for peer" value="Search">
|
||||||
|
|
Loading…
Reference in New Issue