From 9756a80094971db6e0792a1133700e45b5c262f9 Mon Sep 17 00:00:00 2001 From: glyph Date: Mon, 15 Nov 2021 11:59:14 +0200 Subject: [PATCH] add scuttlebutt routes --- peach-web/src/routes/scuttlebutt.rs | 279 ++++++++++++++++++++++++++-- 1 file changed, 266 insertions(+), 13 deletions(-) diff --git a/peach-web/src/routes/scuttlebutt.rs b/peach-web/src/routes/scuttlebutt.rs index 7e9200d..ec8d826 100644 --- a/peach-web/src/routes/scuttlebutt.rs +++ b/peach-web/src/routes/scuttlebutt.rs @@ -1,24 +1,30 @@ -//! Routes for ScuttleButt related functionality. +//! Routes for Scuttlebutt related functionality. -use rocket::{get, request::FlashMessage}; +use rocket::{ + form::{Form, FromForm}, + get, post, + request::FlashMessage, + response::{Flash, Redirect}, + serde::{Deserialize, Serialize}, + uri, +}; use rocket_dyn_templates::Template; -use serde::Serialize; use crate::routes::authentication::Authenticated; -// HELPERS AND ROUTES FOR /messages +// HELPERS AND ROUTES FOR /private #[derive(Debug, Serialize)] -pub struct MessageContext { +pub struct PrivateContext { pub back: Option, pub flash_name: Option, pub flash_msg: Option, pub title: Option, } -impl MessageContext { - pub fn build() -> MessageContext { - MessageContext { +impl PrivateContext { + pub fn build() -> PrivateContext { + PrivateContext { back: None, flash_name: None, flash_msg: None, @@ -27,9 +33,10 @@ impl MessageContext { } } -#[get("/messages")] -pub fn messages(flash: Option, _auth: Authenticated) -> Template { - let mut context = MessageContext::build(); +/// 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 @@ -62,6 +69,7 @@ impl PeerContext { } } +/// 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(); @@ -76,6 +84,94 @@ pub fn peers(flash: Option, _auth: Authenticated) -> Template { Template::render("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)] @@ -97,8 +193,13 @@ impl ProfileContext { } } -#[get("/profile")] -pub fn profile(flash: Option, _auth: Authenticated) -> Template { +/// 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()); @@ -110,3 +211,155 @@ pub fn profile(flash: Option, _auth: Authenticated) -> Template { }; Template::render("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("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("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("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("peers_list", &context) +}