2025-04-11 12:29:29 +01:00
|
|
|
use main::ap;
|
2025-04-26 13:08:49 +01:00
|
|
|
use rocket::{get, http::ContentType, serde::json::Json, State};
|
2025-04-11 12:29:29 +01:00
|
|
|
use rocket_db_pools::Connection;
|
2025-04-25 16:46:47 +01:00
|
|
|
use rocket::response::status::NotFound;
|
2025-04-11 12:29:29 +01:00
|
|
|
|
|
|
|
use crate::{
|
2025-04-26 13:08:49 +01:00
|
|
|
Config,
|
2025-04-11 12:29:29 +01:00
|
|
|
Db,
|
2025-04-11 15:47:22 +01:00
|
|
|
types::{OrderedCollection, Person, UserKey, content},
|
2025-04-11 12:29:29 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
use super::activity_type;
|
|
|
|
|
2025-04-26 13:08:49 +01:00
|
|
|
#[get("/users/<_user>/inbox")]
|
|
|
|
pub async fn inbox(_user: String) -> Json<OrderedCollection> {
|
2025-04-11 12:29:29 +01:00
|
|
|
Json(OrderedCollection {
|
|
|
|
ty: "OrderedCollection".to_string(),
|
|
|
|
total_items: 0,
|
|
|
|
ordered_items: vec![],
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2025-04-26 13:08:49 +01:00
|
|
|
#[get("/users/<_user>/outbox")]
|
|
|
|
pub async fn outbox(_user: String) -> Json<OrderedCollection> {
|
2025-04-11 12:29:29 +01:00
|
|
|
Json(OrderedCollection {
|
|
|
|
ty: "OrderedCollection".to_string(),
|
|
|
|
total_items: 0,
|
|
|
|
ordered_items: vec![],
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2025-04-12 11:27:03 +01:00
|
|
|
#[get("/users/<uuid>/followers")]
|
2025-04-25 16:46:47 +01:00
|
|
|
pub async fn followers(mut db: Connection<Db>, uuid: &str) -> Result<Json<OrderedCollection>, NotFound<String>> {
|
|
|
|
let target = ap::User::from_id(uuid, &mut **db)
|
|
|
|
.await
|
|
|
|
.map_err(|e| NotFound(e.to_string()))?;
|
|
|
|
|
2025-04-11 12:29:29 +01:00
|
|
|
let actor_id = target.actor_id();
|
|
|
|
|
|
|
|
let followers = sqlx::query!(
|
|
|
|
r#"
|
|
|
|
SELECT follower_id FROM follow
|
|
|
|
WHERE followed_id = ?
|
|
|
|
"#,
|
|
|
|
actor_id
|
|
|
|
)
|
|
|
|
.fetch_all(&mut **db)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
2025-04-25 16:46:47 +01:00
|
|
|
Ok(Json(OrderedCollection {
|
2025-04-11 12:29:29 +01:00
|
|
|
ty: "OrderedCollection".to_string(),
|
|
|
|
total_items: 1,
|
|
|
|
ordered_items: followers
|
|
|
|
.into_iter()
|
|
|
|
.map(|f| f.follower_id)
|
|
|
|
.collect::<Vec<_>>(),
|
2025-04-25 16:46:47 +01:00
|
|
|
}))
|
2025-04-11 12:29:29 +01:00
|
|
|
}
|
|
|
|
|
2025-04-12 11:27:03 +01:00
|
|
|
#[get("/users/<uuid>/following")]
|
2025-04-25 16:46:47 +01:00
|
|
|
pub async fn following(mut db: Connection<Db>, uuid: &str) -> Result<Json<OrderedCollection>, NotFound<String>> {
|
|
|
|
let target = ap::User::from_id(uuid, &mut **db)
|
|
|
|
.await
|
|
|
|
.map_err(|e| NotFound(e.to_string()))?;
|
|
|
|
|
2025-04-11 12:29:29 +01:00
|
|
|
let actor_id = target.actor_id();
|
|
|
|
|
|
|
|
let following = sqlx::query!(
|
|
|
|
r#"
|
|
|
|
SELECT followed_id FROM follow
|
|
|
|
WHERE follower_id = ?
|
|
|
|
"#,
|
|
|
|
actor_id
|
|
|
|
)
|
|
|
|
.fetch_all(&mut **db)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
2025-04-25 16:46:47 +01:00
|
|
|
Ok(Json(OrderedCollection {
|
2025-04-11 12:29:29 +01:00
|
|
|
ty: "OrderedCollection".to_string(),
|
|
|
|
total_items: 1,
|
|
|
|
ordered_items: following
|
|
|
|
.into_iter()
|
|
|
|
.map(|f| f.followed_id)
|
|
|
|
.collect::<Vec<_>>(),
|
2025-04-25 16:46:47 +01:00
|
|
|
}))
|
2025-04-11 12:29:29 +01:00
|
|
|
}
|
|
|
|
|
2025-04-12 11:27:03 +01:00
|
|
|
#[get("/users/<uuid>/posts/<post>")]
|
2025-04-12 15:16:40 +01:00
|
|
|
pub async fn post(
|
|
|
|
mut db: Connection<Db>,
|
2025-04-26 13:08:49 +01:00
|
|
|
config: &State<Config>,
|
2025-04-12 15:16:40 +01:00
|
|
|
uuid: &str,
|
|
|
|
post: String,
|
|
|
|
) -> (ContentType, Json<content::Post>) {
|
|
|
|
let post = sqlx::query!(
|
|
|
|
r#"
|
2025-04-12 11:27:03 +01:00
|
|
|
SELECT * FROM post WHERE id = ?1
|
2025-04-12 15:16:40 +01:00
|
|
|
"#,
|
|
|
|
post
|
|
|
|
)
|
|
|
|
.fetch_one(&mut **db)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
2025-04-12 11:27:03 +01:00
|
|
|
|
2025-04-11 12:29:29 +01:00
|
|
|
(
|
|
|
|
activity_type(),
|
|
|
|
Json(content::Post {
|
|
|
|
context: "https://www.w3.org/ns/activitystreams".to_string(),
|
2025-04-26 13:08:49 +01:00
|
|
|
id: config.post_url(uuid, &post.id),
|
|
|
|
attributed_to: Some(config.user_url(uuid)),
|
2025-04-11 12:29:29 +01:00
|
|
|
ty: "Note".to_string(),
|
2025-04-12 11:27:03 +01:00
|
|
|
content: post.content,
|
|
|
|
ts: post.created_at,
|
2025-04-26 13:08:49 +01:00
|
|
|
to: vec![config.followers_url(uuid)],
|
2025-04-11 12:29:29 +01:00
|
|
|
cc: vec!["https://www.w3.org/ns/activitystreams#Public".to_string()],
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2025-04-12 11:27:03 +01:00
|
|
|
#[get("/users/<uuid>")]
|
2025-04-26 13:08:49 +01:00
|
|
|
pub async fn user(
|
|
|
|
mut db: Connection<Db>,
|
|
|
|
config: &State<Config>,
|
|
|
|
uuid: &str
|
|
|
|
) -> Result<(ContentType, Json<Person>), NotFound<String>> {
|
2025-04-25 16:46:47 +01:00
|
|
|
let user = ap::User::from_id(uuid, &mut **db)
|
|
|
|
.await
|
|
|
|
.map_err(|e| NotFound(e.to_string()))?;
|
|
|
|
|
|
|
|
Ok((
|
2025-04-11 12:29:29 +01:00
|
|
|
activity_type(),
|
|
|
|
Json(Person {
|
|
|
|
context: "https://www.w3.org/ns/activitystreams".to_string(),
|
|
|
|
ty: "Person".to_string(),
|
2025-04-26 13:08:49 +01:00
|
|
|
id: config.user_url(user.id()),
|
2025-04-12 11:27:03 +01:00
|
|
|
name: user.username().to_string(),
|
|
|
|
preferred_username: user.display_name().to_string(),
|
2025-04-26 13:08:49 +01:00
|
|
|
followers: config.followers_url(user.id()),
|
|
|
|
following: config.following_url(user.id()),
|
2025-04-12 11:27:03 +01:00
|
|
|
summary: format!("ferri {}", user.username()),
|
2025-04-26 13:08:49 +01:00
|
|
|
inbox: config.inbox_url(user.id()),
|
|
|
|
outbox: config.outbox_url(user.id()),
|
2025-04-11 12:29:29 +01:00
|
|
|
public_key: Some(UserKey {
|
2025-04-12 11:27:03 +01:00
|
|
|
id: format!("https://ferri.amy.mov/users/{}#main-key", uuid),
|
2025-04-26 13:08:49 +01:00
|
|
|
owner: config.user_url(user.id()),
|
2025-04-11 12:29:29 +01:00
|
|
|
public_key: include_str!("../../../public.pem").to_string(),
|
|
|
|
}),
|
|
|
|
}),
|
2025-04-25 16:46:47 +01:00
|
|
|
))
|
2025-04-11 12:29:29 +01:00
|
|
|
}
|