@ -1,90 +0,0 @@ | |||
extern crate activitypub; | |||
use self::activitypub::{actor::Person, context}; | |||
use crate::db::user::User_; | |||
impl User_ { | |||
pub fn person(&self) -> Person { | |||
use crate::{to_datetime_utc, Settings}; | |||
let base_url = &format!("{}/user/{}", Settings::get().api_endpoint(), self.name); | |||
let mut person = Person::default(); | |||
person.object_props.set_context_object(context()).ok(); | |||
person.object_props.set_id_string(base_url.to_string()).ok(); | |||
person | |||
.object_props | |||
.set_name_string(self.name.to_owned()) | |||
.ok(); | |||
person | |||
.object_props | |||
.set_published_utctime(to_datetime_utc(self.published)) | |||
.ok(); | |||
if let Some(i) = self.updated { | |||
person | |||
.object_props | |||
.set_updated_utctime(to_datetime_utc(i)) | |||
.ok(); | |||
} | |||
// person.object_props.summary = self.summary; | |||
person | |||
.ap_actor_props | |||
.set_inbox_string(format!("{}/inbox", &base_url)) | |||
.ok(); | |||
person | |||
.ap_actor_props | |||
.set_outbox_string(format!("{}/outbox", &base_url)) | |||
.ok(); | |||
person | |||
.ap_actor_props | |||
.set_following_string(format!("{}/following", &base_url)) | |||
.ok(); | |||
person | |||
.ap_actor_props | |||
.set_liked_string(format!("{}/liked", &base_url)) | |||
.ok(); | |||
if let Some(i) = &self.preferred_username { | |||
person | |||
.ap_actor_props | |||
.set_preferred_username_string(i.to_string()) | |||
.ok(); | |||
} | |||
person | |||
} | |||
} | |||
#[cfg(test)] | |||
mod tests { | |||
use super::User_; | |||
use crate::db::{ListingType, SortType}; | |||
use crate::naive_now; | |||
#[test] | |||
fn test_person() { | |||
let expected_user = User_ { | |||
id: 52, | |||
name: "thom".into(), | |||
fedi_name: "rrf".into(), | |||
preferred_username: None, | |||
password_encrypted: "here".into(), | |||
email: None, | |||
icon: None, | |||
published: naive_now(), | |||
admin: false, | |||
banned: false, | |||
updated: None, | |||
show_nsfw: false, | |||
theme: "darkly".into(), | |||
default_sort_type: SortType::Hot as i16, | |||
default_listing_type: ListingType::Subscribed as i16, | |||
lang: "browser".into(), | |||
}; | |||
let person = expected_user.person(); | |||
assert_eq!( | |||
"rrr/api/v1/user/thom", | |||
person.object_props.id_string().unwrap() | |||
); | |||
let json = serde_json::to_string_pretty(&person).unwrap(); | |||
println!("{}", json); | |||
} | |||
} |
@ -0,0 +1,112 @@ | |||
use crate::apub::make_apub_endpoint; | |||
use crate::db::community::Community; | |||
use crate::db::community_view::CommunityFollowerView; | |||
use crate::db::establish_connection; | |||
use crate::to_datetime_utc; | |||
use activitypub::{actor::Group, collection::UnorderedCollection, context}; | |||
use actix_web::body::Body; | |||
use actix_web::web::Path; | |||
use actix_web::HttpResponse; | |||
use serde::Deserialize; | |||
impl Community { | |||
pub fn as_group(&self) -> Group { | |||
let base_url = make_apub_endpoint("c", &self.name); | |||
let mut group = Group::default(); | |||
group.object_props.set_context_object(context()).ok(); | |||
group.object_props.set_id_string(base_url.to_string()).ok(); | |||
group | |||
.object_props | |||
.set_name_string(self.name.to_owned()) | |||
.ok(); | |||
group | |||
.object_props | |||
.set_published_utctime(to_datetime_utc(self.published)) | |||
.ok(); | |||
if let Some(updated) = self.updated { | |||
group | |||
.object_props | |||
.set_updated_utctime(to_datetime_utc(updated)) | |||
.ok(); | |||
} | |||
if let Some(description) = &self.description { | |||
group | |||
.object_props | |||
.set_summary_string(description.to_string()) | |||
.ok(); | |||
} | |||
group | |||
.ap_actor_props | |||
.set_inbox_string(format!("{}/inbox", &base_url)) | |||
.ok(); | |||
group | |||
.ap_actor_props | |||
.set_outbox_string(format!("{}/outbox", &base_url)) | |||
.ok(); | |||
group | |||
.ap_actor_props | |||
.set_followers_string(format!("{}/followers", &base_url)) | |||
.ok(); | |||
group | |||
} | |||
pub fn followers_as_collection(&self) -> UnorderedCollection { | |||
let base_url = make_apub_endpoint("c", &self.name); | |||
let mut collection = UnorderedCollection::default(); | |||
collection.object_props.set_context_object(context()).ok(); | |||
collection | |||
.object_props | |||
.set_id_string(base_url.to_string()) | |||
.ok(); | |||
let connection = establish_connection(); | |||
//As we are an object, we validated that the community id was valid | |||
let community_followers = CommunityFollowerView::for_community(&connection, self.id).unwrap(); | |||
let ap_followers = community_followers | |||
.iter() | |||
.map(|follower| make_apub_endpoint("u", &follower.user_name)) | |||
.collect(); | |||
collection | |||
.collection_props | |||
.set_items_string_vec(ap_followers) | |||
.unwrap(); | |||
collection | |||
} | |||
} | |||
#[derive(Deserialize)] | |||
pub struct CommunityQuery { | |||
community_name: String, | |||
} | |||
pub fn get_apub_community(info: Path<CommunityQuery>) -> HttpResponse<Body> { | |||
let connection = establish_connection(); | |||
if let Ok(community) = Community::read_from_name(&connection, info.community_name.to_owned()) { | |||
HttpResponse::Ok() | |||
.content_type("application/activity+json") | |||
.body(serde_json::to_string(&community.as_group()).unwrap()) | |||
} else { | |||
HttpResponse::NotFound().finish() | |||
} | |||
} | |||
pub fn get_apub_community_followers(info: Path<CommunityQuery>) -> HttpResponse<Body> { | |||
let connection = establish_connection(); | |||
if let Ok(community) = Community::read_from_name(&connection, info.community_name.to_owned()) { | |||
HttpResponse::Ok() | |||
.content_type("application/activity+json") | |||
.body(serde_json::to_string(&community.followers_as_collection()).unwrap()) | |||
} else { | |||
HttpResponse::NotFound().finish() | |||
} | |||
} |
@ -0,0 +1,100 @@ | |||
pub mod community; | |||
pub mod post; | |||
pub mod user; | |||
use crate::Settings; | |||
use std::fmt::Display; | |||
#[cfg(test)] | |||
mod tests { | |||
use crate::db::community::Community; | |||
use crate::db::post::Post; | |||
use crate::db::user::User_; | |||
use crate::db::{ListingType, SortType}; | |||
use crate::{naive_now, Settings}; | |||
#[test] | |||
fn test_person() { | |||
let user = User_ { | |||
id: 52, | |||
name: "thom".into(), | |||
fedi_name: "rrf".into(), | |||
preferred_username: None, | |||
password_encrypted: "here".into(), | |||
email: None, | |||
icon: None, | |||
published: naive_now(), | |||
admin: false, | |||
banned: false, | |||
updated: None, | |||
show_nsfw: false, | |||
theme: "darkly".into(), | |||
default_sort_type: SortType::Hot as i16, | |||
default_listing_type: ListingType::Subscribed as i16, | |||
lang: "browser".into(), | |||
}; | |||
let person = user.as_person(); | |||
assert_eq!( | |||
format!("https://{}/federation/u/thom", Settings::get().hostname), | |||
person.object_props.id_string().unwrap() | |||
); | |||
} | |||
#[test] | |||
fn test_community() { | |||
let community = Community { | |||
id: 42, | |||
name: "Test".into(), | |||
title: "Test Title".into(), | |||
description: Some("Test community".into()), | |||
category_id: 32, | |||
creator_id: 52, | |||
removed: false, | |||
published: naive_now(), | |||
updated: Some(naive_now()), | |||
deleted: false, | |||
nsfw: false, | |||
}; | |||
let group = community.as_group(); | |||
assert_eq!( | |||
format!("https://{}/federation/c/Test", Settings::get().hostname), | |||
group.object_props.id_string().unwrap() | |||
); | |||
} | |||
#[test] | |||
fn test_post() { | |||
let post = Post { | |||
id: 62, | |||
name: "A test post".into(), | |||
url: None, | |||
body: None, | |||
creator_id: 52, | |||
community_id: 42, | |||
published: naive_now(), | |||
removed: false, | |||
locked: false, | |||
stickied: false, | |||
nsfw: false, | |||
deleted: false, | |||
updated: None, | |||
}; | |||
let page = post.as_page(); | |||
assert_eq!( | |||
format!("https://{}/federation/post/62", Settings::get().hostname), | |||
page.object_props.id_string().unwrap() | |||
); | |||
} | |||
} | |||
pub fn make_apub_endpoint<S: Display, T: Display>(point: S, value: T) -> String { | |||
format!( | |||
"https://{}/federation/{}/{}", | |||
Settings::get().hostname, | |||
point, | |||
value | |||
) | |||
} |
@ -0,0 +1,38 @@ | |||
use crate::apub::make_apub_endpoint; | |||
use crate::db::post::Post; | |||
use crate::to_datetime_utc; | |||
use activitypub::{context, object::Page}; | |||
impl Post { | |||
pub fn as_page(&self) -> Page { | |||
let base_url = make_apub_endpoint("post", self.id); | |||
let mut page = Page::default(); | |||
page.object_props.set_context_object(context()).ok(); | |||
page.object_props.set_id_string(base_url.to_string()).ok(); | |||
page.object_props.set_name_string(self.name.to_owned()).ok(); | |||
if let Some(body) = &self.body { | |||
page.object_props.set_content_string(body.to_owned()).ok(); | |||
} | |||
if let Some(url) = &self.url { | |||
page.object_props.set_url_string(url.to_owned()).ok(); | |||
} | |||
//page.object_props.set_attributed_to_string | |||
page | |||
.object_props | |||
.set_published_utctime(to_datetime_utc(self.published)) | |||
.ok(); | |||
if let Some(updated) = self.updated { | |||
page | |||
.object_props | |||
.set_updated_utctime(to_datetime_utc(updated)) | |||
.ok(); | |||
} | |||
page | |||
} | |||
} |
@ -0,0 +1,74 @@ | |||
use crate::apub::make_apub_endpoint; | |||
use crate::db::establish_connection; | |||
use crate::db::user::User_; | |||
use crate::to_datetime_utc; | |||
use activitypub::{actor::Person, context}; | |||
use actix_web::body::Body; | |||
use actix_web::web::Path; | |||
use actix_web::HttpResponse; | |||
use serde::Deserialize; | |||
impl User_ { | |||
pub fn as_person(&self) -> Person { | |||
let base_url = make_apub_endpoint("u", &self.name); | |||
let mut person = Person::default(); | |||
person.object_props.set_context_object(context()).ok(); | |||
person.object_props.set_id_string(base_url.to_string()).ok(); | |||
person | |||
.object_props | |||
.set_name_string(self.name.to_owned()) | |||
.ok(); | |||
person | |||
.object_props | |||
.set_published_utctime(to_datetime_utc(self.published)) | |||
.ok(); | |||
if let Some(updated) = self.updated { | |||
person | |||
.object_props | |||
.set_updated_utctime(to_datetime_utc(updated)) | |||
.ok(); | |||
} | |||
person | |||
.ap_actor_props | |||
.set_inbox_string(format!("{}/inbox", &base_url)) | |||
.ok(); | |||
person | |||
.ap_actor_props | |||
.set_outbox_string(format!("{}/outbox", &base_url)) | |||
.ok(); | |||
person | |||
.ap_actor_props | |||
.set_following_string(format!("{}/following", &base_url)) | |||
.ok(); | |||
person | |||
.ap_actor_props | |||
.set_liked_string(format!("{}/liked", &base_url)) | |||
.ok(); | |||
if let Some(i) = &self.preferred_username { | |||
person | |||
.ap_actor_props | |||
.set_preferred_username_string(i.to_string()) | |||
.ok(); | |||
} | |||
person | |||
} | |||
} | |||
#[derive(Deserialize)] | |||
pub struct UserQuery { | |||
user_name: String, | |||
} | |||
pub fn get_apub_user(info: Path<UserQuery>) -> HttpResponse<Body> { | |||
let connection = establish_connection(); | |||
if let Ok(user) = User_::find_by_email_or_username(&connection, &info.user_name) { | |||
HttpResponse::Ok() | |||
.content_type("application/activity+json") | |||
.body(serde_json::to_string(&user.as_person()).unwrap()) | |||
} else { | |||
HttpResponse::NotFound().finish() | |||
} | |||
} |