mirror of
https://github.com/nullishamy/ferri.git
synced 2025-06-28 00:54:17 +00:00
refactor: cleanup; add missing APIs; reorganise
This commit is contained in:
parent
fafaf243c5
commit
ab9836293e
22 changed files with 529 additions and 870 deletions
|
@ -1,12 +1,12 @@
|
|||
use rocket::{
|
||||
get, serde::json::Json, FromFormField, State,
|
||||
};
|
||||
use main::types::{api, get};
|
||||
use main::{federation::http::HttpWrapper, types::{api, get}};
|
||||
use rocket_db_pools::Connection;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::{info, error};
|
||||
|
||||
use crate::{http_wrapper::HttpWrapper, AuthenticatedUser, Db};
|
||||
use crate::{AuthenticatedUser, Db};
|
||||
|
||||
#[derive(Serialize, Deserialize, FromFormField, Debug)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
|
|
|
@ -43,7 +43,7 @@ fn to_db_post(req: &CreateStatus, user: &AuthenticatedUser, config: &Config) ->
|
|||
uri: ObjectUri(config.post_url(&user.id.0, &post_id)),
|
||||
user: user.user.clone(),
|
||||
content: req.status.clone(),
|
||||
created_at: main::ap::now(),
|
||||
created_at: main::now(),
|
||||
boosted_post: None,
|
||||
attachments: vec![]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use main::ap;
|
||||
use main::federation::outbox::OutboxRequest;
|
||||
use main::federation::QueueMessage;
|
||||
use main::types::{api, get, ObjectUuid};
|
||||
use rocket::response::status::NotFound;
|
||||
use rocket::{
|
||||
|
@ -6,10 +7,9 @@ use rocket::{
|
|||
serde::{Deserialize, Serialize, json::Json},
|
||||
};
|
||||
use rocket_db_pools::Connection;
|
||||
use uuid::Uuid;
|
||||
use tracing::info;
|
||||
|
||||
use crate::{AuthenticatedUser, Db};
|
||||
use crate::{AuthenticatedUser, Db, OutboundQueue};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
|
@ -62,39 +62,38 @@ pub async fn verify_credentials(user: AuthenticatedUser) -> Json<CredentialAcoun
|
|||
#[post("/accounts/<uuid>/follow")]
|
||||
pub async fn new_follow(
|
||||
mut db: Connection<Db>,
|
||||
helpers: &State<crate::Helpers>,
|
||||
outbound: &State<OutboundQueue>,
|
||||
uuid: &str,
|
||||
user: AuthenticatedUser,
|
||||
) -> Result<(), NotFound<String>> {
|
||||
let http = &helpers.http;
|
||||
|
||||
let follower = ap::User::from_actor_id(&user.actor_id.0, &mut **db).await;
|
||||
|
||||
let followed = ap::User::from_id(uuid, &mut **db)
|
||||
let follower = user.user;
|
||||
let followed = get::user_by_id(ObjectUuid(uuid.to_string()), &mut **db)
|
||||
.await
|
||||
.map_err(|e| NotFound(e.to_string()))?;
|
||||
.unwrap();
|
||||
|
||||
let outbox = ap::Outbox::for_user(follower.clone(), http);
|
||||
|
||||
let activity = ap::Activity {
|
||||
id: format!("https://ferri.amy.mov/activities/{}", Uuid::new_v4()),
|
||||
ty: ap::ActivityType::Follow,
|
||||
object: followed.actor_id().to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let req = ap::OutgoingActivity {
|
||||
signed_by: format!("{}#main-key", follower.uri()),
|
||||
req: activity,
|
||||
to: followed.actor().clone(),
|
||||
};
|
||||
|
||||
req.save(&mut **db).await;
|
||||
outbox.post(req).await;
|
||||
let conn = db.into_inner();
|
||||
let conn = conn.detach();
|
||||
|
||||
let msg = QueueMessage::Outbound(OutboxRequest::Follow {
|
||||
follower,
|
||||
followed,
|
||||
conn
|
||||
});
|
||||
|
||||
outbound.0.send(msg).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[get("/accounts/relationships?<id>")]
|
||||
pub async fn relationships(
|
||||
id: Vec<String>,
|
||||
user: AuthenticatedUser
|
||||
) -> Result<Json<Vec<api::Relationship>>, ()> {
|
||||
info!("{} looking up relationships for {:#?}", user.username, id);
|
||||
Ok(Json(vec![]))
|
||||
}
|
||||
|
||||
#[get("/accounts/<uuid>")]
|
||||
pub async fn account(
|
||||
mut db: Connection<Db>,
|
||||
|
|
|
@ -50,23 +50,14 @@ pub async fn followers(
|
|||
mut db: Connection<Db>,
|
||||
uuid: &str,
|
||||
) -> Result<ActivityResponse<Json<OrderedCollection>>, NotFound<String>> {
|
||||
let target = main::ap::User::from_id(uuid, &mut **db)
|
||||
let user = get::user_by_id(ObjectUuid(uuid.to_string()), &mut **db)
|
||||
.await
|
||||
.map_err(|e| NotFound(e.to_string()))?;
|
||||
|
||||
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();
|
||||
|
||||
.unwrap();
|
||||
|
||||
let followers = get::followers_for_user(user.id.clone(), &mut **db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
ap_ok(Json(OrderedCollection {
|
||||
context: as_context(),
|
||||
ty: "OrderedCollection".to_string(),
|
||||
|
@ -74,8 +65,8 @@ pub async fn followers(
|
|||
id: format!("https://ferri.amy.mov/users/{}/followers", uuid),
|
||||
ordered_items: followers
|
||||
.into_iter()
|
||||
.map(|f| f.follower_id)
|
||||
.collect::<Vec<_>>(),
|
||||
.map(|f| f.follower.0)
|
||||
.collect(),
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -84,32 +75,23 @@ pub async fn following(
|
|||
mut db: Connection<Db>,
|
||||
uuid: &str,
|
||||
) -> Result<ActivityResponse<Json<OrderedCollection>>, NotFound<String>> {
|
||||
let target = main::ap::User::from_id(uuid, &mut **db)
|
||||
let user = get::user_by_id(ObjectUuid(uuid.to_string()), &mut **db)
|
||||
.await
|
||||
.map_err(|e| NotFound(e.to_string()))?;
|
||||
|
||||
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();
|
||||
|
||||
.unwrap();
|
||||
|
||||
let followers = get::following_for_user(user.id.clone(), &mut **db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
ap_ok(Json(OrderedCollection {
|
||||
context: as_context(),
|
||||
ty: "OrderedCollection".to_string(),
|
||||
total_items: 1,
|
||||
id: format!("https://ferri.amy.mov/users/{}/following", uuid),
|
||||
ordered_items: following
|
||||
ordered_items: followers
|
||||
.into_iter()
|
||||
.map(|f| f.followed_id)
|
||||
.collect::<Vec<_>>(),
|
||||
.map(|f| f.followed.0)
|
||||
.collect(),
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::Db;
|
||||
use main::ap;
|
||||
use main::types::api;
|
||||
use rocket::{State, get, serde::json::Json};
|
||||
use main::types::{api, get};
|
||||
use rocket::{get, serde::json::Json, State};
|
||||
use rocket_db_pools::Connection;
|
||||
use tracing::info;
|
||||
|
||||
|
@ -27,24 +26,26 @@ pub async fn webfinger(
|
|||
|
||||
let acct = resource.strip_prefix("acct:").unwrap();
|
||||
let (user, _) = acct.split_once("@").unwrap();
|
||||
let user = ap::User::from_username(user, &mut **db).await;
|
||||
let user = get::user_by_username(user, &mut **db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
Json(api::WebfingerHit {
|
||||
subject: resource.to_string(),
|
||||
aliases: vec![
|
||||
config.user_url(user.id()),
|
||||
config.user_web_url(user.username()),
|
||||
config.user_url(&user.id.0),
|
||||
config.user_web_url(&user.username),
|
||||
],
|
||||
links: vec![
|
||||
api::WebfingerLink {
|
||||
rel: "http://webfinger.net/rel/profile-page".to_string(),
|
||||
ty: Some("text/html".to_string()),
|
||||
href: Some(config.user_web_url(user.username())),
|
||||
href: Some(config.user_web_url(&user.username)),
|
||||
},
|
||||
api::WebfingerLink {
|
||||
rel: "self".to_string(),
|
||||
ty: Some("application/activity+json".to_string()),
|
||||
href: Some(config.user_url(user.id())),
|
||||
href: Some(config.user_url(&user.id.0)),
|
||||
},
|
||||
],
|
||||
})
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
use crate::http::HttpClient;
|
||||
use main::types::ap;
|
||||
use std::fmt::Debug;
|
||||
use thiserror::Error;
|
||||
use tracing::{Level, error, event, info};
|
||||
|
||||
pub struct HttpWrapper<'a> {
|
||||
client: &'a HttpClient,
|
||||
key_id: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum HttpError {
|
||||
#[error("entity of type `{0}` @ URL `{1}` could not be loaded")]
|
||||
LoadFailure(String, String),
|
||||
#[error("entity of type `{0}` @ URL `{1}` could not be parsed ({2})")]
|
||||
ParseFailure(String, String, String),
|
||||
}
|
||||
|
||||
impl<'a> HttpWrapper<'a> {
|
||||
pub fn new(client: &'a HttpClient, key_id: &'a str) -> HttpWrapper<'a> {
|
||||
Self { client, key_id }
|
||||
}
|
||||
|
||||
async fn get<T: serde::de::DeserializeOwned + Debug>(
|
||||
&self,
|
||||
ty: &str,
|
||||
url: &str,
|
||||
) -> Result<T, HttpError> {
|
||||
let ty = ty.to_string();
|
||||
event!(Level::INFO, url, "loading {}", ty);
|
||||
|
||||
let http_result = self
|
||||
.client
|
||||
.get(url)
|
||||
.sign(self.key_id)
|
||||
.activity()
|
||||
.send()
|
||||
.await;
|
||||
|
||||
if let Err(e) = http_result {
|
||||
error!("could not load url {}: {:#?}", url, e);
|
||||
return Err(HttpError::LoadFailure(ty, url.to_string()));
|
||||
}
|
||||
|
||||
let raw_body = http_result.unwrap().text().await;
|
||||
if let Err(e) = raw_body {
|
||||
error!("could not get text for url {}: {:#?}", url, e);
|
||||
return Err(HttpError::LoadFailure(ty, url.to_string()));
|
||||
}
|
||||
|
||||
let raw_body = raw_body.unwrap();
|
||||
info!("raw body {}", raw_body);
|
||||
let decoded = serde_json::from_str::<T>(&raw_body);
|
||||
|
||||
if let Err(e) = decoded {
|
||||
error!(
|
||||
"could not parse {} for url {}: {:#?} {}",
|
||||
ty, url, e, &raw_body
|
||||
);
|
||||
return Err(HttpError::ParseFailure(ty, url.to_string(), e.to_string()));
|
||||
}
|
||||
|
||||
Ok(decoded.unwrap())
|
||||
}
|
||||
|
||||
pub async fn get_person(&self, url: &str) -> Result<ap::Person, HttpError> {
|
||||
self.get("Person", url).await
|
||||
}
|
||||
}
|
|
@ -4,10 +4,8 @@ use endpoints::{
|
|||
};
|
||||
|
||||
use tracing_subscriber::fmt;
|
||||
use main::{federation::{self, http}, types::{db, get, ObjectUri, ObjectUuid}};
|
||||
|
||||
use main::{federation, types::{db, get, ObjectUri, ObjectUuid}};
|
||||
|
||||
use main::ap::http;
|
||||
use main::config::Config;
|
||||
use rocket::{
|
||||
Build, Request, Rocket, build, get,
|
||||
|
@ -170,6 +168,7 @@ pub fn launch(cfg: Config) -> Rocket<Build> {
|
|||
api::user::new_follow,
|
||||
api::user::statuses,
|
||||
api::user::account,
|
||||
api::user::relationships,
|
||||
api::apps::new_app,
|
||||
api::preferences::preferences,
|
||||
api::user::verify_credentials,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue