From cbd1ae6fa4152e54b3d560b58dec39d892fcf97f Mon Sep 17 00:00:00 2001
From: Leonora Tindall
Date: Mon, 31 Oct 2022 21:21:05 -0500
Subject: [PATCH] Fix error responses and content types
---
README.md | 3 +-
samples/corobel/.well-known/webfinger | 13 ------
src/main.rs | 64 ++++++++++++++++++++-------
src/webfinger.rs | 28 ++++++------
static/index.html | 3 ++
5 files changed, 67 insertions(+), 44 deletions(-)
delete mode 100644 samples/corobel/.well-known/webfinger
diff --git a/README.md b/README.md
index 98d10d7..c2ae58d 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,8 @@ ports to use for development and deployment.
- [x] Webfinger for Cohost projects
- [ ] Handle redirects
-- [ ] RSS feeds for projects
+- [x] RSS feeds for projects
+- [x] Index page explaining what's going on
- [ ] RSS feeds for tags
- [ ] Atom Extension pagination support
- [ ] Read More support
diff --git a/samples/corobel/.well-known/webfinger b/samples/corobel/.well-known/webfinger
deleted file mode 100644
index 622dcc6..0000000
--- a/samples/corobel/.well-known/webfinger
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "subject": "acct:noracodes@example.com",
- "aliases": [
- "acct:noracodes@cohost.org"
- ],
- "links": [
- {
- "rel": "http://webfinger.net/rel/profile-page",
- "type": "text/html",
- "href": "https://cohost.org/noracodes"
- }
- ]
-}
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 3fc8c28..f5b71c9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -37,8 +37,26 @@ fn index() -> RawHtml<&'static str> {
RawHtml(include_str!("../static/index.html"))
}
+#[derive(Responder)]
+#[response(content_type = "application/rss+xml")]
+struct RssResponse {
+ inner: String,
+}
+
+#[derive(Responder)]
+#[response(content_type = "text/plain")]
+enum ErrorResponse {
+ #[response(status = 404)]
+ NotFound(String),
+ #[response(status = 500)]
+ InternalError(String),
+}
+
#[get("//feed.rss?")]
-async fn syndication_rss_route(project: &str, page: Option) -> Option {
+async fn syndication_rss_route(
+ project: &str,
+ page: Option,
+) -> Result {
let page = page.unwrap_or(0);
let project_url = format!("{}{}", COHOST_ACCOUNT_API_URL, project);
let posts_url = cohost_posts_api_url(project, page);
@@ -49,25 +67,28 @@ async fn syndication_rss_route(project: &str, page: Option) -> Option match v.json::().await {
Ok(a) => a,
Err(e) => {
- eprintln!("Couldn't deserialize Cohost project '{}': {:?}", project, e);
- return None;
+ let err = format!("Couldn't deserialize Cohost project '{}': {:?}", project, e);
+ eprintln!("{}", err);
+ return Err(ErrorResponse::InternalError(err));
}
},
// TODO NORA: Handle possible redirects
s => {
- eprintln!(
+ let err = format!(
"Didn't receive status code 200 for Cohost project '{}'; got {:?} instead.",
project, s
);
- return None;
+ eprintln!("{}", err);
+ return Err(ErrorResponse::NotFound(err));
}
},
Err(e) => {
- eprintln!(
+ let err = format!(
"Error making request to Cohost for project '{}': {:?}",
project, e
);
- return None;
+ eprintln!("{}", err);
+ return Err(ErrorResponse::InternalError(err));
}
};
@@ -76,33 +97,41 @@ async fn syndication_rss_route(project: &str, page: Option) -> Option match v.status() {
StatusCode::OK => match v.json::().await {
Ok(page_data) => {
- return Some(
- syndication::channel_for_posts_page(project, page, project_data, page_data)
- .to_string(),
- );
+ return Ok(RssResponse {
+ inner: syndication::channel_for_posts_page(
+ project,
+ page,
+ project_data,
+ page_data,
+ )
+ .to_string(),
+ });
}
Err(e) => {
- eprintln!(
+ let err = format!(
"Couldn't deserialize Cohost posts page for '{}': {:?}",
project, e
);
+ eprintln!("{}", err);
+ return Err(ErrorResponse::InternalError(err));
}
},
// TODO NORA: Handle possible redirects
s => {
- eprintln!("Didn't receive status code 200 for posts for Cohost project '{}'; got {:?} instead.", page, s);
- return None;
+ let err = format!("Didn't receive status code 200 for posts for Cohost project '{}'; got {:?} instead.", page, s);
+ eprintln!("{}", err);
+ return Err(ErrorResponse::NotFound(err));
}
},
Err(e) => {
- eprintln!(
+ let err = format!(
"Error making request to Cohost for posts for project '{}': {:?}",
project, e
);
- return None;
+ eprintln!("{}", err);
+ return Err(ErrorResponse::InternalError(err));
}
};
- None
}
#[get("/.well-known/webfinger?")]
@@ -125,6 +154,7 @@ async fn webfinger_route(params: HashMap) -> Option {
diff --git a/src/webfinger.rs b/src/webfinger.rs
index 063a7a8..c69cd68 100644
--- a/src/webfinger.rs
+++ b/src/webfinger.rs
@@ -16,11 +16,24 @@ pub struct CohostWebfingerProfileLink {
}
impl CohostWebfingerResource {
- pub fn new, T: AsRef>(project_id: S, domain: T) -> Self {
+ pub fn new, T: AsRef>(
+ project_id: S,
+ domain: T,
+ base_url: impl AsRef,
+ ) -> Self {
+ let mut corobel_link = CohostWebfingerProfileLink::new(project_id.as_ref().clone());
+ corobel_link.href = format!(
+ "https://{}{}{}/feed.rss",
+ domain.as_ref().clone(),
+ base_url.as_ref().clone(),
+ project_id.as_ref().clone()
+ );
+ corobel_link.rel = "feed".into();
+ corobel_link.t_type = "application+rss/xml".into();
Self {
subject: format!("acct:{}@{}", project_id.as_ref(), domain.as_ref()),
aliases: vec![format!("acct:{}@cohost.org", project_id.as_ref())],
- links: vec![CohostWebfingerProfileLink::new(project_id)],
+ links: vec![CohostWebfingerProfileLink::new(project_id), corobel_link],
}
}
}
@@ -34,14 +47,3 @@ impl CohostWebfingerProfileLink {
}
}
}
-
-#[test]
-fn serialize_webfinger_resource() -> Result<(), Box> {
- let expected_json = include_str!("../samples/corobel/.well-known/webfinger");
- let resource: CohostWebfingerResource =
- CohostWebfingerResource::new("noracodes", "example.com");
- let actual_json = serde_json::to_string_pretty(&resource)?;
- println!("{}", actual_json);
- assert_eq!(&expected_json, &actual_json);
- Ok(())
-}
diff --git a/static/index.html b/static/index.html
index a8087f6..7649a33 100644
--- a/static/index.html
+++ b/static/index.html
@@ -30,6 +30,9 @@
Go to /project_name/feed.rss
to get a feed for a project.
For example, /noracodes/feed.rss
will give you the feed for my page.
+
+ Webfinger resources for accounts are provided at the Webfinger well-known URL /.well-known/webfinger?project_name
.
+
Brought to you by Leonora Tindall, written in Rust with Rocket.