//! Routes for Scuttlebutt related functionality. use rocket::{ form::{Form, FromForm}, get, post, request::FlashMessage, response::{Flash, Redirect}, serde::{Deserialize, Serialize}, uri, }; use rocket_dyn_templates::Template; use crate::routes::authentication::Authenticated; // HELPERS AND ROUTES FOR /private #[derive(Debug, Serialize)] pub struct PrivateContext { pub back: Option, pub flash_name: Option, pub flash_msg: Option, pub title: Option, } impl PrivateContext { pub fn build() -> PrivateContext { PrivateContext { back: None, flash_name: None, flash_msg: None, title: None, } } } /// A private message composition and publication page. #[get("/private")] pub fn private(flash: Option, _auth: Authenticated) -> Template { let mut context = PrivateContext::build(); context.back = Some("/".to_string()); context.title = Some("Private Messages".to_string()); // check to see if there is a flash message to display if let Some(flash) = flash { // add flash message contents to the context object context.flash_name = Some(flash.kind().to_string()); context.flash_msg = Some(flash.message().to_string()); }; Template::render("scuttlebutt/messages", &context) } // HELPERS AND ROUTES FOR /peers #[derive(Debug, Serialize)] pub struct PeerContext { pub back: Option, pub flash_name: Option, pub flash_msg: Option, pub title: Option, } impl PeerContext { pub fn build() -> PeerContext { PeerContext { back: None, flash_name: None, flash_msg: None, title: None, } } } /// A peer menu which allows navigating to lists of friends, follows, followers and blocks. #[get("/peers")] pub fn peers(flash: Option, _auth: Authenticated) -> Template { let mut context = PeerContext::build(); context.back = Some("/".to_string()); context.title = Some("Scuttlebutt Peers".to_string()); // check to see if there is a flash message to display if let Some(flash) = flash { // add flash message contents to the context object context.flash_name = Some(flash.kind().to_string()); context.flash_msg = Some(flash.message().to_string()); }; Template::render("scuttlebutt/peers", &context) } // HELPERS AND ROUTES FOR /post/publish #[derive(Debug, Deserialize, FromForm)] pub struct Post { pub text: String, } /// Publish a public Scuttlebutt post. Redirects to profile page of the PeachCloud local identity with a flash message describing the outcome of the action (may be successful or unsuccessful). #[post("/publish", data = "")] pub fn publish( post: Form, flash: Option, _auth: Authenticated, ) -> Flash { let post_text = &post.text; // perform the sbotcli publish action using post_text // if successful, redirect to home profile page and flash "success" // if error, redirect to home profile page and flash "error" // redirect to the profile template without public key ("home" / local profile) let pub_key: std::option::Option<&str> = None; let profile_url = uri!(profile(pub_key)); // consider adding the message reference to the flash message (or render it in the template for // `profile` Flash::success(Redirect::to(profile_url), "Published public post") } // HELPERS AND ROUTES FOR /follow #[derive(Debug, Deserialize, FromForm)] pub struct PublicKey { pub key: String, } /// Follow 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("/follow", data = "")] pub fn follow( pub_key: Form, flash: Option, _auth: Authenticated, ) -> Flash { let public_key = &pub_key.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!(profile(Some(public_key))); let success_msg = format!("Followed {}", public_key); Flash::success(Redirect::to(profile_url), success_msg) } // HELPERS AND ROUTES FOR /unfollow /// Unfollow 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("/unfollow", data = "")] pub fn unfollow( pub_key: Form, flash: Option, _auth: Authenticated, ) -> Flash { let public_key = &pub_key.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!(profile(Some(public_key))); let success_msg = format!("Unfollowed {}", public_key); Flash::success(Redirect::to(profile_url), success_msg) } // HELPERS AND ROUTES FOR /block /// Block 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("/block", data = "")] pub fn block( pub_key: Form, flash: Option, _auth: Authenticated, ) -> Flash { let public_key = &pub_key.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!(profile(Some(public_key))); let success_msg = format!("Blocked {}", public_key); Flash::success(Redirect::to(profile_url), success_msg) } // HELPERS AND ROUTES FOR /profile #[derive(Debug, Serialize)] pub struct ProfileContext { pub back: Option, pub flash_name: Option, pub flash_msg: Option, pub title: Option, } impl ProfileContext { pub fn build() -> ProfileContext { ProfileContext { back: None, flash_name: None, flash_msg: None, title: None, } } } /// A Scuttlebutt profile, specified by a public key. It may be our own profile or the profile of a peer. If not public key query parameter is provided, the local profile is displayed (ie. the profile of the public key associated with the local PeachCloud device). #[get("/profile?")] pub fn profile( pub_key: Option<&str>, flash: Option, _auth: Authenticated, ) -> Template { let mut context = ProfileContext::build(); context.back = Some("/".to_string()); context.title = Some("Profile".to_string()); // check to see if there is a flash message to display if let Some(flash) = flash { // add flash message contents to the context object context.flash_name = Some(flash.kind().to_string()); context.flash_msg = Some(flash.message().to_string()); }; Template::render("scuttlebutt/profile", &context) } // HELPERS AND ROUTES FOR /friends #[derive(Debug, Serialize)] pub struct FriendsContext { pub back: Option, pub flash_name: Option, pub flash_msg: Option, pub title: Option, } impl FriendsContext { pub fn build() -> FriendsContext { FriendsContext { back: None, flash_name: None, flash_msg: None, title: None, } } } /// A list of friends (mutual follows), with each list item displaying the name, image and public /// key of the peer. #[get("/friends")] pub fn friends(flash: Option, _auth: Authenticated) -> Template { let mut context = FriendsContext::build(); context.back = Some("/scuttlebutt/peers".to_string()); context.title = Some("Friends".to_string()); // check to see if there is a flash message to display if let Some(flash) = flash { // add flash message contents to the context object context.flash_name = Some(flash.kind().to_string()); context.flash_msg = Some(flash.message().to_string()); }; Template::render("scuttlebutt/peers_list", &context) } // HELPERS AND ROUTES FOR /follows #[derive(Debug, Serialize)] pub struct FollowsContext { pub back: Option, pub flash_name: Option, pub flash_msg: Option, pub title: Option, } impl FollowsContext { pub fn build() -> FollowsContext { FollowsContext { back: None, flash_name: None, flash_msg: None, title: None, } } } /// A list of follows (peers we follow who do not follow us), with each list item displaying the name, image and public /// key of the peer. #[get("/follows")] pub fn follows(flash: Option, _auth: Authenticated) -> Template { let mut context = FollowsContext::build(); context.back = Some("/scuttlebutt/peers".to_string()); context.title = Some("Follows".to_string()); // check to see if there is a flash message to display if let Some(flash) = flash { // add flash message contents to the context object context.flash_name = Some(flash.kind().to_string()); context.flash_msg = Some(flash.message().to_string()); }; Template::render("scuttlebutt/peers_list", &context) } // HELPERS AND ROUTES FOR /followers #[derive(Debug, Serialize)] pub struct FollowersContext { pub back: Option, pub flash_name: Option, pub flash_msg: Option, pub title: Option, } impl FollowersContext { pub fn build() -> FollowersContext { FollowersContext { back: None, flash_name: None, flash_msg: None, title: None, } } } /// A list of followers (peers who follow us but who we do not follow), with each list item displaying the name, image and public /// key of the peer. #[get("/followers")] pub fn followers(flash: Option, _auth: Authenticated) -> Template { let mut context = FollowersContext::build(); context.back = Some("/scuttlebutt/peers".to_string()); context.title = Some("Followers".to_string()); // check to see if there is a flash message to display if let Some(flash) = flash { // add flash message contents to the context object context.flash_name = Some(flash.kind().to_string()); context.flash_msg = Some(flash.message().to_string()); }; Template::render("scuttlebutt/peers_list", &context) } // HELPERS AND ROUTES FOR /blocks #[derive(Debug, Serialize)] pub struct BlocksContext { pub back: Option, pub flash_name: Option, pub flash_msg: Option, pub title: Option, } impl BlocksContext { pub fn build() -> BlocksContext { BlocksContext { back: None, flash_name: None, flash_msg: None, title: 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")] pub fn blocks(flash: Option, _auth: Authenticated) -> Template { let mut context = BlocksContext::build(); context.back = Some("/scuttlebutt/peers".to_string()); context.title = Some("Blocks".to_string()); // check to see if there is a flash message to display if let Some(flash) = flash { // add flash message contents to the context object context.flash_name = Some(flash.kind().to_string()); context.flash_msg = Some(flash.message().to_string()); }; Template::render("scuttlebutt/peers_list", &context) }