forked from nutomic/lemmy
improved community federation (wip)
This commit is contained in:
parent
b7ed716659
commit
da21e4e1c3
5 changed files with 111 additions and 61 deletions
|
@ -1,14 +1,14 @@
|
|||
use crate::apub::group_wrapper::GroupHelper;
|
||||
use crate::apub::make_apub_endpoint;
|
||||
use crate::db::community::Community;
|
||||
use crate::db::community_view::CommunityFollowerView;
|
||||
use crate::db::establish_unpooled_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;
|
||||
use serde_json::json;
|
||||
use serde_json::{Value};
|
||||
|
||||
impl Community {
|
||||
pub fn as_group(&self) -> Group {
|
||||
|
@ -16,42 +16,18 @@ impl Community {
|
|||
|
||||
let mut group = Group::default();
|
||||
|
||||
// TODO: why the hell is this code so awkward?
|
||||
group.object_props.set_context_object(context()).ok();
|
||||
// TODO: id really needs to be a url
|
||||
group.object_props.set_id_string(self.id.to_string()).ok();
|
||||
group
|
||||
.object_props
|
||||
.set_name_string(self.title.to_owned())
|
||||
.ok();
|
||||
group
|
||||
.object_props
|
||||
.set_published_utctime(to_datetime_utc(self.published))
|
||||
.ok();
|
||||
group.object_props.attributed_to = Some(json!(self.creator_id.to_string()));
|
||||
if let Some(updated) = self.updated {
|
||||
group
|
||||
.object_props
|
||||
.set_updated_utctime(to_datetime_utc(updated))
|
||||
.ok();
|
||||
}
|
||||
Group::set_id(&mut group, self.id);
|
||||
Group::set_title(&mut group, &self.title);
|
||||
Group::set_published(&mut group, self.published);
|
||||
Group::set_updated(&mut group, self.updated);
|
||||
Group::set_creator_id(&mut group, self.creator_id);
|
||||
|
||||
if let Some(description) = &self.description {
|
||||
group.object_props.summary = Some(json!(description.to_string()));
|
||||
}
|
||||
Group::set_description(&mut group, &self.description);
|
||||
|
||||
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.ap_actor_props.inbox = Value::String(format!("{}/inbox", &base_url));
|
||||
group.ap_actor_props.outbox = Value::String(format!("{}/outbox", &base_url));
|
||||
group.ap_actor_props.followers = Some(Value::String(format!("{}/followers", &base_url)));
|
||||
|
||||
group
|
||||
}
|
||||
|
@ -65,7 +41,6 @@ impl Community {
|
|||
|
||||
let connection = establish_unpooled_connection();
|
||||
//As we are an object, we validated that the community id was valid
|
||||
// TODO: add a method that only returns count for better performance
|
||||
let community_followers = CommunityFollowerView::for_community(&connection, self.id).unwrap();
|
||||
|
||||
collection
|
||||
|
|
91
server/src/apub/group_wrapper.rs
Normal file
91
server/src/apub/group_wrapper.rs
Normal file
|
@ -0,0 +1,91 @@
|
|||
use crate::to_datetime_utc;
|
||||
use activitypub::actor::Group;
|
||||
use chrono::{DateTime, NaiveDateTime};
|
||||
use failure::Error;
|
||||
use serde_json::Value;
|
||||
|
||||
pub trait GroupHelper {
|
||||
// TODO: id really needs to be a url
|
||||
fn set_id(group: &mut Group, id: i32);
|
||||
fn get_id(group: &Group) -> Result<i32, Error>;
|
||||
|
||||
fn set_title(group: &mut Group, title: &str);
|
||||
fn get_title(group: &Group) -> Result<String, Error>;
|
||||
|
||||
fn set_description(group: &mut Group, description: &Option<String>);
|
||||
fn get_description(group: &Group) -> Result<Option<String>, Error>;
|
||||
|
||||
// TODO: also needs to be changed to url
|
||||
fn set_creator_id(group: &mut Group, creator_id: i32);
|
||||
fn get_creator_id(group: &Group) -> Result<i32, Error>;
|
||||
|
||||
fn set_published(group: &mut Group, published: NaiveDateTime);
|
||||
fn get_published(group: &Group) -> Result<NaiveDateTime, Error>;
|
||||
|
||||
fn set_updated(group: &mut Group, updated: Option<NaiveDateTime>);
|
||||
fn get_updated(group: &Group) -> Result<Option<NaiveDateTime>, Error>;
|
||||
}
|
||||
|
||||
// TODO: something is crashing and not reporting the error
|
||||
impl GroupHelper for Group {
|
||||
fn set_id(group: &mut Group, id: i32) {
|
||||
group.object_props.id = Some(Value::String(id.to_string()));
|
||||
}
|
||||
fn get_id(group: &Group) -> Result<i32, Error> {
|
||||
Ok(get_string_value(group.clone().object_props.id).parse::<i32>()?)
|
||||
}
|
||||
|
||||
fn set_title(group: &mut Group, title: &str) {
|
||||
group.object_props.name = Some(Value::String(title.to_string()));
|
||||
}
|
||||
fn get_title(group: &Group) -> Result<String, Error> {
|
||||
Ok(get_string_value(group.to_owned().object_props.name))
|
||||
}
|
||||
|
||||
fn set_description(group: &mut Group, description: &Option<String>) {
|
||||
group.object_props.summary = description.as_ref().map(|d| Value::String(d.to_string()));
|
||||
}
|
||||
fn get_description(group: &Group) -> Result<Option<String>, Error> {
|
||||
Ok(get_string_value_opt(group.to_owned().object_props.summary))
|
||||
}
|
||||
|
||||
fn set_creator_id(group: &mut Group, creator_id: i32) {
|
||||
group.object_props.attributed_to = Some(Value::String(creator_id.to_string()));
|
||||
}
|
||||
fn get_creator_id(group: &Group) -> Result<i32, Error> {
|
||||
Ok(get_string_value(group.clone().object_props.attributed_to).parse::<i32>()?)
|
||||
}
|
||||
|
||||
fn set_published(group: &mut Group, published: NaiveDateTime) {
|
||||
group.object_props.published = Some(Value::String(to_datetime_utc(published).to_string()))
|
||||
}
|
||||
fn get_published(group: &Group) -> Result<NaiveDateTime, Error> {
|
||||
let str = get_string_value(group.to_owned().object_props.published);
|
||||
// TODO: no idea which date format
|
||||
let date = DateTime::parse_from_rfc2822(&str)?;
|
||||
Ok(date.naive_local())
|
||||
}
|
||||
|
||||
fn set_updated(group: &mut Group, updated: Option<NaiveDateTime>) {
|
||||
group.object_props.updated = updated.map(|u| Value::String(u.to_string()));
|
||||
}
|
||||
fn get_updated(group: &Group) -> Result<Option<NaiveDateTime>, Error> {
|
||||
let str = get_string_value_opt(group.to_owned().object_props.updated);
|
||||
match str {
|
||||
Some(s) => Ok(Some(DateTime::parse_from_rfc2822(&s)?.naive_local())),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_string_value_opt(value: Option<Value>) -> Option<String> {
|
||||
value
|
||||
.as_ref()
|
||||
.map(Value::as_str)
|
||||
.flatten()
|
||||
.map(str::to_string)
|
||||
}
|
||||
|
||||
fn get_string_value(value: Option<Value>) -> String {
|
||||
get_string_value_opt(value).unwrap()
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
pub mod community;
|
||||
pub mod group_wrapper;
|
||||
pub mod post;
|
||||
pub mod puller;
|
||||
pub mod user;
|
||||
|
|
|
@ -3,11 +3,10 @@ extern crate reqwest;
|
|||
use self::reqwest::Error;
|
||||
use crate::api::community::{GetCommunityResponse, ListCommunitiesResponse};
|
||||
use crate::api::post::GetPosts;
|
||||
use crate::apub::group_wrapper::GroupHelper;
|
||||
use crate::db::community_view::CommunityView;
|
||||
use crate::naive_now;
|
||||
use crate::settings::Settings;
|
||||
use activitypub::actor::Group;
|
||||
use serde_json::Value;
|
||||
|
||||
// TODO: right now all of the data is requested on demand, for production we will need to store
|
||||
// things in the local database to not ruin the performance
|
||||
|
@ -43,22 +42,20 @@ pub fn get_remote_community(identifier: String) -> Result<GetCommunityResponse,
|
|||
|
||||
// TODO: looks like a bunch of data is missing from the activitypub response
|
||||
// TODO: i dont think simple numeric ids are going to work, we probably need something like uuids
|
||||
// TODO: why are the Group properties not typed?
|
||||
Ok(GetCommunityResponse {
|
||||
moderators: vec![],
|
||||
admins: vec![],
|
||||
community: CommunityView {
|
||||
// TODO: why does the stupid library have everything stored as value without working autocomplete for methods???
|
||||
// TODO: we need to merge id and name into a single thing (stuff like @user@instance.com)
|
||||
id: get_string_value(community.object_props.id).parse::<i32>()?,
|
||||
id: Group::get_id(&community)?,
|
||||
name,
|
||||
title: get_string_value(community.object_props.name),
|
||||
description: get_string_value_opt(community.object_props.summary),
|
||||
title: Group::get_title(&community)?,
|
||||
description: Group::get_description(&community)?,
|
||||
category_id: -1,
|
||||
creator_id: get_string_value(community.object_props.attributed_to).parse::<i32>()?,
|
||||
creator_id: Group::get_creator_id(&community)?,
|
||||
removed: false,
|
||||
published: naive_now(), // TODO: need to handle time conversion (or handle it in apub lib)
|
||||
updated: Some(naive_now()), // TODO: community.object_props.updated
|
||||
published: Group::get_published(&community)?,
|
||||
updated: Group::get_updated(&community)?,
|
||||
deleted: false,
|
||||
nsfw: false,
|
||||
creator_name: "".to_string(),
|
||||
|
@ -69,24 +66,12 @@ pub fn get_remote_community(identifier: String) -> Result<GetCommunityResponse,
|
|||
number_of_comments: -1,
|
||||
hot_rank: -1,
|
||||
user_id: None,
|
||||
subscribed: None, // TODO: looks like lemmy uses None/true for this value
|
||||
subscribed: None,
|
||||
},
|
||||
online: 0,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_string_value_opt(value: Option<Value>) -> Option<String> {
|
||||
value
|
||||
.as_ref()
|
||||
.map(Value::as_str)
|
||||
.flatten()
|
||||
.map(str::to_string)
|
||||
}
|
||||
|
||||
fn get_string_value(value: Option<Value>) -> String {
|
||||
get_string_value_opt(value).unwrap()
|
||||
}
|
||||
|
||||
pub fn get_following_instances() -> Result<Vec<String>, Error> {
|
||||
let instance_list = match Settings::get().federated_instance.clone() {
|
||||
Some(f) => vec![f, Settings::get().hostname.clone()],
|
||||
|
|
|
@ -557,8 +557,6 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
|
|||
if community_name.contains('@') {
|
||||
// TODO: need to support sort, filter etc for remote communities
|
||||
get_remote_community(community_name)?
|
||||
// TODO what is this about
|
||||
// get_community.name = Some(name.replace("!", ""));
|
||||
} else {
|
||||
Oper::new(get_community).perform(&conn)?
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue