peachpub mostly working

This commit is contained in:
notplants 2025-05-06 14:03:06 -04:00
parent fc2ea78876
commit bf05149d93
6 changed files with 191 additions and 161 deletions

View File

@ -29,67 +29,67 @@ pub fn build_template() -> PreEscaped<String> {
}
}
" 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("<!-- BUG REPORTS -->"))
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("<!-- REQUEST SUPPORT -->"))
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("<!-- CONTRIBUTE -->"))
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("<!-- BUG REPORTS -->"))
// 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("<!-- REQUEST SUPPORT -->"))
// 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("<!-- CONTRIBUTE -->"))
// 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."
// }
// }
}
}
};

View File

@ -17,10 +17,10 @@ pub fn build_template() -> PreEscaped<String> {
div class="card-container" {
(PreEscaped("<!-- BUTTONS -->"))
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" }
}
}

View File

@ -9,9 +9,9 @@ pub fn build_template() -> PreEscaped<String> {
div class="card center" {
(PreEscaped("<!-- BUTTONS -->"))
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" }
}
}

View File

@ -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<u64, PeachWebError> {
pub fn latest_sequence_number() -> Result<String, PeachWebError> {
// 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<HashMap<String, String>, Box<dyn
// insert the public key of the peer into the info hashmap
peer_info.insert("id".to_string(), key.to_string());
// retrieve the profile image blob id for the given peer
// TODO: blob support
// TODO: display profile photo blob
// // retrieve the profile image blob id for the given peer
// if let Some(blob_id) = peer_info.get("image") {
// // look-up the path for the image blob
// if let Ok(blob_path) = blobs::get_blob_path(blob_id) {
@ -586,15 +587,10 @@ pub fn publish_private_msg(text: String, recipients: Vec<String>) -> Result<Stri
let mut sbot_client = init_sbot_client()
.await?;
Err(PeachWebError::NotYetImplemented)
// debug!("Publishing a new Scuttlebutt private message");
// match sbot_client
// .publish_private(text.to_string(), recipients)
// .await
// {
// Ok(_) => 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<String, PeachWeb
// write file to temporary path
fs::write(&temp_path, &image.data)?;
// open the file and read it into a buffer
let mut file = File::open(&temp_path)?;
let mut buffer = Vec::new();
file.read_to_end(&mut buffer)?;
// create blob from file
let mut sbot_client = init_sbot_client().await?;
Err(PeachWebError::NotYetImplemented)
// TODO: not yet implemented
let blob_path = temp_path.to_str().ok_or("Error storing blob to disk").map_err(|e| PeachWebError::Tilde(TildeError {
message: format!("Error storing blob to disk: {}", e),
}))?;
let blob_id = sbot_client.store_blob(blob_path).await?;
// // hash the bytes representing the file
// let (hex_hash, blob_id) = blobs::hash_blob(&buffer)?;
//
// // define the blobstore path and blob filename
// let (blob_dir, blob_filename) = hex_hash.split_at(2);
// let go_ssb_path = get_go_ssb_path()?;
// let blobstore_sub_dir = format!("{}/blobs/sha256/{}", go_ssb_path, blob_dir);
//
// // create the blobstore sub-directory
// fs::create_dir_all(&blobstore_sub_dir)?;
//
// // copy the file to the blobstore
// let blob_path = format!("{}/{}", blobstore_sub_dir, blob_filename);
// fs::copy(temp_path, blob_path)?;
//
// Ok(blob_id)
Ok(blob_id)
}

View File

@ -6,7 +6,7 @@ use std::fmt;
/// all tilde client errors
#[derive(Debug)]
pub struct TildeError {
pub(crate) message: String,
pub message: String,
}
impl fmt::Display for TildeError {

View File

@ -3,7 +3,7 @@
use std::collections::HashMap;
pub use crate::error::TildeError;
use serde_json::Value;
use serde_json::{json, Value};
use std::process::{Command, exit};
mod error;
@ -56,6 +56,16 @@ impl TildeClient {
self.tilde_command_to_value(vec!["get_profile", "-i", key]).await
}
pub async fn latest_sequence_number(&self) -> Result<String, TildeError> {
let key = self.whoami().await?;
// let num = self.run_tilde_command(vec!["get_sequence", "-i", &key])?.parse::<u64>().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<bool, TildeError> {
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<String, TildeError> {
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<String, TildeError> {
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<String, TildeError> {
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<String, TildeError> {
self.run_tilde_command(vec!["store_blob", "-f", blob_file_path])
}
pub async fn private_message(&self, recipient_key: &str, message: &str) -> Result<String, TildeError> {
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<String, TildeError> {
// TODO: look up ip/domain from config
let key = self.whoami().await?;