From bf05149d934823d05f23a3bfd8a56a8e58350da0 Mon Sep 17 00:00:00 2001 From: notplants Date: Tue, 6 May 2025 14:03:06 -0400 Subject: [PATCH] peachpub mostly working --- peach-web/src/routes/guide.rs | 116 ++++++------- peach-web/src/routes/scuttlebutt/peers.rs | 8 +- peach-web/src/routes/settings/admin/menu.rs | 4 +- peach-web/src/utils/sbot.rs | 171 +++++++++----------- tilde-client/src/error.rs | 2 +- tilde-client/src/lib.rs | 51 +++++- 6 files changed, 191 insertions(+), 161 deletions(-) diff --git a/peach-web/src/routes/guide.rs b/peach-web/src/routes/guide.rs index d5fc4eb..dab61a1 100644 --- a/peach-web/src/routes/guide.rs +++ b/peach-web/src/routes/guide.rs @@ -29,67 +29,67 @@ pub fn build_template() -> PreEscaped { } } " to start the sbot. If the server starts successfully, you will see a green smiley face on the home page. If the face is orange and sleeping, that means the sbot is still inactive (ie. the process is not running). If the face is red and dead, that means the sbot failed to start - indicated an error. For now, the best way to gain insight into the problem is to check the systemd log. Open a terminal and enter: " - code { "systemctl status go-sbot.service" } + code { "systemctl status tilde-sbot.service" } ". The log output may give some clues about the source of the error." } } - (PreEscaped("")) - details { - summary class="card-text link" { "Submit a bug report" } - p class="card-text" style="margin-top: 1rem; margin-bottom: 1rem;" { - "Bug reports can be submitted by " - strong { - a href="https://git.coopcloud.tech/PeachCloud/peach-workspace/issues/new?template=BUG_TEMPLATE.md" class="link font-gray" { - "filing an issue" - } - } - " on the peach-workspace git repo. Before filing a report, first check to see if an issue already exists for the bug you've encountered. If not, you're invited to submit a new report; the template will guide you through several questions." - } - } - (PreEscaped("")) - details { - summary class="card-text link" { "Share feedback & request support" } - p class="card-text" style="margin-top: 1rem; margin-bottom: 1rem;" { - "You're invited to share your thoughts and experiences of PeachCloud in the #peachcloud channel on Scuttlebutt. The channel is also a good place to ask for help." - } - p class="card-text" style="margin-top: 1rem; margin-bottom: 1rem;" { - "Alternatively, we have a " - strong { - a href="https://matrix.to/#/#peachcloud:matrix.org" class="link font-gray" { - "Matrix channel" - } - } - " for discussion about PeachCloud and you can also reach out to @glyph " - strong { - a href="mailto:glyph@mycelial.technology" class="link font-gray" { - "via email" - } - } - "." - } - } - (PreEscaped("")) - details { - summary class="card-text link" { "Contribute to PeachCloud" } - p class="card-text" style="margin-top: 1rem; margin-bottom: 1rem;" { - "PeachCloud is free, open-source software and relies on donations and grants to fund develop. Donations can be made on our " - strong { - a href="https://opencollective.com/peachcloud" class="link font-gray" { - "Open Collective" - } - } - " page." - } - p class="card-text" style="margin-top: 1rem; margin-bottom: 1rem;" { - "Programmers, designers, artists and writers are also welcome to contribute to the project. Please visit the " - strong { - a href="https://git.coopcloud.tech/PeachCloud/peach-workspace" class="link font-gray" { - "main PeachCloud git repository" - } - } - " to find out more details or contact the team via Scuttlebutt, Matrix or email." - } - } + // (PreEscaped("")) + // details { + // summary class="card-text link" { "Submit a bug report" } + // p class="card-text" style="margin-top: 1rem; margin-bottom: 1rem;" { + // "Bug reports can be submitted by " + // strong { + // a href="https://git.coopcloud.tech/PeachCloud/peach-workspace/issues/new?template=BUG_TEMPLATE.md" class="link font-gray" { + // "filing an issue" + // } + // } + // " on the peach-workspace git repo. Before filing a report, first check to see if an issue already exists for the bug you've encountered. If not, you're invited to submit a new report; the template will guide you through several questions." + // } + // } + // (PreEscaped("")) + // details { + // summary class="card-text link" { "Share feedback & request support" } + // p class="card-text" style="margin-top: 1rem; margin-bottom: 1rem;" { + // "You're invited to share your thoughts and experiences of PeachCloud in the #peachcloud channel on Scuttlebutt. The channel is also a good place to ask for help." + // } + // p class="card-text" style="margin-top: 1rem; margin-bottom: 1rem;" { + // "Alternatively, we have a " + // strong { + // a href="https://matrix.to/#/#peachcloud:matrix.org" class="link font-gray" { + // "Matrix channel" + // } + // } + // " for discussion about PeachCloud and you can also reach out to @glyph " + // strong { + // a href="mailto:glyph@mycelial.technology" class="link font-gray" { + // "via email" + // } + // } + // "." + // } + // } + // (PreEscaped("")) + // details { + // summary class="card-text link" { "Contribute to PeachCloud" } + // p class="card-text" style="margin-top: 1rem; margin-bottom: 1rem;" { + // "PeachCloud is free, open-source software and relies on donations and grants to fund develop. Donations can be made on our " + // strong { + // a href="https://opencollective.com/peachcloud" class="link font-gray" { + // "Open Collective" + // } + // } + // " page." + // } + // p class="card-text" style="margin-top: 1rem; margin-bottom: 1rem;" { + // "Programmers, designers, artists and writers are also welcome to contribute to the project. Please visit the " + // strong { + // a href="https://git.coopcloud.tech/PeachCloud/peach-workspace" class="link font-gray" { + // "main PeachCloud git repository" + // } + // } + // " to find out more details or contact the team via Scuttlebutt, Matrix or email." + // } + // } } } }; diff --git a/peach-web/src/routes/scuttlebutt/peers.rs b/peach-web/src/routes/scuttlebutt/peers.rs index 39bb64a..2ccb23f 100644 --- a/peach-web/src/routes/scuttlebutt/peers.rs +++ b/peach-web/src/routes/scuttlebutt/peers.rs @@ -17,10 +17,10 @@ pub fn build_template() -> PreEscaped { div class="card-container" { (PreEscaped("")) div id="buttons" { - a id="search" class="button button-primary center" href="/scuttlebutt/search" title="Search for a peer" { "Search" } - a id="friends" class="button button-primary center" href="/scuttlebutt/friends" title="List friends" { "Friends" } - a id="follows" class="button button-primary center" href="/scuttlebutt/follows" title="List follows" { "Follows" } - a id="blocks" class="button button-primary center" href="/scuttlebutt/blocks" title="List blocks" { "Blocks" } + // a id="search" class="button button-primary center" href="/scuttlebutt/search" title="Search for a peer" { "Search" } + // a id="friends" class="button button-primary center" href="/scuttlebutt/friends" title="List friends" { "Friends" } + // a id="follows" class="button button-primary center" href="/scuttlebutt/follows" title="List follows" { "Follows" } + // a id="blocks" class="button button-primary center" href="/scuttlebutt/blocks" title="List blocks" { "Blocks" } a id="invites" class="button button-primary center" href="/scuttlebutt/invites" title="Create invites" { "Invites" } } } diff --git a/peach-web/src/routes/settings/admin/menu.rs b/peach-web/src/routes/settings/admin/menu.rs index 49470d5..7a1d7ae 100644 --- a/peach-web/src/routes/settings/admin/menu.rs +++ b/peach-web/src/routes/settings/admin/menu.rs @@ -9,9 +9,9 @@ pub fn build_template() -> PreEscaped { div class="card center" { (PreEscaped("")) div id="settingsButtons" { - a id="configure" class="button button-primary center" href="/settings/admin/configure" title="Configure Admin" { "Configure Admin" } + // a id="configure" class="button button-primary center" href="/settings/admin/configure" title="Configure Admin" { "Configure Admin" } a id="change" class="button button-primary center" href="/auth/change" title="Change Password" { "Change Password" } - a id="reset" class="button button-primary center" href="/auth/reset" title="Reset Password" { "Reset Password" } + // a id="reset" class="button button-primary center" href="/auth/reset" title="Reset Password" { "Reset Password" } } } diff --git a/peach-web/src/utils/sbot.rs b/peach-web/src/utils/sbot.rs index e9dbdf6..29700b4 100644 --- a/peach-web/src/utils/sbot.rs +++ b/peach-web/src/utils/sbot.rs @@ -19,7 +19,7 @@ use peach_lib::ssb_messages::SsbMessageKVT; use rouille::input::post::BufferedFile; use temporary::Directory; use peach_lib::serde_json::json; -use peach_lib::tilde_client::TildeClient; +use peach_lib::tilde_client::{TildeClient, TildeError}; use crate::{error::PeachWebError, utils::sbot}; // SBOT HELPER FUNCTIONS @@ -114,14 +114,15 @@ pub fn validate_public_key(public_key: &str) -> Result<(), String> { /// reverses the list and reads the sequence number of the most recently /// authored message. This gives us the size of the database in terms of /// the total number of locally-authored messages. -pub fn latest_sequence_number() -> Result { +pub fn latest_sequence_number() -> Result { // retrieve latest solar-sbot configuration parameters let sbot_config = SbotConfig::read().ok(); task::block_on(async { let mut sbot_client = init_sbot_client().await?; - Err(PeachWebError::NotYetImplemented) + let sequence_num = sbot_client.latest_sequence_number().await?; + Ok(sequence_num) // retrieve the local id // let id = sbot_client.whoami().await?; @@ -278,67 +279,67 @@ pub fn update_profile_info( let sbot_config = SbotConfig::read().ok(); task::block_on(async { - let mut sbot_client = init_sbot_client() - .await?; + let mut sbot_client = init_sbot_client().await?; - Err(PeachWebError::NotYetImplemented) // // track whether the name, description or image have been updated - // let mut name_updated: bool = false; - // let mut description_updated: bool = false; - // let mut image_updated: bool = false; - // - // // check if a new_name value has been submitted in the form - // if let Some(name) = new_name { - // // only update the name if it has changed - // if name != current_name { - // debug!("Publishing a new Scuttlebutt profile name"); - // if let Err(e) = sbot_client.publish_name(&name).await { - // return Err(format!("Failed to update name: {}", e)); - // } else { - // name_updated = true - // } - // } - // } - // - // if let Some(description) = new_description { - // // only update the description if it has changed - // if description != current_description { - // debug!("Publishing a new Scuttlebutt profile description"); - // if let Err(e) = sbot_client.publish_description(&description).await { - // return Err(format!("Failed to update description: {}", e)); - // } else { - // description_updated = true - // } - // } - // } - // - // // only update the image if a file was uploaded - // if let Some(img) = image { - // // only write the blob if it has a filename and data > 0 bytes - // if img.filename.is_some() && !img.data.is_empty() { - // match write_blob_to_store(img).await { - // Ok(blob_id) => { - // // if the file was successfully added to the blobstore, - // // publish an about image message with the blob id - // if let Err(e) = sbot_client.publish_image(&blob_id).await { - // return Err(format!("Failed to update image: {}", e)); - // } else { - // image_updated = true - // } - // } - // Err(e) => return Err(format!("Failed to add image to blobstore: {}", e)), - // } - // } else { - // image_updated = false - // } - // } - // - // if name_updated || description_updated || image_updated { - // Ok("Profile updated".to_string()) - // } else { - // // no updates were made but no errors were encountered either - // Ok("Profile info unchanged".to_string()) - // } + let mut name_updated: bool = false; + let mut description_updated: bool = false; + let mut image_updated: bool = false; + + // check if a new_name value has been submitted in the form + if let Some(name) = new_name { + // only update the name if it has changed + if name != current_name { + debug!("Publishing a new Scuttlebutt profile name"); + if let Err(e) = sbot_client.publish_name(&name).await { + return Err(PeachWebError::Tilde(TildeError {message: (format!("Failed to update name: {}", e))})); + } else { + name_updated = true; + } + } + } + + if let Some(description) = new_description { + // only update the description if it has changed + if description != current_description { + debug!("Publishing a new Scuttlebutt profile description"); + if let Err(e) = sbot_client.publish_description(&description).await { + return Err(PeachWebError::Tilde(TildeError {message: (format!("Failed to update description: {}", e))})); + } else { + description_updated = true + } + } + } + + // only update the image if a file was uploaded + if let Some(img) = image { + // only write the blob if it has a filename and data > 0 bytes + if img.filename.is_some() && !img.data.is_empty() { + match write_blob_to_store(img).await { + Ok(blob_id) => { + // if the file was successfully added to the blobstore, + // publish an about image message with the blob id + if let Err(e) = sbot_client.publish_image(&blob_id).await { + return Err(PeachWebError::Tilde(TildeError {message: (format!("Failed to update image: {}", e))})); + } else { + image_updated = true + } + } + Err(e) => { + return Err(PeachWebError::Tilde(TildeError {message: (format!("Failed to add image to blob store: {}", e))})); + } + } + } else { + image_updated = false + } + } + + if name_updated || description_updated || image_updated { + Ok("Profile updated".to_string()) + } else { + // no updates were made but no errors were encountered either + Ok("Profile info unchanged".to_string()) + } }) } @@ -459,8 +460,8 @@ pub async fn get_peer_info(key: &str) -> Result, Box) -> Result Ok("Published private message".to_string()), - // Err(e) => Err(format!("Failed to publish private message: {}", e)), - // } + for recipient in &recipients { + sbot_client.private_message(recipient, &text).await?; + } + Ok("Published private message".to_string()) }) } @@ -643,28 +639,13 @@ pub async fn write_blob_to_store(image: BufferedFile) -> Result Result { + let key = self.whoami().await?; + // let num = self.run_tilde_command(vec!["get_sequence", "-i", &key])?.parse::().map_err(|e| TildeError { + // message: format!("Failed to parse u64 from sequence number: {}", e), + // })?; + let num = self.run_tilde_command(vec!["get_sequence", "-i", &key])?; + println!("NUM: {}", num); + Ok(num) + } + pub async fn is_following(&self, from_id: &str, to_id: &str) -> Result { todo!(); } @@ -81,6 +91,45 @@ impl TildeClient { self.run_tilde_command(vec!["publish", "-u", ":admin", "-i", &key, "-c", &json_string]) } + pub async fn publish_name(&self, name: &str) -> Result { + let key = self.whoami().await?; + let about_post = json!({ + "type": "about", + "about": key, + "name": name + }); + self.publish(about_post).await + } + + pub async fn publish_description(&self, description: &str) -> Result { + let key = self.whoami().await?; + let about_post = json!({ + "type": "about", + "about": key, + "description": description + }); + self.publish(about_post).await + } + + pub async fn publish_image(&self, image_blob_id: &str) -> Result { + let key = self.whoami().await?; + let about_post = json!({ + "type": "about", + "about": key, + "image": image_blob_id + }); + self.publish(about_post).await + } + + pub async fn store_blob(&self, blob_file_path: &str) -> Result { + self.run_tilde_command(vec!["store_blob", "-f", blob_file_path]) + } + + pub async fn private_message(&self, recipient_key: &str, message: &str) -> Result { + let self_key = self.whoami().await?; + self.run_tilde_command(vec!["private", "-u", ":admin", "-i", &self_key, "-r", recipient_key, "-t", message]) + } + pub async fn create_invite(&self, num_uses: i32) -> Result { // TODO: look up ip/domain from config let key = self.whoami().await?;