ap types and nodeinfo
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
use std::sync::Arc;
|
||||
use axum::Json;
|
||||
use axum::extract::State;
|
||||
use axum::response::Response;
|
||||
|
||||
use crate::state::AppState;
|
||||
|
||||
pub async fn well_known(
|
||||
State(state): State<Arc<AppState>>,
|
||||
) -> Result<Json<serde_json::Value>, Response> {
|
||||
let ap = state.ap.as_ref().ok_or_else(|| {
|
||||
(axum::http::StatusCode::NOT_FOUND, "not found").into_response()
|
||||
})?;
|
||||
|
||||
Ok(Json(serde_json::json!({
|
||||
"links": [{
|
||||
"rel": "http://nodeinfo/2.1",
|
||||
"href": format!("https://{}/nodeinfo/2.1", ap.domain),
|
||||
}]
|
||||
})))
|
||||
}
|
||||
|
||||
use axum::response::IntoResponse;
|
||||
|
||||
pub async fn nodeinfo(
|
||||
State(state): State<Arc<AppState>>,
|
||||
) -> Result<Json<serde_json::Value>, Response> {
|
||||
let ap = state.ap.as_ref().ok_or_else(|| {
|
||||
(axum::http::StatusCode::NOT_FOUND, "not found").into_response()
|
||||
})?;
|
||||
|
||||
let dbi = state.db.lock().await;
|
||||
let users: i64 = dbi.db.query_row("SELECT COUNT(*) FROM sessions", [], |r| r.get(0)).unwrap_or(0);
|
||||
let puzzles: i64 = dbi.db.query_row("SELECT COUNT(*) FROM puzzles", [], |r| r.get(0)).unwrap_or(0);
|
||||
|
||||
Ok(Json(serde_json::json!({
|
||||
"version": "2.1",
|
||||
"software": {
|
||||
"name": "cruciverb",
|
||||
"version": env!("CARGO_PKG_VERSION"),
|
||||
"repository": "https://git.lashman.live/lashman/cruciverb",
|
||||
},
|
||||
"protocols": ["activitypub"],
|
||||
"services": { "inbound": [], "outbound": ["atom1.0", "rss2.0"] },
|
||||
"openRegistrations": true,
|
||||
"usage": {
|
||||
"users": { "total": users },
|
||||
"localPosts": puzzles,
|
||||
},
|
||||
"metadata": {
|
||||
"nodeName": format!("cruciverb @ {}", ap.domain),
|
||||
"nodeDescription": "self-hosted crossword puzzles",
|
||||
"features": ["daily_puzzles", "community_clues", "puzzle_editor", "cryptic_mode"],
|
||||
},
|
||||
})))
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const PUBLIC: &str = "https://www.w3.org/ns/activitystreams#Public";
|
||||
pub const CONTEXT: &str = "https://www.w3.org/ns/activitystreams";
|
||||
pub const SECURITY_CONTEXT: &str = "https://w3id.org/security/v1";
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Actor {
|
||||
#[serde(rename = "@context")]
|
||||
pub context: serde_json::Value,
|
||||
pub id: String,
|
||||
#[serde(rename = "type")]
|
||||
pub actor_type: String,
|
||||
#[serde(rename = "preferredUsername")]
|
||||
pub preferred_username: String,
|
||||
pub name: String,
|
||||
pub summary: String,
|
||||
pub inbox: String,
|
||||
pub outbox: String,
|
||||
pub followers: String,
|
||||
#[serde(rename = "publicKey")]
|
||||
pub public_key: ActorPublicKey,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub endpoints: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ActorPublicKey {
|
||||
pub id: String,
|
||||
pub owner: String,
|
||||
#[serde(rename = "publicKeyPem")]
|
||||
pub public_key_pem: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Activity {
|
||||
#[serde(rename = "@context", skip_serializing_if = "Option::is_none")]
|
||||
pub context: Option<serde_json::Value>,
|
||||
pub id: String,
|
||||
#[serde(rename = "type")]
|
||||
pub activity_type: String,
|
||||
pub actor: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub published: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub to: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub cc: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub object: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Note {
|
||||
#[serde(rename = "type")]
|
||||
pub note_type: String,
|
||||
pub id: String,
|
||||
#[serde(rename = "attributedTo")]
|
||||
pub attributed_to: String,
|
||||
pub content: String,
|
||||
pub published: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub url: Option<String>,
|
||||
pub to: Vec<String>,
|
||||
pub cc: Vec<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tag: Option<Vec<serde_json::Value>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub attachment: Option<Vec<serde_json::Value>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct OrderedCollection {
|
||||
#[serde(rename = "@context")]
|
||||
pub context: String,
|
||||
pub id: String,
|
||||
#[serde(rename = "type")]
|
||||
pub collection_type: String,
|
||||
#[serde(rename = "totalItems")]
|
||||
pub total_items: usize,
|
||||
#[serde(rename = "orderedItems")]
|
||||
pub ordered_items: Vec<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct WebFingerResponse {
|
||||
pub subject: String,
|
||||
pub links: Vec<WebFingerLink>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct WebFingerLink {
|
||||
pub rel: String,
|
||||
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
|
||||
pub link_type: Option<String>,
|
||||
pub href: String,
|
||||
}
|
||||
Reference in New Issue
Block a user