+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 {
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
}
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
--- /dev/null
+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()
+}
pub mod community;
+pub mod group_wrapper;
pub mod post;
pub mod puller;
pub mod user;
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
// 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(),
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()],
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)?
}