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.