Some more cleanup.
This commit is contained in:
parent
66a2c4a2c3
commit
d846740839
9 changed files with 251 additions and 237 deletions
|
@ -61,7 +61,7 @@ fn get_follower_inboxes(conn: &PgConnection, community: &Community) -> Result<Ve
|
||||||
|
|
||||||
/// Send out information about a newly created post, to the followers of the community.
|
/// Send out information about a newly created post, to the followers of the community.
|
||||||
pub fn post_create(post: &Post, creator: &User_, conn: &PgConnection) -> Result<(), Error> {
|
pub fn post_create(post: &Post, creator: &User_, conn: &PgConnection) -> Result<(), Error> {
|
||||||
let page = post.as_page(conn)?;
|
let page = post.to_apub(conn)?;
|
||||||
let community = Community::read(conn, post.community_id)?;
|
let community = Community::read(conn, post.community_id)?;
|
||||||
let mut create = Create::new();
|
let mut create = Create::new();
|
||||||
populate_object_props(
|
populate_object_props(
|
||||||
|
@ -84,7 +84,7 @@ pub fn post_create(post: &Post, creator: &User_, conn: &PgConnection) -> Result<
|
||||||
|
|
||||||
/// Send out information about an edited post, to the followers of the community.
|
/// Send out information about an edited post, to the followers of the community.
|
||||||
pub fn post_update(post: &Post, creator: &User_, conn: &PgConnection) -> Result<(), Error> {
|
pub fn post_update(post: &Post, creator: &User_, conn: &PgConnection) -> Result<(), Error> {
|
||||||
let page = post.as_page(conn)?;
|
let page = post.to_apub(conn)?;
|
||||||
let community = Community::read(conn, post.community_id)?;
|
let community = Community::read(conn, post.community_id)?;
|
||||||
let mut update = Update::new();
|
let mut update = Update::new();
|
||||||
populate_object_props(
|
populate_object_props(
|
||||||
|
@ -139,7 +139,11 @@ pub fn accept_follow(follow: &Follow, conn: &PgConnection) -> Result<(), Error>
|
||||||
.get_object_xsd_any_uri()
|
.get_object_xsd_any_uri()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string();
|
.to_string();
|
||||||
let actor_uri = follow.follow_props.get_actor_xsd_any_uri().unwrap().to_string();
|
let actor_uri = follow
|
||||||
|
.follow_props
|
||||||
|
.get_actor_xsd_any_uri()
|
||||||
|
.unwrap()
|
||||||
|
.to_string();
|
||||||
let community = Community::read_from_actor_id(conn, &community_uri)?;
|
let community = Community::read_from_actor_id(conn, &community_uri)?;
|
||||||
let mut accept = Accept::new();
|
let mut accept = Accept::new();
|
||||||
accept
|
accept
|
||||||
|
@ -151,7 +155,7 @@ pub fn accept_follow(follow: &Follow, conn: &PgConnection) -> Result<(), Error>
|
||||||
.follow_props
|
.follow_props
|
||||||
.get_actor_xsd_any_uri()
|
.get_actor_xsd_any_uri()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string()
|
.to_string(),
|
||||||
)?;
|
)?;
|
||||||
accept
|
accept
|
||||||
.accept_props
|
.accept_props
|
||||||
|
|
|
@ -5,10 +5,9 @@ pub struct CommunityQuery {
|
||||||
community_name: String,
|
community_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO turn these as_group, as_page, into apub trait... something like to_apub
|
impl ToApub<GroupExt> for Community {
|
||||||
impl Community {
|
|
||||||
// Turn a Lemmy Community into an ActivityPub group that can be sent out over the network.
|
// Turn a Lemmy Community into an ActivityPub group that can be sent out over the network.
|
||||||
fn as_group(&self, conn: &PgConnection) -> Result<GroupExt, Error> {
|
fn to_apub(&self, conn: &PgConnection) -> Result<GroupExt, Error> {
|
||||||
let mut group = Group::default();
|
let mut group = Group::default();
|
||||||
let oprops: &mut ObjectProperties = group.as_mut();
|
let oprops: &mut ObjectProperties = group.as_mut();
|
||||||
|
|
||||||
|
@ -45,29 +44,26 @@ impl Community {
|
||||||
|
|
||||||
Ok(group.extend(actor_props).extend(public_key.to_ext()))
|
Ok(group.extend(actor_props).extend(public_key.to_ext()))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_followers_url(&self) -> String {
|
impl ActorType for Community {
|
||||||
format!("{}/followers", &self.actor_id)
|
fn actor_id(&self) -> String {
|
||||||
}
|
self.actor_id.to_owned()
|
||||||
pub fn get_inbox_url(&self) -> String {
|
|
||||||
format!("{}/inbox", &self.actor_id)
|
|
||||||
}
|
|
||||||
pub fn get_outbox_url(&self) -> String {
|
|
||||||
format!("{}/outbox", &self.actor_id)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommunityForm {
|
impl FromApub<GroupExt> for CommunityForm {
|
||||||
/// Parse an ActivityPub group received from another instance into a Lemmy community.
|
/// Parse an ActivityPub group received from another instance into a Lemmy community.
|
||||||
pub fn from_group(group: &GroupExt, conn: &PgConnection) -> Result<Self, Error> {
|
fn from_apub(group: &GroupExt, conn: &PgConnection) -> Result<Self, Error> {
|
||||||
let oprops = &group.base.base.object_props;
|
let oprops = &group.base.base.object_props;
|
||||||
let aprops = &group.base.extension;
|
let aprops = &group.base.extension;
|
||||||
let public_key: &PublicKey = &group.extension.public_key;
|
let public_key: &PublicKey = &group.extension.public_key;
|
||||||
|
|
||||||
let followers_uri = Url::parse(&aprops.get_followers().unwrap().to_string())?;
|
let _followers_uri = Url::parse(&aprops.get_followers().unwrap().to_string())?;
|
||||||
let outbox_uri = Url::parse(&aprops.get_outbox().to_string())?;
|
let _outbox_uri = Url::parse(&aprops.get_outbox().to_string())?;
|
||||||
let _outbox = fetch_remote_object::<OrderedCollection>(&outbox_uri)?;
|
// TODO don't do extra fetching here
|
||||||
let _followers = fetch_remote_object::<UnorderedCollection>(&followers_uri)?;
|
// let _outbox = fetch_remote_object::<OrderedCollection>(&outbox_uri)?;
|
||||||
|
// let _followers = fetch_remote_object::<UnorderedCollection>(&followers_uri)?;
|
||||||
let apub_id = &oprops.get_attributed_to_xsd_any_uri().unwrap().to_string();
|
let apub_id = &oprops.get_attributed_to_xsd_any_uri().unwrap().to_string();
|
||||||
let creator = get_or_fetch_and_upsert_remote_user(&apub_id, conn)?;
|
let creator = get_or_fetch_and_upsert_remote_user(&apub_id, conn)?;
|
||||||
|
|
||||||
|
@ -101,10 +97,9 @@ impl CommunityForm {
|
||||||
pub async fn get_apub_community_http(
|
pub async fn get_apub_community_http(
|
||||||
info: Path<CommunityQuery>,
|
info: Path<CommunityQuery>,
|
||||||
db: DbPoolParam,
|
db: DbPoolParam,
|
||||||
chat_server: ChatServerParam,
|
|
||||||
) -> Result<HttpResponse<Body>, Error> {
|
) -> Result<HttpResponse<Body>, Error> {
|
||||||
let community = Community::read_from_name(&&db.get()?, &info.community_name)?;
|
let community = Community::read_from_name(&&db.get()?, &info.community_name)?;
|
||||||
let c = community.as_group(&db.get().unwrap())?;
|
let c = community.to_apub(&db.get().unwrap())?;
|
||||||
Ok(create_apub_response(&c))
|
Ok(create_apub_response(&c))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,14 +108,13 @@ pub async fn get_apub_community_http(
|
||||||
pub async fn get_apub_community_followers(
|
pub async fn get_apub_community_followers(
|
||||||
info: Path<CommunityQuery>,
|
info: Path<CommunityQuery>,
|
||||||
db: DbPoolParam,
|
db: DbPoolParam,
|
||||||
chat_server: ChatServerParam,
|
|
||||||
) -> Result<HttpResponse<Body>, Error> {
|
) -> Result<HttpResponse<Body>, Error> {
|
||||||
let community = Community::read_from_name(&&db.get()?, &info.community_name)?;
|
let community = Community::read_from_name(&&db.get()?, &info.community_name)?;
|
||||||
|
|
||||||
let connection = establish_unpooled_connection();
|
let conn = db.get()?;
|
||||||
|
|
||||||
//As we are an object, we validated that the community id was valid
|
//As we are an object, we validated that the community id was valid
|
||||||
let community_followers =
|
let community_followers = CommunityFollowerView::for_community(&conn, community.id).unwrap();
|
||||||
CommunityFollowerView::for_community(&connection, community.id).unwrap();
|
|
||||||
|
|
||||||
let mut collection = UnorderedCollection::default();
|
let mut collection = UnorderedCollection::default();
|
||||||
let oprops: &mut ObjectProperties = collection.as_mut();
|
let oprops: &mut ObjectProperties = collection.as_mut();
|
||||||
|
@ -133,32 +127,33 @@ pub async fn get_apub_community_followers(
|
||||||
Ok(create_apub_response(&collection))
|
Ok(create_apub_response(&collection))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an UnorderedCollection with the latest posts from the community.
|
// TODO should not be doing this
|
||||||
pub async fn get_apub_community_outbox(
|
// Returns an UnorderedCollection with the latest posts from the community.
|
||||||
info: Path<CommunityQuery>,
|
//pub async fn get_apub_community_outbox(
|
||||||
db: DbPoolParam,
|
// info: Path<CommunityQuery>,
|
||||||
chat_server: ChatServerParam,
|
// db: DbPoolParam,
|
||||||
) -> Result<HttpResponse<Body>, Error> {
|
// chat_server: ChatServerParam,
|
||||||
let community = Community::read_from_name(&&db.get()?, &info.community_name)?;
|
//) -> Result<HttpResponse<Body>, Error> {
|
||||||
|
// let community = Community::read_from_name(&&db.get()?, &info.community_name)?;
|
||||||
|
|
||||||
let conn = establish_unpooled_connection();
|
// let conn = establish_unpooled_connection();
|
||||||
//As we are an object, we validated that the community id was valid
|
// //As we are an object, we validated that the community id was valid
|
||||||
let community_posts: Vec<Post> = Post::list_for_community(&conn, community.id)?;
|
// let community_posts: Vec<Post> = Post::list_for_community(&conn, community.id)?;
|
||||||
|
|
||||||
let mut collection = OrderedCollection::default();
|
// let mut collection = OrderedCollection::default();
|
||||||
let oprops: &mut ObjectProperties = collection.as_mut();
|
// let oprops: &mut ObjectProperties = collection.as_mut();
|
||||||
oprops
|
// oprops
|
||||||
.set_context_xsd_any_uri(context())?
|
// .set_context_xsd_any_uri(context())?
|
||||||
.set_id(community.actor_id)?;
|
// .set_id(community.actor_id)?;
|
||||||
collection
|
// collection
|
||||||
.collection_props
|
// .collection_props
|
||||||
.set_many_items_base_boxes(
|
// .set_many_items_base_boxes(
|
||||||
community_posts
|
// community_posts
|
||||||
.iter()
|
// .iter()
|
||||||
.map(|c| c.as_page(&conn).unwrap())
|
// .map(|c| c.as_page(&conn).unwrap())
|
||||||
.collect(),
|
// .collect(),
|
||||||
)?
|
// )?
|
||||||
.set_total_items(community_posts.len() as u64)?;
|
// .set_total_items(community_posts.len() as u64)?;
|
||||||
|
|
||||||
Ok(create_apub_response(&collection))
|
// Ok(create_apub_response(&collection))
|
||||||
}
|
//}
|
||||||
|
|
|
@ -6,6 +6,7 @@ pub enum CommunityAcceptedObjects {
|
||||||
Follow(Follow),
|
Follow(Follow),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Consolidate community and user inboxes into a single shared one
|
||||||
/// Handler for all incoming activities to community inboxes.
|
/// Handler for all incoming activities to community inboxes.
|
||||||
pub async fn community_inbox(
|
pub async fn community_inbox(
|
||||||
request: HttpRequest,
|
request: HttpRequest,
|
||||||
|
@ -18,11 +19,12 @@ pub async fn community_inbox(
|
||||||
let community_name = path.into_inner();
|
let community_name = path.into_inner();
|
||||||
debug!(
|
debug!(
|
||||||
"Community {} received activity {:?}",
|
"Community {} received activity {:?}",
|
||||||
&community_name,
|
&community_name, &input
|
||||||
&input
|
|
||||||
);
|
);
|
||||||
match input {
|
match input {
|
||||||
CommunityAcceptedObjects::Follow(f) => handle_follow(&f, &request, &community_name, db, chat_server),
|
CommunityAcceptedObjects::Follow(f) => {
|
||||||
|
handle_follow(&f, &request, &community_name, db, chat_server)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,14 +35,14 @@ fn handle_follow(
|
||||||
request: &HttpRequest,
|
request: &HttpRequest,
|
||||||
community_name: &str,
|
community_name: &str,
|
||||||
db: DbPoolParam,
|
db: DbPoolParam,
|
||||||
chat_server: ChatServerParam,
|
_chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
let user_uri = follow
|
let user_uri = follow
|
||||||
.follow_props
|
.follow_props
|
||||||
.get_actor_xsd_any_uri()
|
.get_actor_xsd_any_uri()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string();
|
.to_string();
|
||||||
let community_uri = follow
|
let _community_uri = follow
|
||||||
.follow_props
|
.follow_props
|
||||||
.get_object_xsd_any_uri()
|
.get_object_xsd_any_uri()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
|
@ -11,40 +11,8 @@ fn _fetch_node_info(domain: &str) -> Result<NodeInfo, Error> {
|
||||||
Ok(fetch_remote_object::<NodeInfo>(&well_known.links.href)?)
|
Ok(fetch_remote_object::<NodeInfo>(&well_known.links.href)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
// // TODO: move these to db
|
|
||||||
// // TODO use the last_refreshed_at
|
|
||||||
// fn upsert_community(
|
|
||||||
// community_form: &CommunityForm,
|
|
||||||
// conn: &PgConnection,
|
|
||||||
// ) -> Result<Community, Error> {
|
|
||||||
// let existing = Community::read_from_actor_id(conn, &community_form.actor_id);
|
|
||||||
// match existing {
|
|
||||||
// Err(NotFound {}) => Ok(Community::create(conn, &community_form)?),
|
|
||||||
// Ok(c) => Ok(Community::update(conn, c.id, &community_form)?),
|
|
||||||
// Err(e) => Err(Error::from(e)),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// fn upsert_user(user_form: &UserForm, conn: &PgConnection) -> Result<User_, Error> {
|
|
||||||
// let existing = User_::read_from_actor_id(conn, &user_form.actor_id);
|
|
||||||
// Ok(match existing {
|
|
||||||
// Err(NotFound {}) => User_::create(conn, &user_form)?,
|
|
||||||
// Ok(u) => User_::update(conn, u.id, &user_form)?,
|
|
||||||
// Err(e) => return Err(Error::from(e)),
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn upsert_post(post_form: &PostForm, conn: &PgConnection) -> Result<Post, Error> {
|
|
||||||
let existing = Post::read_from_apub_id(conn, &post_form.ap_id);
|
|
||||||
match existing {
|
|
||||||
Err(NotFound {}) => Ok(Post::create(conn, &post_form)?),
|
|
||||||
Ok(p) => Ok(Post::update(conn, p.id, &post_form)?),
|
|
||||||
Err(e) => Err(Error::from(e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fetch any type of ActivityPub object, handling things like HTTP headers, deserialisation,
|
/// Fetch any type of ActivityPub object, handling things like HTTP headers, deserialisation,
|
||||||
/// timeouts etc.
|
/// timeouts etc.
|
||||||
/// TODO: add an optional param last_updated and only fetch if its too old
|
|
||||||
pub fn fetch_remote_object<Response>(url: &Url) -> Result<Response, Error>
|
pub fn fetch_remote_object<Response>(url: &Url) -> Result<Response, Error>
|
||||||
where
|
where
|
||||||
Response: for<'de> Deserialize<'de>,
|
Response: for<'de> Deserialize<'de>,
|
||||||
|
@ -71,15 +39,14 @@ where
|
||||||
pub enum SearchAcceptedObjects {
|
pub enum SearchAcceptedObjects {
|
||||||
Person(Box<PersonExt>),
|
Person(Box<PersonExt>),
|
||||||
Group(Box<GroupExt>),
|
Group(Box<GroupExt>),
|
||||||
// Page(Box<Page>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to parse the query as URL, and fetch an ActivityPub object from it.
|
/// Attempt to parse the query as URL, and fetch an ActivityPub object from it.
|
||||||
///
|
///
|
||||||
/// Some working examples for use with the docker/federation/ setup:
|
/// Some working examples for use with the docker/federation/ setup:
|
||||||
/// http://lemmy_alpha:8540/federation/c/main
|
/// http://lemmy_alpha:8540/c/main
|
||||||
/// http://lemmy_alpha:8540/federation/u/lemmy_alpha
|
/// http://lemmy_alpha:8540/u/lemmy_alpha
|
||||||
/// http://lemmy_alpha:8540/federation/p/3
|
/// http://lemmy_alpha:8540/p/3
|
||||||
pub fn search_by_apub_id(query: &str, conn: &PgConnection) -> Result<SearchResponse, Error> {
|
pub fn search_by_apub_id(query: &str, conn: &PgConnection) -> Result<SearchResponse, Error> {
|
||||||
let query_url = Url::parse(&query)?;
|
let query_url = Url::parse(&query)?;
|
||||||
let mut response = SearchResponse {
|
let mut response = SearchResponse {
|
||||||
|
@ -91,65 +58,47 @@ pub fn search_by_apub_id(query: &str, conn: &PgConnection) -> Result<SearchRespo
|
||||||
};
|
};
|
||||||
match fetch_remote_object::<SearchAcceptedObjects>(&query_url)? {
|
match fetch_remote_object::<SearchAcceptedObjects>(&query_url)? {
|
||||||
SearchAcceptedObjects::Person(p) => {
|
SearchAcceptedObjects::Person(p) => {
|
||||||
let user = get_or_fetch_and_upsert_remote_user(query, &conn)?;
|
let user_uri = p.base.base.object_props.get_id().unwrap().to_string();
|
||||||
|
let user = get_or_fetch_and_upsert_remote_user(&user_uri, &conn)?;
|
||||||
response.users = vec![UserView::read(conn, user.id)?];
|
response.users = vec![UserView::read(conn, user.id)?];
|
||||||
}
|
}
|
||||||
SearchAcceptedObjects::Group(g) => {
|
SearchAcceptedObjects::Group(g) => {
|
||||||
let community = get_or_fetch_and_upsert_remote_community(query, &conn)?;
|
let community_uri = g.base.base.object_props.get_id().unwrap().to_string();
|
||||||
|
let community = get_or_fetch_and_upsert_remote_community(&community_uri, &conn)?;
|
||||||
|
// TODO Maybe at some point in the future, fetch all the history of a community
|
||||||
// fetch_community_outbox(&c, conn)?;
|
// fetch_community_outbox(&c, conn)?;
|
||||||
response.communities = vec![CommunityView::read(conn, community.id, None)?];
|
response.communities = vec![CommunityView::read(conn, community.id, None)?];
|
||||||
}
|
}
|
||||||
// SearchAcceptedObjects::Page(p) => {
|
|
||||||
// let p = upsert_post(&PostForm::from_page(&p, conn)?, conn)?;
|
|
||||||
// response.posts = vec![PostView::read(conn, p.id, None)?];
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO It should not be fetching data from a community outbox.
|
|
||||||
// All posts, comments, comment likes, etc should be posts to our community_inbox
|
|
||||||
// The only data we should be periodically fetching (if it hasn't been fetched in the last day
|
|
||||||
// maybe), is community and user actors
|
|
||||||
// and user actors
|
|
||||||
/// Fetch all posts in the outbox of the given user, and insert them into the database.
|
|
||||||
fn fetch_community_outbox(community: &Community, conn: &PgConnection) -> Result<Vec<Post>, Error> {
|
|
||||||
let outbox_url = Url::parse(&community.get_outbox_url())?;
|
|
||||||
let outbox = fetch_remote_object::<OrderedCollection>(&outbox_url)?;
|
|
||||||
let items = outbox.collection_props.get_many_items_base_boxes();
|
|
||||||
|
|
||||||
Ok(
|
|
||||||
items
|
|
||||||
.unwrap()
|
|
||||||
.map(|obox: &BaseBox| -> Result<PostForm, Error> {
|
|
||||||
let page = obox.clone().to_concrete::<Page>()?;
|
|
||||||
PostForm::from_page(&page, conn)
|
|
||||||
})
|
|
||||||
.map(|pf| upsert_post(&pf?, conn))
|
|
||||||
.collect::<Result<Vec<Post>, Error>>()?,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if a remote user exists, create if not found, if its too old update it.Fetch a user, insert/update it in the database and return the user.
|
/// Check if a remote user exists, create if not found, if its too old update it.Fetch a user, insert/update it in the database and return the user.
|
||||||
pub fn get_or_fetch_and_upsert_remote_user(apub_id: &str, conn: &PgConnection) -> Result<User_, Error> {
|
pub fn get_or_fetch_and_upsert_remote_user(
|
||||||
|
apub_id: &str,
|
||||||
|
conn: &PgConnection,
|
||||||
|
) -> Result<User_, Error> {
|
||||||
match User_::read_from_actor_id(&conn, &apub_id) {
|
match User_::read_from_actor_id(&conn, &apub_id) {
|
||||||
Ok(u) => {
|
Ok(u) => {
|
||||||
// If its older than a day, re-fetch it
|
// If its older than a day, re-fetch it
|
||||||
// TODO the less than needs to be tested
|
// TODO the less than needs to be tested
|
||||||
if u.last_refreshed_at.lt(&(naive_now() - chrono::Duration::days(1))) {
|
if u
|
||||||
|
.last_refreshed_at
|
||||||
|
.lt(&(naive_now() - chrono::Duration::days(1)))
|
||||||
|
{
|
||||||
debug!("Fetching and updating from remote user: {}", apub_id);
|
debug!("Fetching and updating from remote user: {}", apub_id);
|
||||||
let person = fetch_remote_object::<PersonExt>(&Url::parse(apub_id)?)?;
|
let person = fetch_remote_object::<PersonExt>(&Url::parse(apub_id)?)?;
|
||||||
let uf = UserForm::from_person(&person)?;
|
let mut uf = UserForm::from_apub(&person, &conn)?;
|
||||||
uf.last_refreshed_at = Some(naive_now());
|
uf.last_refreshed_at = Some(naive_now());
|
||||||
Ok(User_::update(&conn, u.id, &uf)?)
|
Ok(User_::update(&conn, u.id, &uf)?)
|
||||||
} else {
|
} else {
|
||||||
Ok(u)
|
Ok(u)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(NotFound {}) => {
|
Err(NotFound {}) => {
|
||||||
debug!("Fetching and creating remote user: {}", apub_id);
|
debug!("Fetching and creating remote user: {}", apub_id);
|
||||||
let person = fetch_remote_object::<PersonExt>(&Url::parse(apub_id)?)?;
|
let person = fetch_remote_object::<PersonExt>(&Url::parse(apub_id)?)?;
|
||||||
let uf = UserForm::from_person(&person)?;
|
let uf = UserForm::from_apub(&person, &conn)?;
|
||||||
Ok(User_::create(conn, &uf)?)
|
Ok(User_::create(conn, &uf)?)
|
||||||
}
|
}
|
||||||
Err(e) => Err(Error::from(e)),
|
Err(e) => Err(Error::from(e)),
|
||||||
|
@ -157,27 +106,66 @@ pub fn get_or_fetch_and_upsert_remote_user(apub_id: &str, conn: &PgConnection) -
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a remote community exists, create if not found, if its too old update it.Fetch a community, insert/update it in the database and return the community.
|
/// Check if a remote community exists, create if not found, if its too old update it.Fetch a community, insert/update it in the database and return the community.
|
||||||
pub fn get_or_fetch_and_upsert_remote_community(apub_id: &str, conn: &PgConnection) -> Result<Community, Error> {
|
pub fn get_or_fetch_and_upsert_remote_community(
|
||||||
|
apub_id: &str,
|
||||||
|
conn: &PgConnection,
|
||||||
|
) -> Result<Community, Error> {
|
||||||
match Community::read_from_actor_id(&conn, &apub_id) {
|
match Community::read_from_actor_id(&conn, &apub_id) {
|
||||||
Ok(c) => {
|
Ok(c) => {
|
||||||
// If its older than a day, re-fetch it
|
// If its older than a day, re-fetch it
|
||||||
// TODO the less than needs to be tested
|
// TODO the less than needs to be tested
|
||||||
if c.last_refreshed_at.lt(&(naive_now() - chrono::Duration::days(1))) {
|
if c
|
||||||
|
.last_refreshed_at
|
||||||
|
.lt(&(naive_now() - chrono::Duration::days(1)))
|
||||||
|
{
|
||||||
debug!("Fetching and updating from remote community: {}", apub_id);
|
debug!("Fetching and updating from remote community: {}", apub_id);
|
||||||
let group = fetch_remote_object::<GroupExt>(&Url::parse(apub_id)?)?;
|
let group = fetch_remote_object::<GroupExt>(&Url::parse(apub_id)?)?;
|
||||||
let cf = CommunityForm::from_group(&group, conn)?;
|
let mut cf = CommunityForm::from_apub(&group, conn)?;
|
||||||
cf.last_refreshed_at = Some(naive_now());
|
cf.last_refreshed_at = Some(naive_now());
|
||||||
Ok(Community::update(&conn, c.id, &cf)?)
|
Ok(Community::update(&conn, c.id, &cf)?)
|
||||||
} else {
|
} else {
|
||||||
Ok(c)
|
Ok(c)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(NotFound {}) => {
|
Err(NotFound {}) => {
|
||||||
debug!("Fetching and creating remote community: {}", apub_id);
|
debug!("Fetching and creating remote community: {}", apub_id);
|
||||||
let group = fetch_remote_object::<GroupExt>(&Url::parse(apub_id)?)?;
|
let group = fetch_remote_object::<GroupExt>(&Url::parse(apub_id)?)?;
|
||||||
let cf = CommunityForm::from_group(&group, conn)?;
|
let cf = CommunityForm::from_apub(&group, conn)?;
|
||||||
Ok(Community::create(conn, &cf)?)
|
Ok(Community::create(conn, &cf)?)
|
||||||
}
|
}
|
||||||
Err(e) => Err(Error::from(e)),
|
Err(e) => Err(Error::from(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Maybe add post, comment searching / caching at a later time
|
||||||
|
// fn upsert_post(post_form: &PostForm, conn: &PgConnection) -> Result<Post, Error> {
|
||||||
|
// let existing = Post::read_from_apub_id(conn, &post_form.ap_id);
|
||||||
|
// match existing {
|
||||||
|
// Err(NotFound {}) => Ok(Post::create(conn, &post_form)?),
|
||||||
|
// Ok(p) => Ok(Post::update(conn, p.id, &post_form)?),
|
||||||
|
// Err(e) => Err(Error::from(e)),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// TODO It should not be fetching data from a community outbox.
|
||||||
|
// All posts, comments, comment likes, etc should be posts to our community_inbox
|
||||||
|
// The only data we should be periodically fetching (if it hasn't been fetched in the last day
|
||||||
|
// maybe), is community and user actors
|
||||||
|
// and user actors
|
||||||
|
// Fetch all posts in the outbox of the given user, and insert them into the database.
|
||||||
|
// fn fetch_community_outbox(community: &Community, conn: &PgConnection) -> Result<Vec<Post>, Error> {
|
||||||
|
// let outbox_url = Url::parse(&community.get_outbox_url())?;
|
||||||
|
// let outbox = fetch_remote_object::<OrderedCollection>(&outbox_url)?;
|
||||||
|
// let items = outbox.collection_props.get_many_items_base_boxes();
|
||||||
|
|
||||||
|
// Ok(
|
||||||
|
// items
|
||||||
|
// .unwrap()
|
||||||
|
// .map(|obox: &BaseBox| -> Result<PostForm, Error> {
|
||||||
|
// let page = obox.clone().to_concrete::<Page>()?;
|
||||||
|
// PostForm::from_page(&page, conn)
|
||||||
|
// })
|
||||||
|
// .map(|pf| upsert_post(&pf?, conn))
|
||||||
|
// .collect::<Result<Vec<Post>, Error>>()?,
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
|
|
@ -8,64 +8,48 @@ pub mod user;
|
||||||
pub mod user_inbox;
|
pub mod user_inbox;
|
||||||
|
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
context, public, BaseBox,
|
|
||||||
actor::{
|
|
||||||
Actor,
|
|
||||||
Person,
|
|
||||||
Group,
|
|
||||||
properties::ApActorProperties,
|
|
||||||
},
|
|
||||||
activity::{Accept, Create, Follow, Update},
|
activity::{Accept, Create, Follow, Update},
|
||||||
object::{
|
actor::{properties::ApActorProperties, Actor, Group, Person},
|
||||||
Page,
|
collection::UnorderedCollection,
|
||||||
properties::ObjectProperties,
|
context,
|
||||||
},
|
ext::{Ext, Extensible, Extension},
|
||||||
ext::{
|
object::{properties::ObjectProperties, Page},
|
||||||
Ext,
|
public, BaseBox,
|
||||||
Extensible,
|
|
||||||
Extension,
|
|
||||||
},
|
|
||||||
collection::{
|
|
||||||
UnorderedCollection,
|
|
||||||
OrderedCollection,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use actix_web::body::Body;
|
use actix_web::body::Body;
|
||||||
use actix_web::{web, Result, HttpRequest, HttpResponse};
|
|
||||||
use actix_web::web::Path;
|
use actix_web::web::Path;
|
||||||
use url::Url;
|
use actix_web::{web, HttpRequest, HttpResponse, Result};
|
||||||
use failure::Error;
|
|
||||||
use failure::_core::fmt::Debug;
|
|
||||||
use log::debug;
|
|
||||||
use isahc::prelude::*;
|
|
||||||
use diesel::result::Error::NotFound;
|
use diesel::result::Error::NotFound;
|
||||||
use diesel::PgConnection;
|
use diesel::PgConnection;
|
||||||
|
use failure::Error;
|
||||||
|
use failure::_core::fmt::Debug;
|
||||||
use http::request::Builder;
|
use http::request::Builder;
|
||||||
use http_signature_normalization::Config;
|
use http_signature_normalization::Config;
|
||||||
|
use isahc::prelude::*;
|
||||||
|
use log::debug;
|
||||||
use openssl::hash::MessageDigest;
|
use openssl::hash::MessageDigest;
|
||||||
use openssl::sign::{Signer, Verifier};
|
use openssl::sign::{Signer, Verifier};
|
||||||
use openssl::{pkey::PKey, rsa::Rsa};
|
use openssl::{pkey::PKey, rsa::Rsa};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use crate::routes::{DbPoolParam, ChatServerParam};
|
use crate::api::site::SearchResponse;
|
||||||
use crate::routes::nodeinfo::{NodeInfo, NodeInfoWellKnown};
|
use crate::db::community::{Community, CommunityFollower, CommunityFollowerForm, CommunityForm};
|
||||||
use crate::{convert_datetime, naive_now, Settings};
|
|
||||||
use crate::db::community::{Community, CommunityForm, CommunityFollower, CommunityFollowerForm};
|
|
||||||
use crate::db::community_view::{CommunityFollowerView, CommunityView};
|
use crate::db::community_view::{CommunityFollowerView, CommunityView};
|
||||||
use crate::db::post::{Post, PostForm};
|
use crate::db::post::{Post, PostForm};
|
||||||
use crate::db::post_view::PostView;
|
|
||||||
use crate::db::user::{UserForm, User_};
|
use crate::db::user::{UserForm, User_};
|
||||||
use crate::db::user_view::UserView;
|
use crate::db::user_view::UserView;
|
||||||
// TODO check on unpooled connection
|
use crate::db::{Crud, Followable, SearchType};
|
||||||
use crate::db::{Crud, Followable, SearchType, establish_unpooled_connection};
|
use crate::routes::nodeinfo::{NodeInfo, NodeInfoWellKnown};
|
||||||
use crate::api::site::SearchResponse;
|
use crate::routes::{ChatServerParam, DbPoolParam};
|
||||||
|
use crate::{convert_datetime, naive_now, Settings};
|
||||||
|
|
||||||
use signatures::{PublicKey, PublicKeyExtension, sign};
|
|
||||||
use activities::accept_follow;
|
use activities::accept_follow;
|
||||||
|
use fetcher::{get_or_fetch_and_upsert_remote_community, get_or_fetch_and_upsert_remote_user};
|
||||||
use signatures::verify;
|
use signatures::verify;
|
||||||
use fetcher::{fetch_remote_object, get_or_fetch_and_upsert_remote_user, get_or_fetch_and_upsert_remote_community};
|
use signatures::{sign, PublicKey, PublicKeyExtension};
|
||||||
|
|
||||||
type GroupExt = Ext<Ext<Group, ApActorProperties>, PublicKeyExtension>;
|
type GroupExt = Ext<Ext<Group, ApActorProperties>, PublicKeyExtension>;
|
||||||
type PersonExt = Ext<Ext<Person, ApActorProperties>, PublicKeyExtension>;
|
type PersonExt = Ext<Ext<Person, ApActorProperties>, PublicKeyExtension>;
|
||||||
|
@ -140,3 +124,35 @@ fn is_apub_id_valid(apub_id: &Url) -> bool {
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Not sure good names for these
|
||||||
|
pub trait ToApub<Response> {
|
||||||
|
fn to_apub(&self, conn: &PgConnection) -> Result<Response, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FromApub<ApubType> {
|
||||||
|
fn from_apub(apub: &ApubType, conn: &PgConnection) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ActorType {
|
||||||
|
fn actor_id(&self) -> String;
|
||||||
|
|
||||||
|
fn get_inbox_url(&self) -> String {
|
||||||
|
format!("{}/inbox", &self.actor_id())
|
||||||
|
}
|
||||||
|
fn get_outbox_url(&self) -> String {
|
||||||
|
format!("{}/outbox", &self.actor_id())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_followers_url(&self) -> String {
|
||||||
|
format!("{}/followers", &self.actor_id())
|
||||||
|
}
|
||||||
|
fn get_following_url(&self) -> String {
|
||||||
|
format!("{}/following", &self.actor_id())
|
||||||
|
}
|
||||||
|
fn get_liked_url(&self) -> String {
|
||||||
|
format!("{}/liked", &self.actor_id())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,16 +9,15 @@ pub struct PostQuery {
|
||||||
pub async fn get_apub_post(
|
pub async fn get_apub_post(
|
||||||
info: Path<PostQuery>,
|
info: Path<PostQuery>,
|
||||||
db: DbPoolParam,
|
db: DbPoolParam,
|
||||||
chat_server: ChatServerParam,
|
|
||||||
) -> Result<HttpResponse<Body>, Error> {
|
) -> Result<HttpResponse<Body>, Error> {
|
||||||
let id = info.post_id.parse::<i32>()?;
|
let id = info.post_id.parse::<i32>()?;
|
||||||
let post = Post::read(&&db.get()?, id)?;
|
let post = Post::read(&&db.get()?, id)?;
|
||||||
Ok(create_apub_response(&post.as_page(&db.get().unwrap())?))
|
Ok(create_apub_response(&post.to_apub(&db.get().unwrap())?))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Post {
|
impl ToApub<Page> for Post {
|
||||||
// Turn a Lemmy post into an ActivityPub page that can be sent out over the network.
|
// Turn a Lemmy post into an ActivityPub page that can be sent out over the network.
|
||||||
pub fn as_page(&self, conn: &PgConnection) -> Result<Page, Error> {
|
fn to_apub(&self, conn: &PgConnection) -> Result<Page, Error> {
|
||||||
let mut page = Page::default();
|
let mut page = Page::default();
|
||||||
let oprops: &mut ObjectProperties = page.as_mut();
|
let oprops: &mut ObjectProperties = page.as_mut();
|
||||||
let creator = User_::read(conn, self.creator_id)?;
|
let creator = User_::read(conn, self.creator_id)?;
|
||||||
|
@ -54,9 +53,9 @@ impl Post {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PostForm {
|
impl FromApub<Page> for PostForm {
|
||||||
/// Parse an ActivityPub page received from another instance into a Lemmy post.
|
/// Parse an ActivityPub page received from another instance into a Lemmy post.
|
||||||
pub fn from_page(page: &Page, conn: &PgConnection) -> Result<PostForm, Error> {
|
fn from_apub(page: &Page, conn: &PgConnection) -> Result<PostForm, Error> {
|
||||||
let oprops = &page.object_props;
|
let oprops = &page.object_props;
|
||||||
let creator_actor_id = &oprops.get_attributed_to_xsd_any_uri().unwrap().to_string();
|
let creator_actor_id = &oprops.get_attributed_to_xsd_any_uri().unwrap().to_string();
|
||||||
let creator = get_or_fetch_and_upsert_remote_user(&creator_actor_id, &conn)?;
|
let creator = get_or_fetch_and_upsert_remote_user(&creator_actor_id, &conn)?;
|
||||||
|
|
|
@ -5,52 +5,54 @@ pub struct UserQuery {
|
||||||
user_name: String,
|
user_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn a Lemmy user into an ActivityPub person and return it as json.
|
impl ToApub<PersonExt> for User_ {
|
||||||
pub async fn get_apub_user(
|
// Turn a Lemmy Community into an ActivityPub group that can be sent out over the network.
|
||||||
info: Path<UserQuery>,
|
fn to_apub(&self, _conn: &PgConnection) -> Result<PersonExt, Error> {
|
||||||
db: DbPoolParam,
|
// TODO go through all these to_string and to_owned()
|
||||||
chat_server: ChatServerParam,
|
let mut person = Person::default();
|
||||||
) -> Result<HttpResponse<Body>, Error> {
|
let oprops: &mut ObjectProperties = person.as_mut();
|
||||||
let user = User_::find_by_email_or_username(&&db.get()?, &info.user_name)?;
|
oprops
|
||||||
|
.set_context_xsd_any_uri(context())?
|
||||||
|
.set_id(self.actor_id.to_string())?
|
||||||
|
.set_name_xsd_string(self.name.to_owned())?
|
||||||
|
.set_published(convert_datetime(self.published))?;
|
||||||
|
|
||||||
let mut person = Person::default();
|
if let Some(u) = self.updated {
|
||||||
let oprops: &mut ObjectProperties = person.as_mut();
|
oprops.set_updated(convert_datetime(u))?;
|
||||||
oprops
|
}
|
||||||
.set_context_xsd_any_uri(context())?
|
|
||||||
.set_id(user.actor_id.to_string())?
|
|
||||||
.set_name_xsd_string(user.name.to_owned())?
|
|
||||||
.set_published(convert_datetime(user.published))?;
|
|
||||||
|
|
||||||
if let Some(u) = user.updated {
|
if let Some(i) = &self.preferred_username {
|
||||||
oprops.set_updated(convert_datetime(u))?;
|
oprops.set_name_xsd_string(i.to_owned())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut actor_props = ApActorProperties::default();
|
||||||
|
|
||||||
|
actor_props
|
||||||
|
.set_inbox(self.get_inbox_url())?
|
||||||
|
.set_outbox(self.get_outbox_url())?
|
||||||
|
.set_followers(self.get_followers_url())?
|
||||||
|
.set_following(self.get_following_url())?
|
||||||
|
.set_liked(self.get_liked_url())?;
|
||||||
|
|
||||||
|
let public_key = PublicKey {
|
||||||
|
id: format!("{}#main-key", self.actor_id),
|
||||||
|
owner: self.actor_id.to_owned(),
|
||||||
|
public_key_pem: self.public_key.to_owned().unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(person.extend(actor_props).extend(public_key.to_ext()))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(i) = &user.preferred_username {
|
|
||||||
oprops.set_name_xsd_string(i.to_owned())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut actor_props = ApActorProperties::default();
|
|
||||||
|
|
||||||
actor_props
|
|
||||||
.set_inbox(format!("{}/inbox", &user.actor_id))?
|
|
||||||
.set_outbox(format!("{}/outbox", &user.actor_id))?
|
|
||||||
.set_following(format!("{}/following", &user.actor_id))?
|
|
||||||
.set_liked(format!("{}/liked", &user.actor_id))?;
|
|
||||||
|
|
||||||
let public_key = PublicKey {
|
|
||||||
id: format!("{}#main-key", user.actor_id),
|
|
||||||
owner: user.actor_id.to_owned(),
|
|
||||||
public_key_pem: user.public_key.unwrap(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(create_apub_response(
|
|
||||||
&person.extend(actor_props).extend(public_key.to_ext()),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserForm {
|
impl ActorType for User_ {
|
||||||
|
fn actor_id(&self) -> String {
|
||||||
|
self.actor_id.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromApub<PersonExt> for UserForm {
|
||||||
/// Parse an ActivityPub person received from another instance into a Lemmy user.
|
/// Parse an ActivityPub person received from another instance into a Lemmy user.
|
||||||
pub fn from_person(person: &PersonExt) -> Result<Self, Error> {
|
fn from_apub(person: &PersonExt, _conn: &PgConnection) -> Result<Self, Error> {
|
||||||
let oprops = &person.base.base.object_props;
|
let oprops = &person.base.base.object_props;
|
||||||
let aprops = &person.base.extension;
|
let aprops = &person.base.extension;
|
||||||
let public_key: &PublicKey = &person.extension.public_key;
|
let public_key: &PublicKey = &person.extension.public_key;
|
||||||
|
@ -83,3 +85,13 @@ impl UserForm {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the user json over HTTP.
|
||||||
|
pub async fn get_apub_user_http(
|
||||||
|
info: Path<UserQuery>,
|
||||||
|
db: DbPoolParam,
|
||||||
|
) -> Result<HttpResponse<Body>, Error> {
|
||||||
|
let user = User_::find_by_email_or_username(&&db.get()?, &info.user_name)?;
|
||||||
|
let u = user.to_apub(&db.get().unwrap())?;
|
||||||
|
Ok(create_apub_response(&u))
|
||||||
|
}
|
||||||
|
|
|
@ -14,17 +14,13 @@ pub async fn user_inbox(
|
||||||
input: web::Json<UserAcceptedObjects>,
|
input: web::Json<UserAcceptedObjects>,
|
||||||
path: web::Path<String>,
|
path: web::Path<String>,
|
||||||
db: DbPoolParam,
|
db: DbPoolParam,
|
||||||
chat_server: ChatServerParam,
|
_chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
// TODO: would be nice if we could do the signature check here, but we cant access the actor property
|
// TODO: would be nice if we could do the signature check here, but we cant access the actor property
|
||||||
let input = input.into_inner();
|
let input = input.into_inner();
|
||||||
let conn = &db.get().unwrap();
|
let conn = &db.get().unwrap();
|
||||||
let username = path.into_inner();
|
let username = path.into_inner();
|
||||||
debug!(
|
debug!("User {} received activity: {:?}", &username, &input);
|
||||||
"User {} received activity: {:?}",
|
|
||||||
&username,
|
|
||||||
&input
|
|
||||||
);
|
|
||||||
|
|
||||||
match input {
|
match input {
|
||||||
UserAcceptedObjects::Create(c) => handle_create(&c, &request, &username, &conn),
|
UserAcceptedObjects::Create(c) => handle_create(&c, &request, &username, &conn),
|
||||||
|
@ -37,18 +33,18 @@ pub async fn user_inbox(
|
||||||
fn handle_create(
|
fn handle_create(
|
||||||
create: &Create,
|
create: &Create,
|
||||||
request: &HttpRequest,
|
request: &HttpRequest,
|
||||||
username: &str,
|
_username: &str,
|
||||||
conn: &PgConnection,
|
conn: &PgConnection,
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
// TODO before this even gets named, because we don't know what type of object it is, we need
|
// TODO before this even gets named, because we don't know what type of object it is, we need
|
||||||
// to parse this out
|
// to parse this out
|
||||||
let community_uri = create
|
let user_uri = create
|
||||||
.create_props
|
.create_props
|
||||||
.get_actor_xsd_any_uri()
|
.get_actor_xsd_any_uri()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string();
|
.to_string();
|
||||||
// TODO: should do this in a generic way so we dont need to know if its a user or a community
|
|
||||||
let user = fetch_remote_user(&Url::parse(&community_uri)?, conn)?;
|
let user = get_or_fetch_and_upsert_remote_user(&user_uri, &conn)?;
|
||||||
verify(request, &user.public_key.unwrap())?;
|
verify(request, &user.public_key.unwrap())?;
|
||||||
|
|
||||||
let page = create
|
let page = create
|
||||||
|
@ -58,7 +54,7 @@ fn handle_create(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_owned()
|
.to_owned()
|
||||||
.to_concrete::<Page>()?;
|
.to_concrete::<Page>()?;
|
||||||
let post = PostForm::from_page(&page, conn)?;
|
let post = PostForm::from_apub(&page, conn)?;
|
||||||
Post::create(conn, &post)?;
|
Post::create(conn, &post)?;
|
||||||
// TODO: send the new post out via websocket
|
// TODO: send the new post out via websocket
|
||||||
Ok(HttpResponse::Ok().finish())
|
Ok(HttpResponse::Ok().finish())
|
||||||
|
@ -68,15 +64,16 @@ fn handle_create(
|
||||||
fn handle_update(
|
fn handle_update(
|
||||||
update: &Update,
|
update: &Update,
|
||||||
request: &HttpRequest,
|
request: &HttpRequest,
|
||||||
username: &str,
|
_username: &str,
|
||||||
conn: &PgConnection,
|
conn: &PgConnection,
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
let community_uri = update
|
let user_uri = update
|
||||||
.update_props
|
.update_props
|
||||||
.get_actor_xsd_any_uri()
|
.get_actor_xsd_any_uri()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string();
|
.to_string();
|
||||||
let user = fetch_remote_user(&Url::parse(&community_uri)?, conn)?;
|
|
||||||
|
let user = get_or_fetch_and_upsert_remote_user(&user_uri, &conn)?;
|
||||||
verify(request, &user.public_key.unwrap())?;
|
verify(request, &user.public_key.unwrap())?;
|
||||||
|
|
||||||
let page = update
|
let page = update
|
||||||
|
@ -86,7 +83,7 @@ fn handle_update(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_owned()
|
.to_owned()
|
||||||
.to_concrete::<Page>()?;
|
.to_concrete::<Page>()?;
|
||||||
let post = PostForm::from_page(&page, conn)?;
|
let post = PostForm::from_apub(&page, conn)?;
|
||||||
let id = Post::read_from_apub_id(conn, &post.ap_id)?.id;
|
let id = Post::read_from_apub_id(conn, &post.ap_id)?.id;
|
||||||
Post::update(conn, id, &post)?;
|
Post::update(conn, id, &post)?;
|
||||||
// TODO: send the new post out via websocket
|
// TODO: send the new post out via websocket
|
||||||
|
|
|
@ -21,11 +21,12 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||||
"/c/{community_name}/followers",
|
"/c/{community_name}/followers",
|
||||||
web::get().to(get_apub_community_followers),
|
web::get().to(get_apub_community_followers),
|
||||||
)
|
)
|
||||||
.route(
|
// TODO This is only useful for history which we aren't doing right now
|
||||||
"/c/{community_name}/outbox",
|
// .route(
|
||||||
web::get().to(get_apub_community_outbox),
|
// "/c/{community_name}/outbox",
|
||||||
)
|
// web::get().to(get_apub_community_outbox),
|
||||||
.route("/u/{user_name}", web::get().to(get_apub_user))
|
// )
|
||||||
|
.route("/u/{user_name}", web::get().to(get_apub_user_http))
|
||||||
.route("/post/{post_id}", web::get().to(get_apub_post)),
|
.route("/post/{post_id}", web::get().to(get_apub_post)),
|
||||||
)
|
)
|
||||||
// Inboxes dont work with the header guard for some reason.
|
// Inboxes dont work with the header guard for some reason.
|
||||||
|
|
Loading…
Reference in a new issue