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
|
- [x] Webfinger for Cohost projects
|
||||||
- [ ] Handle redirects
|
- [ ] Handle redirects
|
||||||
- [ ] RSS feeds for projects
|
- [x] RSS feeds for projects
|
||||||
|
- [x] Index page explaining what's going on
|
||||||
- [ ] RSS feeds for tags
|
- [ ] RSS feeds for tags
|
||||||
- [ ] Atom Extension pagination support
|
- [ ] Atom Extension pagination support
|
||||||
- [ ] Read More 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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
62
src/main.rs
62
src/main.rs
|
@ -37,8 +37,26 @@ fn index() -> RawHtml<&'static str> {
|
||||||
RawHtml(include_str!("../static/index.html"))
|
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>")]
|
#[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 page = page.unwrap_or(0);
|
||||||
let project_url = format!("{}{}", COHOST_ACCOUNT_API_URL, project);
|
let project_url = format!("{}{}", COHOST_ACCOUNT_API_URL, project);
|
||||||
let posts_url = cohost_posts_api_url(project, page);
|
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 {
|
StatusCode::OK => match v.json::<CohostAccount>().await {
|
||||||
Ok(a) => a,
|
Ok(a) => a,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Couldn't deserialize Cohost project '{}': {:?}", project, e);
|
let err = format!("Couldn't deserialize Cohost project '{}': {:?}", project, e);
|
||||||
return None;
|
eprintln!("{}", err);
|
||||||
|
return Err(ErrorResponse::InternalError(err));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// TODO NORA: Handle possible redirects
|
// TODO NORA: Handle possible redirects
|
||||||
s => {
|
s => {
|
||||||
eprintln!(
|
let err = format!(
|
||||||
"Didn't receive status code 200 for Cohost project '{}'; got {:?} instead.",
|
"Didn't receive status code 200 for Cohost project '{}'; got {:?} instead.",
|
||||||
project, s
|
project, s
|
||||||
);
|
);
|
||||||
return None;
|
eprintln!("{}", err);
|
||||||
|
return Err(ErrorResponse::NotFound(err));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!(
|
let err = format!(
|
||||||
"Error making request to Cohost for project '{}': {:?}",
|
"Error making request to Cohost for project '{}': {:?}",
|
||||||
project, e
|
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() {
|
Ok(v) => match v.status() {
|
||||||
StatusCode::OK => match v.json::<CohostPostsPage>().await {
|
StatusCode::OK => match v.json::<CohostPostsPage>().await {
|
||||||
Ok(page_data) => {
|
Ok(page_data) => {
|
||||||
return Some(
|
return Ok(RssResponse {
|
||||||
syndication::channel_for_posts_page(project, page, project_data, page_data)
|
inner: syndication::channel_for_posts_page(
|
||||||
|
project,
|
||||||
|
page,
|
||||||
|
project_data,
|
||||||
|
page_data,
|
||||||
|
)
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!(
|
let err = format!(
|
||||||
"Couldn't deserialize Cohost posts page for '{}': {:?}",
|
"Couldn't deserialize Cohost posts page for '{}': {:?}",
|
||||||
project, e
|
project, e
|
||||||
);
|
);
|
||||||
|
eprintln!("{}", err);
|
||||||
|
return Err(ErrorResponse::InternalError(err));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// TODO NORA: Handle possible redirects
|
// TODO NORA: Handle possible redirects
|
||||||
s => {
|
s => {
|
||||||
eprintln!("Didn't receive status code 200 for posts for Cohost project '{}'; got {:?} instead.", page, s);
|
let err = format!("Didn't receive status code 200 for posts for Cohost project '{}'; got {:?} instead.", page, s);
|
||||||
return None;
|
eprintln!("{}", err);
|
||||||
|
return Err(ErrorResponse::NotFound(err));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!(
|
let err = format!(
|
||||||
"Error making request to Cohost for posts for project '{}': {:?}",
|
"Error making request to Cohost for posts for project '{}': {:?}",
|
||||||
project, e
|
project, e
|
||||||
);
|
);
|
||||||
return None;
|
eprintln!("{}", err);
|
||||||
|
return Err(ErrorResponse::InternalError(err));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/.well-known/webfinger?<params..>")]
|
#[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(
|
return Some(Json(CohostWebfingerResource::new(
|
||||||
param.0.as_str(),
|
param.0.as_str(),
|
||||||
&ARGS.domain,
|
&ARGS.domain,
|
||||||
|
&ARGS.base_url,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
|
@ -16,11 +16,24 @@ pub struct CohostWebfingerProfileLink {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CohostWebfingerResource {
|
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 {
|
Self {
|
||||||
subject: format!("acct:{}@{}", project_id.as_ref(), domain.as_ref()),
|
subject: format!("acct:{}@{}", project_id.as_ref(), domain.as_ref()),
|
||||||
aliases: vec![format!("acct:{}@cohost.org", project_id.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.
|
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.
|
For example, <a href="/noracodes/feed.rss"><code>/noracodes/feed.rss</code></a> will give you the feed for my page.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
Webfinger resources for accounts are provided at the Webfinger well-known URL <code>/.well-known/webfinger?project_name</code>.
|
||||||
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Brought to you by Leonora Tindall, written in Rust with Rocket.
|
Brought to you by Leonora Tindall, written in Rust with Rocket.
|
||||||
</p>
|
</p>
|
||||||
|
|
Loading…
Reference in New Issue