-use crate::apub::puller::fetch_remote_object;
+use crate::apub::puller::{fetch_remote_object, fetch_remote_user};
use crate::apub::*;
-use crate::convert_datetime;
use crate::db::community::{Community, CommunityForm};
use crate::db::community_view::CommunityFollowerView;
use crate::db::establish_unpooled_connection;
use crate::db::post::Post;
+use crate::db::user::User_;
+use crate::db::Crud;
use crate::settings::Settings;
+use crate::{convert_datetime, naive_now};
use activitystreams::actor::properties::ApActorProperties;
use activitystreams::collection::OrderedCollection;
use activitystreams::{
db: web::Data<Pool<ConnectionManager<PgConnection>>>,
) -> Result<HttpResponse<Body>, Error> {
// TODO: implement pagination
- let communities = Community::list(&db.get().unwrap())?
+ let communities = Community::list_local(&db.get().unwrap())?
.iter()
- .map(|c| c.as_group())
+ .map(|c| c.as_group(&db.get().unwrap()))
.collect::<Result<Vec<GroupExt>, Error>>()?;
let mut collection = UnorderedCollection::default();
let oprops: &mut ObjectProperties = collection.as_mut();
}
impl Community {
- fn as_group(&self) -> Result<GroupExt, Error> {
+ fn as_group(&self, conn: &PgConnection) -> Result<GroupExt, Error> {
let base_url = make_apub_endpoint(EndpointType::Community, &self.name);
let mut group = Group::default();
let oprops: &mut ObjectProperties = group.as_mut();
+ let creator = User_::read(conn, self.creator_id)?;
oprops
.set_context_xsd_any_uri(context())?
.set_id(base_url.to_owned())?
.set_name_xsd_string(self.name.to_owned())?
.set_published(convert_datetime(self.published))?
- .set_attributed_to_xsd_any_uri(make_apub_endpoint(
- EndpointType::User,
- &self.creator_id.to_string(),
- ))?;
+ .set_attributed_to_xsd_any_uri(make_apub_endpoint(EndpointType::User, &creator.name))?;
if let Some(u) = self.updated.to_owned() {
oprops.set_updated(convert_datetime(u))?;
}
impl CommunityForm {
- pub fn from_group(group: &GroupExt) -> Result<Self, Error> {
+ pub fn from_group(group: &GroupExt, conn: &PgConnection) -> Result<Self, Error> {
let followers_uri = &group.extension.get_followers().unwrap().to_string();
let outbox_uri = &group.extension.get_outbox().to_string();
let _outbox = fetch_remote_object::<OrderedCollection>(outbox_uri)?;
let _followers = fetch_remote_object::<UnorderedCollection>(followers_uri)?;
let oprops = &group.base.object_props;
let aprops = &group.extension;
+ let creator = fetch_remote_user(
+ &oprops.get_attributed_to_xsd_any_uri().unwrap().to_string(),
+ conn,
+ )?;
Ok(CommunityForm {
name: oprops.get_name_xsd_string().unwrap().to_string(),
title: aprops.get_preferred_username().unwrap().to_string(),
description: oprops.get_summary_xsd_string().map(|s| s.to_string()),
category_id: 1,
- creator_id: 2, //community.object_props.get_attributed_to_xsd_any_uri()
+ creator_id: creator.id,
removed: None,
published: oprops
.get_published()
local: false,
private_key: None,
public_key: None,
- last_refreshed_at: None,
+ last_refreshed_at: Some(naive_now()),
})
}
}
db: web::Data<Pool<ConnectionManager<PgConnection>>>,
) -> Result<HttpResponse<Body>, Error> {
let community = Community::read_from_name(&&db.get()?, info.community_name.to_owned())?;
- let c = community.as_group()?;
+ let c = community.as_group(&db.get().unwrap())?;
Ok(create_apub_response(&c))
}
let community = Community::read_from_name(&&db.get()?, info.community_name.to_owned())?;
let base_url = make_apub_endpoint(EndpointType::Community, &community.name);
- let connection = establish_unpooled_connection();
+ let conn = establish_unpooled_connection();
//As we are an object, we validated that the community id was valid
- let community_posts: Vec<Post> = Post::list_for_community(&connection, community.id)?;
+ let community_posts: Vec<Post> = Post::list_for_community(&conn, community.id)?;
let mut collection = OrderedCollection::default();
let oprops: &mut ObjectProperties = collection.as_mut();
.set_many_items_base_boxes(
community_posts
.iter()
- .map(|c| c.as_page().unwrap())
+ .map(|c| c.as_page(&conn).unwrap())
.collect(),
)?
.set_total_items(community_posts.len() as u64)?;
use crate::Settings;
use openssl::{pkey::PKey, rsa::Rsa};
-use activitystreams::actor::{properties::ApActorProperties, Group};
+use activitystreams::actor::{properties::ApActorProperties, Group, Person};
use activitystreams::ext::Ext;
use actix_web::body::Body;
use actix_web::HttpResponse;
use url::Url;
type GroupExt = Ext<Group, ApActorProperties>;
+type PersonExt = Ext<Person, ApActorProperties>;
static APUB_JSON_CONTENT_TYPE: &str = "application/activity+json";
+use crate::apub::puller::fetch_remote_user;
use crate::apub::{create_apub_response, make_apub_endpoint, EndpointType};
use crate::convert_datetime;
use crate::db::post::{Post, PostForm};
-use activitystreams::{object::properties::ObjectProperties, object::Page};
+use crate::db::user::User_;
+use crate::db::Crud;
+use activitystreams::{context, object::properties::ObjectProperties, object::Page};
use actix_web::body::Body;
use actix_web::web::Path;
use actix_web::{web, HttpResponse};
) -> Result<HttpResponse<Body>, Error> {
let id = info.post_id.parse::<i32>()?;
let post = Post::read(&&db.get()?, id)?;
- Ok(create_apub_response(&post.as_page()?))
+ Ok(create_apub_response(&post.as_page(&db.get().unwrap())?))
}
impl Post {
- pub fn as_page(&self) -> Result<Page, Error> {
+ pub fn as_page(&self, conn: &PgConnection) -> Result<Page, Error> {
let base_url = make_apub_endpoint(EndpointType::Post, &self.id.to_string());
let mut page = Page::default();
let oprops: &mut ObjectProperties = page.as_mut();
+ let creator = User_::read(conn, self.creator_id)?;
oprops
// Not needed when the Post is embedded in a collection (like for community outbox)
- //.set_context_xsd_any_uri(context())?
+ .set_context_xsd_any_uri(context())?
.set_id(base_url)?
.set_name_xsd_string(self.name.to_owned())?
.set_published(convert_datetime(self.published))?
- .set_attributed_to_xsd_any_uri(make_apub_endpoint(
- EndpointType::User,
- &self.creator_id.to_string(),
- ))?;
+ .set_attributed_to_xsd_any_uri(make_apub_endpoint(EndpointType::User, &creator.name))?;
if let Some(body) = &self.body {
oprops.set_content_xsd_string(body.to_owned())?;
}
impl PostForm {
- pub fn from_page(page: &Page) -> Result<PostForm, Error> {
+ pub fn from_page(page: &Page, conn: &PgConnection) -> Result<PostForm, Error> {
let oprops = &page.object_props;
+ let creator = fetch_remote_user(
+ &oprops.get_attributed_to_xsd_any_uri().unwrap().to_string(),
+ conn,
+ )?;
Ok(PostForm {
name: oprops.get_name_xsd_string().unwrap().to_string(),
url: oprops.get_url_xsd_any_uri().map(|u| u.to_string()),
body: oprops.get_content_xsd_string().map(|c| c.to_string()),
- creator_id: 2,
+ creator_id: creator.id,
community_id: -1,
removed: None,
locked: None,
use crate::apub::*;
use crate::db::community::{Community, CommunityForm};
use crate::db::post::{Post, PostForm};
+use crate::db::user::{UserForm, User_};
use crate::db::Crud;
use crate::routes::nodeinfo::{NodeInfo, NodeInfoWellKnown};
use crate::settings::Settings;
Ok(fetch_remote_object::<NodeInfo>(&well_known.links.href)?)
}
-fn fetch_communities_from_instance(domain: &str) -> Result<Vec<CommunityForm>, Error> {
+fn fetch_communities_from_instance(
+ domain: &str,
+ conn: &PgConnection,
+) -> Result<Vec<CommunityForm>, Error> {
let node_info = fetch_node_info(domain)?;
if let Some(community_list_url) = node_info.metadata.community_list_url {
let communities: Result<Vec<CommunityForm>, Error> = object_boxes
.map(|c| {
let group = c.to_owned().to_concrete::<GroupExt>()?;
- CommunityForm::from_group(&group)
+ CommunityForm::from_group(&group, conn)
})
.collect();
Ok(communities?)
}
}
+// TODO: add an optional param last_updated and only fetch if its too old
pub fn fetch_remote_object<Response>(uri: &str) -> Result<Response, Error>
where
Response: for<'de> Deserialize<'de>,
Ok(res)
}
-fn fetch_remote_community_posts(instance: &str, community: &str) -> Result<Vec<PostForm>, Error> {
+fn fetch_remote_community_posts(
+ instance: &str,
+ community: &str,
+ conn: &PgConnection,
+) -> Result<Vec<PostForm>, Error> {
let endpoint = format!("http://{}/federation/c/{}", instance, community);
let community = fetch_remote_object::<GroupExt>(&endpoint)?;
let outbox_uri = &community.extension.get_outbox().to_string();
.unwrap()
.map(|obox: &BaseBox| {
let page = obox.clone().to_concrete::<Page>().unwrap();
- PostForm::from_page(&page)
+ PostForm::from_page(&page, conn)
})
.collect::<Result<Vec<PostForm>, Error>>()?;
Ok(posts)
}
+pub fn fetch_remote_user(apub_id: &str, conn: &PgConnection) -> Result<User_, Error> {
+ let person = fetch_remote_object::<PersonExt>(apub_id)?;
+ let uf = UserForm::from_person(&person)?;
+ let existing = User_::read_from_apub_id(conn, &uf.actor_id);
+ Ok(match existing {
+ // TODO: should make sure that this is actually a `NotFound` error
+ Err(_) => User_::create(conn, &uf)?,
+ Ok(u) => User_::update(conn, u.id, &uf)?,
+ })
+}
+
// TODO: in the future, this should only be done when an instance is followed for the first time
// after that, we should rely in the inbox, and fetch on demand when needed
pub fn fetch_all(conn: &PgConnection) -> Result<(), Error> {
for instance in &get_following_instances() {
- let communities = fetch_communities_from_instance(instance)?;
+ let communities = fetch_communities_from_instance(instance, conn)?;
for community in &communities {
let existing = Community::read_from_actor_id(conn, &community.actor_id);
Err(_) => Community::create(conn, community)?.id,
Ok(c) => Community::update(conn, c.id, community)?.id,
};
- let mut posts = fetch_remote_community_posts(instance, &community.name)?;
+ let mut posts = fetch_remote_community_posts(instance, &community.name, conn)?;
for post_ in &mut posts {
post_.community_id = community_id;
let existing = Post::read_from_apub_id(conn, &post_.ap_id);
match existing {
// TODO: should make sure that this is actually a `NotFound` error
- Err(_) => {
- Post::create(conn, post_)?;
- }
- Ok(p) => {
- Post::update(conn, p.id, post_)?;
- }
- }
+ Err(_) => Post::create(conn, post_)?,
+ Ok(p) => Post::update(conn, p.id, post_)?,
+ };
}
}
}
-use crate::apub::{create_apub_response, make_apub_endpoint, EndpointType};
-use crate::convert_datetime;
-use crate::db::user::User_;
+use crate::apub::{create_apub_response, make_apub_endpoint, EndpointType, PersonExt};
+use crate::db::user::{UserForm, User_};
+use crate::{convert_datetime, naive_now};
use activitystreams::{
actor::{properties::ApActorProperties, Person},
context,
info: Path<UserQuery>,
db: web::Data<Pool<ConnectionManager<PgConnection>>>,
) -> Result<HttpResponse<Body>, Error> {
+ dbg!(&info.user_name);
let user = User_::find_by_email_or_username(&&db.get()?, &info.user_name)?;
let base_url = make_apub_endpoint(EndpointType::User, &user.name);
oprops
.set_context_xsd_any_uri(context())?
.set_id(base_url.to_string())?
+ .set_name_xsd_string(user.name.to_owned())?
.set_published(convert_datetime(user.published))?;
if let Some(u) = user.updated {
Ok(create_apub_response(&person.extend(actor_props)))
}
+
+impl UserForm {
+ pub fn from_person(person: &PersonExt) -> Result<Self, Error> {
+ let oprops = &person.base.object_props;
+ let aprops = &person.extension;
+ Ok(UserForm {
+ name: oprops.get_name_xsd_string().unwrap().to_string(),
+ preferred_username: aprops.get_preferred_username().map(|u| u.to_string()),
+ password_encrypted: "".to_string(),
+ admin: false,
+ banned: false,
+ email: None,
+ avatar: None,
+ updated: oprops
+ .get_updated()
+ .map(|u| u.as_ref().to_owned().naive_local()),
+ show_nsfw: false,
+ theme: "".to_string(),
+ default_sort_type: 0,
+ default_listing_type: 0,
+ lang: "".to_string(),
+ show_avatars: false,
+ send_notifications_to_email: false,
+ matrix_user_id: None,
+ actor_id: oprops.get_id().unwrap().to_string(),
+ bio: oprops.get_summary_xsd_string().map(|s| s.to_string()),
+ local: false,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: Some(naive_now()),
+ })
+ }
+}
.first::<Self>(conn)
}
- pub fn list(conn: &PgConnection) -> Result<Vec<Self>, Error> {
+ pub fn list_local(conn: &PgConnection) -> Result<Vec<Self>, Error> {
use crate::schema::community::dsl::*;
- community.load::<Community>(conn)
+ community.filter(local.eq(true)).load::<Community>(conn)
}
pub fn get_url(&self) -> String {
pub last_refreshed_at: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset, Clone)]
+#[derive(Insertable, AsChangeset, Clone, Debug)]
#[table_name = "user_"]
pub struct UserForm {
pub name: String,
.set(banned.eq(ban))
.get_result::<Self>(conn)
}
+
+ pub fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error> {
+ use crate::schema::user_::dsl::*;
+ user_.filter(actor_id.eq(object_id)).first::<Self>(conn)
+ }
}
#[derive(Debug, Serialize, Deserialize)]