activitypub/src/lysand/http.rs

213 lines
6.2 KiB
Rust
Raw Normal View History

2024-06-27 05:13:38 +02:00
use activitypub_federation::{
2024-07-16 19:35:04 +02:00
fetch::{object_id::ObjectId, webfinger::webfinger_resolve_actor},
2024-07-17 02:08:39 +02:00
protocol::{context::WithContext, public_key::PublicKey},
2024-07-16 19:35:04 +02:00
traits::Object,
FEDERATION_CONTENT_TYPE,
2024-06-27 05:13:38 +02:00
};
use activitystreams_kinds::{activity::CreateType, object};
use actix_web::{get, web, HttpResponse};
2024-07-16 19:35:04 +02:00
use sea_orm::{query, ColumnTrait, EntityTrait, QueryFilter};
use url::Url;
2024-06-18 03:43:59 +02:00
use crate::{
database::State,
entities::{
post::{self, Entity},
2024-07-16 19:35:04 +02:00
prelude, user,
2024-06-18 03:43:59 +02:00
},
2024-07-16 19:35:04 +02:00
error,
lysand::conversion::{lysand_post_from_db, lysand_user_from_db},
objects,
2024-07-17 02:08:39 +02:00
utils::{base_url_decode, generate_create_id, generate_user_id},
Response, API_DOMAIN, DB, FEDERATION_CONFIG,
2024-06-18 03:43:59 +02:00
};
2024-07-16 19:35:04 +02:00
#[derive(serde::Deserialize)]
struct LysandQuery {
// Post url
url: Option<Url>,
// User handle
user: Option<String>,
// User URL
user_url: Option<Url>,
}
#[get("/apbridge/lysand/query")]
async fn query_post(
query: web::Query<LysandQuery>,
state: web::Data<State>,
) -> actix_web::Result<HttpResponse, error::Error> {
if query.url.is_none() && query.user.is_none() && query.user_url.is_none() {
return Ok(
HttpResponse::BadRequest().body("Bad Request. Error code: mrrrmrrrmrrawwawwawwa")
);
}
let db = DB.get().unwrap();
let data = FEDERATION_CONFIG.get().unwrap();
if let Some(user) = query.user.clone() {
let target =
webfinger_resolve_actor::<State, user::Model>(user.as_str(), &data.to_request_data())
.await?;
let lysand_user = lysand_user_from_db(target).await?;
return Ok(HttpResponse::Ok()
.content_type("application/json")
.json(lysand_user));
}
if let Some(user) = query.user_url.clone() {
let opt_model = prelude::User::find()
.filter(user::Column::Url.eq(user.as_str()))
.one(db)
2024-07-16 19:35:04 +02:00
.await?;
let target;
if let Some(model) = opt_model {
target = model;
} else {
target = ObjectId::<user::Model>::from(user)
.dereference(&data.to_request_data())
.await?;
}
2024-07-16 19:35:04 +02:00
let lysand_user = lysand_user_from_db(target).await?;
return Ok(HttpResponse::Ok()
.content_type("application/json")
.json(lysand_user));
}
2024-07-17 01:13:10 +02:00
let opt_model = prelude::Post::find()
2024-07-17 02:08:39 +02:00
.filter(post::Column::Url.eq(query.url.clone().unwrap().as_str()))
.one(db)
.await?;
let target;
if let Some(model) = opt_model {
target = model;
} else {
target = ObjectId::<post::Model>::from(Url::parse(query.url.clone().unwrap().as_str())?)
.dereference(&data.to_request_data())
2024-07-17 01:13:10 +02:00
.await?;
2024-07-17 02:08:39 +02:00
}
2024-07-16 19:35:04 +02:00
Ok(HttpResponse::Ok()
.content_type("application/json")
.json(lysand_post_from_db(target).await?))
}
#[get("/apbridge/object/{post}")]
async fn fetch_post(
path: web::Path<String>,
state: web::Data<State>,
) -> actix_web::Result<HttpResponse, error::Error> {
let db = DB.get().unwrap();
let post = prelude::Post::find()
.filter(post::Column::Id.eq(path.as_str()))
.one(db)
.await?;
let post = match post {
Some(post) => post,
None => return Ok(HttpResponse::NotFound().finish()),
};
2024-06-18 03:43:59 +02:00
Ok(HttpResponse::Ok()
.content_type(FEDERATION_CONTENT_TYPE)
2024-06-27 09:48:47 +02:00
.json(crate::objects::post::Note::from_db(&post)))
2024-06-18 03:43:59 +02:00
}
2024-06-27 05:13:38 +02:00
2024-07-17 02:08:39 +02:00
#[get("/apbridge/user/{user}")]
async fn fetch_user(
path: web::Path<String>,
state: web::Data<State>,
) -> actix_web::Result<HttpResponse, error::Error> {
let db = DB.get().unwrap();
let user = prelude::User::find()
2024-07-17 02:38:49 +02:00
.filter(user::Column::Id.eq(path.as_str()))
2024-07-17 02:08:39 +02:00
.one(db)
.await?;
let user = match user {
Some(user) => user,
None => return Ok(HttpResponse::NotFound().finish()),
};
Ok(HttpResponse::Ok()
.content_type(FEDERATION_CONTENT_TYPE)
.json(crate::objects::person::Person {
kind: Default::default(),
id: generate_user_id(&API_DOMAIN, &user.id)?.into(),
preferred_username: user.username.clone(),
name: user.name.clone(),
summary: user.summary.clone(),
url: Url::parse(user.url.as_str()).unwrap(),
inbox: Url::parse(user.inbox.as_str()).unwrap(),
public_key: PublicKey {
owner: Url::parse(user.url.as_str()).unwrap(),
public_key_pem: user.public_key,
id: format!("{}#main-key", Url::parse(user.url.as_str()).unwrap()),
},
}))
}
2024-07-16 19:35:04 +02:00
#[get("/apbridge/lysand/object/{post}")]
async fn fetch_lysand_post(
path: web::Path<String>,
state: web::Data<State>,
) -> actix_web::Result<HttpResponse, error::Error> {
let db = DB.get().unwrap();
let post = prelude::Post::find()
.filter(post::Column::Id.eq(path.as_str()))
.one(db)
.await?;
let post = match post {
Some(post) => post,
None => return Ok(HttpResponse::NotFound().finish()),
};
Ok(HttpResponse::Ok()
.content_type("application/json")
.json(lysand_post_from_db(post).await?))
}
2024-06-27 05:13:38 +02:00
#[get("/apbridge/create/{id}/{base64url}")]
async fn create_activity(
path: web::Path<(String, String)>,
state: web::Data<State>,
) -> actix_web::Result<HttpResponse, error::Error> {
let db = DB.get().unwrap();
let url = base_url_decode(path.1.as_str());
let post = prelude::Post::find()
.filter(post::Column::Id.eq(path.0.as_str()))
.one(db)
.await?;
let post = match post {
Some(post) => post,
None => return Ok(HttpResponse::NotFound().finish()),
};
let ap_post = crate::objects::post::Note::from_db(&post);
let data = FEDERATION_CONFIG.get().unwrap();
let create = crate::activities::create_post::CreatePost {
actor: ap_post.attributed_to.clone(),
to: ap_post.to.clone(),
object: ap_post,
kind: CreateType::Create,
id: generate_create_id(&data.to_request_data().domain(), &path.0, &path.1)?,
};
let create_with_context = WithContext::new_default(create);
Ok(HttpResponse::Ok()
.content_type(FEDERATION_CONTENT_TYPE)
.json(create_with_context))
}