Fix error responses and content types
This commit is contained in:
parent
25c6dffc85
commit
cbd1ae6fa4
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
64
src/main.rs
64
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("/<project>/feed.rss?<page>")]
|
||||
async fn syndication_rss_route(project: &str, page: Option<u64>) -> Option<String> {
|
||||
async fn syndication_rss_route(
|
||||
project: &str,
|
||||
page: Option<u64>,
|
||||
) -> Result<RssResponse, ErrorResponse> {
|
||||
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<u64>) -> Option<Strin
|
|||
StatusCode::OK => match v.json::<CohostAccount>().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<u64>) -> Option<Strin
|
|||
Ok(v) => match v.status() {
|
||||
StatusCode::OK => match v.json::<CohostPostsPage>().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?<params..>")]
|
||||
|
@ -125,6 +154,7 @@ async fn webfinger_route(params: HashMap<String, String>) -> Option<Json<CohostW
|
|||
return Some(Json(CohostWebfingerResource::new(
|
||||
param.0.as_str(),
|
||||
&ARGS.domain,
|
||||
&ARGS.base_url,
|
||||
)));
|
||||
}
|
||||
Err(e) => {
|
||||
|
|
|
@ -16,11 +16,24 @@ pub struct CohostWebfingerProfileLink {
|
|||
}
|
||||
|
||||
impl CohostWebfingerResource {
|
||||
pub fn new<S: AsRef<str>, T: AsRef<str>>(project_id: S, domain: T) -> Self {
|
||||
pub fn new<S: AsRef<str>, T: AsRef<str>>(
|
||||
project_id: S,
|
||||
domain: T,
|
||||
base_url: impl AsRef<str>,
|
||||
) -> 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<dyn std::error::Error>> {
|
||||
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(())
|
||||
}
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
Go to <code>/project_name/feed.rss</code> to get a feed for a project.
|
||||
For example, <a href="/noracodes/feed.rss"><code>/noracodes/feed.rss</code></a> will give you the feed for my page.
|
||||
</p>
|
||||
<p>
|
||||
Webfinger resources for accounts are provided at the Webfinger well-known URL <code>/.well-known/webfinger?project_name</code>.
|
||||
</p>
|
||||
<p>
|
||||
Brought to you by Leonora Tindall, written in Rust with Rocket.
|
||||
</p>
|
||||
|
|
Loading…
Reference in New Issue