improve messaging for when sbot is inactive

This commit is contained in:
glyph 2022-03-07 11:36:03 +02:00
parent 1a8ac3f57f
commit 983aa0689c
6 changed files with 242 additions and 187 deletions

View File

@ -424,98 +424,88 @@ impl ProfileContext {
// 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();
// retrieve latest go-sbot configuration parameters
let sbot_config = SbotConfig::read().ok();
let mut sbot_client = init_sbot_with_config(&sbot_config).await?;
let mut sbot_client = init_sbot_with_config(&sbot_config).await?;
let local_id = sbot_client.whoami().await?;
let local_id = sbot_client.whoami().await?;
// if an ssb_id has been provided to the context builder, we assume that
// the profile info being retrieved is for a peer (ie. not for our local
// profile)
let id = if ssb_id.is_some() {
// we are not dealing with the local profile
context.is_local_profile = false;
// if an ssb_id has been provided to the context builder, we assume that
// the profile info being retrieved is for a peer (ie. not for our local
// profile)
let id = if ssb_id.is_some() {
// we are not dealing with the local profile
context.is_local_profile = false;
// we're safe to unwrap here because we know it's `Some(id)`
let peer_id = ssb_id.unwrap();
// we're safe to unwrap here because we know it's `Some(id)`
let peer_id = ssb_id.unwrap();
// determine relationship between peer and local id
let follow_query = RelationshipQuery {
source: local_id.clone(),
dest: peer_id.clone(),
};
// query follow state
context.following = match sbot_client.friends_is_following(follow_query).await {
Ok(following) if following == "true" => Some(true),
Ok(following) if following == "false" => Some(false),
_ => None,
};
// TODO: i don't like that we have to instantiate the same query object
// twice. see if we can streamline this in golgi
let block_query = RelationshipQuery {
source: local_id.clone(),
dest: peer_id.clone(),
};
// query block state
context.blocking = match sbot_client.friends_is_blocking(block_query).await {
Ok(blocking) if blocking == "true" => Some(true),
Ok(blocking) if blocking == "false" => Some(false),
_ => None,
};
peer_id
} else {
// if an ssb_id has not been provided, retrieve the local id using whoami
context.is_local_profile = true;
local_id
// determine relationship between peer and local id
let follow_query = RelationshipQuery {
source: local_id.clone(),
dest: peer_id.clone(),
};
// TODO: add relationship state context if not local profile
// ie. lookup is_following and is_blocking, set context accordingly
// query follow state
context.following = match sbot_client.friends_is_following(follow_query).await {
Ok(following) if following == "true" => Some(true),
Ok(following) if following == "false" => Some(false),
_ => None,
};
// retrieve the profile info for the given id
let info = sbot_client.get_profile_info(&id).await?;
// set each context field accordingly
for (key, val) in info {
match key.as_str() {
"name" => context.name = Some(val),
"description" => context.description = Some(val),
"image" => context.image = Some(val),
_ => (),
}
}
// TODO: i don't like that we have to instantiate the same query object
// twice. see if we can streamline this in golgi
let block_query = RelationshipQuery {
source: local_id.clone(),
dest: peer_id.clone(),
};
// assign the ssb public key to the context
// (could be for the local profile or a peer)
context.id = Some(id);
// query block state
context.blocking = match sbot_client.friends_is_blocking(block_query).await {
Ok(blocking) if blocking == "true" => Some(true),
Ok(blocking) if blocking == "false" => Some(false),
_ => None,
};
// determine the path to the blob defined by the value of `context.image`
if let Some(ref blob_id) = context.image {
context.blob_path = match blobs::get_blob_path(&blob_id) {
Ok(path) => {
// if we get the path, check if the blob is in the blobstore.
// this allows us to default to a placeholder image in the template
if let Ok(exists) = utils::blob_is_stored_locally(&path).await {
context.blob_exists = exists
};
Some(path)
}
Err(_) => None,
}
}
peer_id
} 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, profile data cannot be retrieved. Visit the Scuttlebutt settings menu to start the Sbot and then try again".to_string());
// if an ssb_id has not been provided, retrieve the local id using whoami
context.is_local_profile = true;
local_id
};
// retrieve the profile info for the given id
let info = sbot_client.get_profile_info(&id).await?;
// set each context field accordingly
for (key, val) in info {
match key.as_str() {
"name" => context.name = Some(val),
"description" => context.description = Some(val),
"image" => context.image = Some(val),
_ => (),
}
}
// assign the ssb public key to the context
// (could be for the local profile or a peer)
context.id = Some(id);
// determine the path to the blob defined by the value of `context.image`
if let Some(ref blob_id) = context.image {
context.blob_path = match blobs::get_blob_path(&blob_id) {
Ok(path) => {
// if we get the path, check if the blob is in the blobstore.
// this allows us to default to a placeholder image in the template
if let Ok(exists) = utils::blob_is_stored_locally(&path).await {
context.blob_exists = exists
};
Some(path)
}
Err(_) => None,
}
}
context.sbot_status = Some(sbot_status);
@ -563,22 +553,15 @@ impl PrivateContext {
// 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();
// retrieve latest go-sbot configuration parameters
let sbot_config = SbotConfig::read().ok();
let mut sbot_client = init_sbot_with_config(&sbot_config).await?;
let mut sbot_client = init_sbot_with_config(&sbot_config).await?;
context.recipient_id = recipient_id;
context.recipient_id = recipient_id;
let local_id = sbot_client.whoami().await?;
context.id = Some(local_id);
} 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, private messages cannot be published. Visit the Scuttlebutt settings menu to start the Sbot and then try again".to_string());
}
let local_id = sbot_client.whoami().await?;
context.id = Some(local_id);
context.sbot_status = Some(sbot_status);

View File

@ -156,7 +156,7 @@ pub async fn create_invite(invite: Form<Invite>, _auth: Authenticated) -> Flash<
Ok(false) => {
return Flash::warning(
Redirect::to(url),
"The Sbot is currently inactive. As a result, new invite codes cannot be generated. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
"The Sbot is inactive. New invite codes cannot be generated. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
)
}
// failed to retrieve go-sbot systemd process status
@ -173,34 +173,53 @@ pub async fn private(
flash: Option<FlashMessage<'_>>,
_auth: Authenticated,
) -> Template {
if let Some(ref key) = public_key {
// `url_decode` replaces '+' with ' ', so we need to revert that
public_key = Some(key.replace(' ', "+"));
}
// display a helpful message if the sbot is inactive
if let Ok(false) = is_sbot_active() {
// retrieve current ui theme
let theme = utils::get_theme();
// build the private context object
let context = PrivateContext::build(public_key).await;
let mut context = Context::new();
context.insert("theme", &theme);
context.insert("back", &Some("/".to_string()));
context.insert("title", &Some("Private Messages".to_string()));
context.insert(
"unavailable_msg",
&Some("Private messages cannot be published.".to_string()),
);
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
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/private", &context)
// render the "sbot is inactive" template
return Template::render("scuttlebutt/inactive", &context.into_json());
// otherwise, build the full context and render the private message template
} else {
if let Some(ref key) = public_key {
// `url_decode` replaces '+' with ' ', so we need to revert that
public_key = Some(key.replace(' ', "+"));
}
// an error occurred while building the context
Err(e) => {
// build the default context and pass along the error message
let mut context = PrivateContext::default();
context.flash_name = Some("error".to_string());
context.flash_msg = Some(e.to_string());
Template::render("scuttlebutt/private", &context)
// build the private context object
let context = PrivateContext::build(public_key).await;
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
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/private", &context)
}
// an error occurred while building the context
Err(e) => {
// build the default context and pass along the error message
let mut context = PrivateContext::default();
context.flash_name = Some("error".to_string());
context.flash_msg = Some(e.to_string());
Template::render("scuttlebutt/private", &context)
}
}
}
}
@ -256,7 +275,7 @@ pub async fn private_post(private: Form<Private>, _auth: Authenticated) -> Flash
Ok(false) => {
return Flash::warning(
Redirect::to(url),
"The Sbot is currently inactive. As a result, new private message cannot be published. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
"The Sbot is inactive. New private message cannot be published. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
);
}
// failed to retrieve go-sbot systemd process status
@ -337,9 +356,13 @@ pub fn peers(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
// display a helpful message if the sbot is inactive
if let Ok(false) = is_sbot_active() {
context.insert("sbot_state", &Some("inactive".to_string()));
context.insert("flash_name", &Some("warning".to_string()));
context.insert("flash_msg", &Some("The Sbot is currently inactive. As a result, social lists and interactions are unavailable. Visit the Scuttlebutt settings menu to start the Sbot and then try again".to_string()));
context.insert(
"unavailable_msg",
&Some("Social lists and interactions are unavailable.".to_string()),
);
// render the "sbot is inactive" template
return Template::render("scuttlebutt/inactive", &context.into_json());
} else {
context.insert("sbot_state", &Some("active".to_string()));
// check to see if there is a flash message to display
@ -396,7 +419,7 @@ pub async fn publish(post: Form<Post>, _auth: Authenticated) -> Flash<Redirect>
Ok(false) => {
return Flash::warning(
Redirect::to(url),
"The Sbot is currently inactive. As a result, new posts cannot be published. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
"The Sbot is inactive. New posts cannot be published. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
);
}
Err(e) => return Flash::error(Redirect::to(url), e),
@ -439,7 +462,7 @@ pub async fn follow(peer: Form<Peer>, _auth: Authenticated) -> Flash<Redirect> {
Ok(false) => {
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",
"The Sbot is inactive. Follow messages cannot be published. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
);
}
Err(e) => return Flash::error(Redirect::to(url), e),
@ -484,7 +507,7 @@ pub async fn unfollow(peer: Form<Peer>, _auth: Authenticated) -> Flash<Redirect>
Ok(false) => {
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",
"The Sbot is inactive. Follow messages cannot be published. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
);
}
Err(e) => return Flash::error(Redirect::to(url), e),
@ -527,7 +550,7 @@ pub async fn block(peer: Form<Peer>, _auth: Authenticated) -> Flash<Redirect> {
Ok(false) => {
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",
"The Sbot is inactive. Follow messages cannot be published. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
);
}
Err(e) => return Flash::error(Redirect::to(url), e),
@ -571,7 +594,7 @@ pub async fn unblock(peer: Form<Peer>, _auth: Authenticated) -> Flash<Redirect>
Ok(false) => {
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",
"The Sbot is inactive. Follow messages cannot be published. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
);
}
Err(e) => return Flash::error(Redirect::to(url), e),
@ -590,41 +613,59 @@ pub async fn profile(
flash: Option<FlashMessage<'_>>,
_auth: Authenticated,
) -> Template {
if let Some(ref key) = public_key {
// `url_decode` replaces '+' with ' ', so we need to revert that
public_key = Some(key.replace(' ', "+"));
}
// display a helpful message if the sbot is inactive
if let Ok(false) = is_sbot_active() {
// retrieve current ui theme
let theme = utils::get_theme();
// build the profile context object
let context = ProfileContext::build(public_key).await;
let mut context = Context::new();
context.insert("theme", &theme);
context.insert("back", &Some("/".to_string()));
context.insert("title", &Some("Profile".to_string()));
context.insert(
"unavailable_msg",
&Some("Profile data cannot be retrieved.".to_string()),
);
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
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)
// render the "sbot is inactive" template
return Template::render("scuttlebutt/inactive", &context.into_json());
} else {
if let Some(ref key) = public_key {
// `url_decode` replaces '+' with ' ', so we need to revert that
public_key = Some(key.replace(' ', "+"));
}
// an error occurred while building the context
Err(e) => {
// build the default context and pass along the error message
let mut context = ProfileContext::default();
// flash name and msg will be `Some` if the sbot is inactive (in
// that case, they are set by the context builder).
// otherwise, we need to assign the name and returned error msg
// to the flash.
if context.flash_name.is_none() || context.flash_msg.is_none() {
context.flash_name = Some("error".to_string());
context.flash_msg = Some(e.to_string());
// build the profile context object
let context = ProfileContext::build(public_key).await;
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
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)
}
// an error occurred while building the context
Err(e) => {
// build the default context and pass along the error message
let mut context = ProfileContext::default();
Template::render("scuttlebutt/profile", &context)
// flash name and msg will be `Some` if the sbot is inactive (in
// that case, they are set by the context builder).
// otherwise, we need to assign the name and returned error msg
// to the flash.
if context.flash_name.is_none() || context.flash_msg.is_none() {
context.flash_name = Some("error".to_string());
context.flash_msg = Some(e.to_string());
}
Template::render("scuttlebutt/profile", &context)
}
}
}
}
@ -635,31 +676,49 @@ pub async fn profile(
/// for the local Scuttlebutt profile.
#[get("/profile/update")]
pub async fn update_profile(flash: Option<FlashMessage<'_>>, _auth: Authenticated) -> Template {
// build the profile context object
let context = ProfileContext::build(None).await;
// display a helpful message if the sbot is inactive
if let Ok(false) = is_sbot_active() {
// retrieve current ui theme
let theme = utils::get_theme();
match context {
// we were able to build the context without errors
Ok(mut context) => {
context.back = Some("/scuttlebutt/profile".to_string());
let mut context = Context::new();
context.insert("theme", &theme);
context.insert("back", &Some("/".to_string()));
context.insert("title", &Some("Profile".to_string()));
context.insert(
"unavailable_msg",
&Some("Profile data cannot be retrieved.".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());
};
// render the "sbot is inactive" template
return Template::render("scuttlebutt/inactive", &context.into_json());
} else {
// build the profile context object
let context = ProfileContext::build(None).await;
Template::render("scuttlebutt/update_profile", &context)
}
// an error occurred while building the context
Err(e) => {
// build the default context and pass along the error message
let mut context = ProfileContext::default();
context.flash_name = Some("error".to_string());
context.flash_msg = Some(e.to_string());
match context {
// we were able to build the context without errors
Ok(mut context) => {
context.back = Some("/scuttlebutt/profile".to_string());
Template::render("scuttlebutt/update_profile", &context)
// 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/update_profile", &context)
}
// an error occurred while building the context
Err(e) => {
// build the default context and pass along the error message
let mut context = ProfileContext::default();
context.flash_name = Some("error".to_string());
context.flash_msg = Some(e.to_string());
Template::render("scuttlebutt/update_profile", &context)
}
}
}
}
@ -780,7 +839,7 @@ pub async fn update_profile_post(
Ok(false) => {
return Flash::warning(
Redirect::to(url),
"The Sbot is currently inactive. As a result, profile data cannot be updated. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
"The Sbot is inactive. Profile data cannot be updated. Visit the Scuttlebutt settings menu to start the Sbot and then try again",
);
}
Err(e) => return Flash::error(Redirect::to(url), e),

View File

@ -0,0 +1,11 @@
{%- extends "nav" -%}
{%- block card %}
<!-- SBOT INACTIVE -->
<div class="card center">
<div class="capsule capsule-container border-warning center-text">
<p class="card-text" style="font-size: var(--font-size-4);">Sbot Inactive</p>
<p>{{ unavailable_msg }}</p>
<p class="card-text">Visit the <strong><a href="/settings/scuttlebutt" class="link font-near-black">Scuttlebutt settings menu</a></strong> to start the Sbot and then try again.</p>
</div>
</div>
{%- endblock card -%}

View File

@ -2,7 +2,7 @@
{%- block card %}
<div class="card center">
{%- if peers %}
<ul class="list">
<ul class="center list">
{%- for peer in peers %}
{# set a fall-back value for name in case the data is unavailable #}
{%- if not peer['name'] %}

View File

@ -1,7 +1,7 @@
{%- extends "nav" -%}
{%- block card %}
<!-- SCUTTLEBUTT PRIVATE MESSAGE FORM -->
<div class="card center">
<div class="card card-wide center">
{# only render the private message elements if the sbot is active #}
{%- if sbot_status and sbot_status.state == "active" %}
<form id="sbotConfig" class="center" action="/scuttlebutt/private" method="post">

View File

@ -1,7 +1,7 @@
{%- extends "nav" -%}
{%- block card %}
<!-- USER PROFILE -->
<div class="card center">
<div class="card card-wide center">
{# only render the profile info elements if the sbot is active #}
{%- if sbot_status and sbot_status.state == "active" %}
<!-- PROFILE INFO BOX -->
@ -38,12 +38,12 @@
<!-- TODO: each of these buttons needs to be a form with a public key -->
<div id="buttons" style="margin-top: 2rem;">
{% if following == false %}
<form id="followForm" action="/scuttlebutt/follow" method="post">
<form id="followForm" class="center" 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 %}
<form id="unfollowForm" action="/scuttlebutt/unfollow" method="post">
<form id="unfollowForm" class="center" 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>
@ -51,19 +51,21 @@
<p>Unable to determine follow state</p>
{% endif %}
{% if blocking == false %}
<form id="blockForm" action="/scuttlebutt/block" method="post">
<form id="blockForm" class="center" 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 %}
<form id="unblockForm" action="/scuttlebutt/unblock" method="post">
<form id="unblockForm" class="center" 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 %}
<p>Unable to determine block state</p>
{% endif %}
<a id="privateMessage" class="button button-primary center" href="/scuttlebutt/private?public_key={{ id }}" title="Private Message">Send Private Message</a>
<form class="center">
<a id="privateMessage" class="button button-primary center" href="/scuttlebutt/private?public_key={{ id }}" title="Private Message">Send Private Message</a>
</form>
</div>
{%- endif %}
{%- endif %}