106 lines
3.4 KiB
Rust
106 lines
3.4 KiB
Rust
use super::types::{ActorExt, PublicKey, PublicKeyInner};
|
|
use super::util::accept;
|
|
use super::{keys, DOMAIN};
|
|
use crate::activitypub::db;
|
|
use crate::activitypub::types::{ImageExt, ImageExtData};
|
|
use activitystreams::actor::{ApActor, Person};
|
|
use activitystreams::base::AnyBase;
|
|
use activitystreams::collection::UnorderedCollection;
|
|
use activitystreams::object::Image;
|
|
use activitystreams::prelude::{ApActorExt, ObjectExt};
|
|
use activitystreams::{context, iri_string::types::IriString, prelude::*, security};
|
|
use axum::http::HeaderMap;
|
|
use axum::response::{IntoResponse, Redirect, Response};
|
|
use axum::{Extension, Json};
|
|
use hyper::{StatusCode, Uri};
|
|
use log::error;
|
|
use once_cell::sync::Lazy;
|
|
use sqlx::SqlitePool;
|
|
|
|
pub async fn handle(headers: HeaderMap, uri: Uri) -> Response {
|
|
let json = uri
|
|
.query()
|
|
.unwrap_or("")
|
|
.split("&")
|
|
.any(|p| p.split("=").next() == Some("json"));
|
|
if accept::accepts_html(&headers) && !json {
|
|
Redirect::permanent("/").into_response()
|
|
} else {
|
|
(
|
|
[("Content-Type", "application/activity+json")],
|
|
Json(actor()),
|
|
)
|
|
.into_response()
|
|
}
|
|
}
|
|
|
|
pub async fn handle_followers(Extension(pool): Extension<SqlitePool>) -> Response {
|
|
match db::get_followers(&pool).await {
|
|
Ok(followers) => {
|
|
let mut collection = UnorderedCollection::new();
|
|
collection.add_context(context());
|
|
collection.set_id(FOLLOWERS.clone());
|
|
collection.set_total_items(followers.len() as u64);
|
|
collection.set_many_items(
|
|
followers
|
|
.into_iter()
|
|
.map(|actor| AnyBase::from_xsd_string(actor.id)),
|
|
);
|
|
Json(collection).into_response()
|
|
}
|
|
Err(e) => {
|
|
error!("Error fetching followers: {:?}", e);
|
|
(
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
"Unable to fetch followers",
|
|
)
|
|
.into_response()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub static ID: Lazy<IriString> = Lazy::new(|| {
|
|
format!("https://{}/ap/actor", *DOMAIN)
|
|
.parse::<IriString>()
|
|
.unwrap()
|
|
});
|
|
static ICON_URL: Lazy<String> = Lazy::new(|| format!("https://{}/shadowfacts.png", *DOMAIN));
|
|
static INBOX: Lazy<IriString> = Lazy::new(|| {
|
|
format!("https://{}/ap/inbox", *DOMAIN)
|
|
.parse::<IriString>()
|
|
.unwrap()
|
|
});
|
|
pub static FOLLOWERS: Lazy<IriString> = Lazy::new(|| {
|
|
format!("https://{}/ap/actor/followers", *DOMAIN)
|
|
.parse::<IriString>()
|
|
.unwrap()
|
|
});
|
|
pub static KEY_ID: Lazy<IriString> = Lazy::new(|| {
|
|
format!("https://{}/ap/actor#main-key", *DOMAIN)
|
|
.parse::<IriString>()
|
|
.unwrap()
|
|
});
|
|
|
|
fn actor() -> ActorExt {
|
|
let key = PublicKey {
|
|
public_key: PublicKeyInner {
|
|
id: KEY_ID.clone(),
|
|
owner: ID.clone(),
|
|
public_key_pem: keys::PUB_KEY_PEM.clone(),
|
|
},
|
|
};
|
|
let mut actor = ActorExt::new(ApActor::new(INBOX.clone(), Person::new()), key);
|
|
actor.add_context(context());
|
|
actor.add_context(security());
|
|
actor.set_id(ID.clone());
|
|
actor.set_preferred_username("blog");
|
|
actor.set_name("shadowfacts' blog");
|
|
let image = ImageExt::new(
|
|
Image::new(),
|
|
ImageExtData::new("image/png".into(), ICON_URL.clone()),
|
|
);
|
|
actor.set_icon(image.into_any_base().unwrap());
|
|
actor.set_followers(FOLLOWERS.clone());
|
|
actor
|
|
}
|