Compare commits
2 commits
main
...
apub-remov
Author | SHA1 | Date | |
---|---|---|---|
8c9928bcdf | |||
6b0bc1029f |
22 changed files with 528 additions and 282 deletions
|
@ -31,6 +31,18 @@ use regex::{Regex, RegexBuilder};
|
||||||
use std::io::{Error, ErrorKind};
|
use std::io::{Error, ErrorKind};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! location_info {
|
||||||
|
() => {
|
||||||
|
format!(
|
||||||
|
"None value at {}:{}, column {}",
|
||||||
|
file!(),
|
||||||
|
line!(),
|
||||||
|
column!()
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_datetime_utc(ndt: NaiveDateTime) -> DateTime<Utc> {
|
pub fn to_datetime_utc(ndt: NaiveDateTime) -> DateTime<Utc> {
|
||||||
DateTime::<Utc>::from_utc(ndt, Utc)
|
DateTime::<Utc>::from_utc(ndt, Utc)
|
||||||
}
|
}
|
||||||
|
|
|
@ -605,11 +605,11 @@ impl Perform for Oper<FollowCommunity> {
|
||||||
// Dont actually add to the community followers here, because you need
|
// Dont actually add to the community followers here, because you need
|
||||||
// to wait for the accept
|
// to wait for the accept
|
||||||
user
|
user
|
||||||
.send_follow(&community.actor_id, &self.client, pool)
|
.send_follow(&community.actor_id()?, &self.client, pool)
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
} else {
|
||||||
user
|
user
|
||||||
.send_unfollow(&community.actor_id, &self.client, pool)
|
.send_unfollow(&community.actor_id()?, &self.client, pool)
|
||||||
.await?;
|
.await?;
|
||||||
let unfollow = move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form);
|
let unfollow = move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form);
|
||||||
if blocking(pool, unfollow).await?.is_err() {
|
if blocking(pool, unfollow).await?.is_err() {
|
||||||
|
|
|
@ -21,7 +21,7 @@ use uuid::Uuid;
|
||||||
pub async fn send_activity_to_community(
|
pub async fn send_activity_to_community(
|
||||||
creator: &User_,
|
creator: &User_,
|
||||||
community: &Community,
|
community: &Community,
|
||||||
to: Vec<String>,
|
to: Vec<Url>,
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
|
@ -43,17 +43,18 @@ pub async fn send_activity(
|
||||||
client: &Client,
|
client: &Client,
|
||||||
activity: &AnyBase,
|
activity: &AnyBase,
|
||||||
actor: &dyn ActorType,
|
actor: &dyn ActorType,
|
||||||
to: Vec<String>,
|
to: Vec<Url>,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let activity = serde_json::to_string(&activity)?;
|
let activity = serde_json::to_string(&activity)?;
|
||||||
debug!("Sending activitypub activity {} to {:?}", activity, to);
|
debug!("Sending activitypub activity {} to {:?}", activity, to);
|
||||||
|
|
||||||
for t in to {
|
for to_url in to {
|
||||||
let to_url = Url::parse(&t)?;
|
|
||||||
check_is_apub_id_valid(&to_url)?;
|
check_is_apub_id_valid(&to_url)?;
|
||||||
|
|
||||||
let res = retry_custom(|| async {
|
let res = retry_custom(|| async {
|
||||||
let request = client.post(&t).header("Content-Type", "application/json");
|
let request = client
|
||||||
|
.post(to_url.as_str())
|
||||||
|
.header("Content-Type", "application/json");
|
||||||
|
|
||||||
match sign(request, actor, activity.clone()).await {
|
match sign(request, actor, activity.clone()).await {
|
||||||
Ok(signed) => Ok(signed.send().await),
|
Ok(signed) => Ok(signed.send().await),
|
||||||
|
|
|
@ -41,6 +41,7 @@ use activitystreams::{
|
||||||
public,
|
public,
|
||||||
};
|
};
|
||||||
use actix_web::{body::Body, client::Client, web::Path, HttpResponse};
|
use actix_web::{body::Body, client::Client, web::Path, HttpResponse};
|
||||||
|
use anyhow::Context;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::{Comment, CommentForm},
|
comment::{Comment, CommentForm},
|
||||||
|
@ -49,7 +50,13 @@ use lemmy_db::{
|
||||||
user::User_,
|
user::User_,
|
||||||
Crud,
|
Crud,
|
||||||
};
|
};
|
||||||
use lemmy_utils::{convert_datetime, remove_slurs, scrape_text_for_mentions, MentionData};
|
use lemmy_utils::{
|
||||||
|
convert_datetime,
|
||||||
|
location_info,
|
||||||
|
remove_slurs,
|
||||||
|
scrape_text_for_mentions,
|
||||||
|
MentionData,
|
||||||
|
};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::Error;
|
use serde_json::Error;
|
||||||
|
@ -136,21 +143,21 @@ impl FromApub for CommentForm {
|
||||||
) -> Result<CommentForm, LemmyError> {
|
) -> Result<CommentForm, LemmyError> {
|
||||||
let creator_actor_id = ¬e
|
let creator_actor_id = ¬e
|
||||||
.attributed_to()
|
.attributed_to()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_single_xsd_any_uri()
|
.as_single_xsd_any_uri()
|
||||||
.unwrap();
|
.context(location_info!())?;
|
||||||
|
|
||||||
let creator = get_or_fetch_and_upsert_user(creator_actor_id, client, pool).await?;
|
let creator = get_or_fetch_and_upsert_user(creator_actor_id, client, pool).await?;
|
||||||
|
|
||||||
let mut in_reply_tos = note
|
let mut in_reply_tos = note
|
||||||
.in_reply_to()
|
.in_reply_to()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_many()
|
.as_many()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| i.as_xsd_any_uri().unwrap());
|
.map(|i| i.as_xsd_any_uri().context(""));
|
||||||
let post_ap_id = in_reply_tos.next().unwrap();
|
let post_ap_id = in_reply_tos.next().context(location_info!())??;
|
||||||
|
|
||||||
// This post, or the parent comment might not yet exist on this server yet, fetch them.
|
// This post, or the parent comment might not yet exist on this server yet, fetch them.
|
||||||
let post = get_or_fetch_and_insert_post(&post_ap_id, client, pool).await?;
|
let post = get_or_fetch_and_insert_post(&post_ap_id, client, pool).await?;
|
||||||
|
@ -159,7 +166,7 @@ impl FromApub for CommentForm {
|
||||||
// For deeply nested comments, FromApub automatically gets called recursively
|
// For deeply nested comments, FromApub automatically gets called recursively
|
||||||
let parent_id: Option<i32> = match in_reply_tos.next() {
|
let parent_id: Option<i32> = match in_reply_tos.next() {
|
||||||
Some(parent_comment_uri) => {
|
Some(parent_comment_uri) => {
|
||||||
let parent_comment_ap_id = &parent_comment_uri;
|
let parent_comment_ap_id = &parent_comment_uri?;
|
||||||
let parent_comment =
|
let parent_comment =
|
||||||
get_or_fetch_and_insert_comment(&parent_comment_ap_id, client, pool).await?;
|
get_or_fetch_and_insert_comment(&parent_comment_ap_id, client, pool).await?;
|
||||||
|
|
||||||
|
@ -169,9 +176,9 @@ impl FromApub for CommentForm {
|
||||||
};
|
};
|
||||||
let content = note
|
let content = note
|
||||||
.content()
|
.content()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_single_xsd_string()
|
.as_single_xsd_string()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.to_string();
|
.to_string();
|
||||||
let content_slurs_removed = remove_slurs(&content);
|
let content_slurs_removed = remove_slurs(&content);
|
||||||
|
|
||||||
|
@ -295,7 +302,7 @@ impl ApubObjectType for Comment {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
&creator,
|
&creator,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
delete.into_any_base()?,
|
delete.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -337,7 +344,7 @@ impl ApubObjectType for Comment {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
&creator,
|
&creator,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
undo.into_any_base()?,
|
undo.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -370,7 +377,7 @@ impl ApubObjectType for Comment {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
&mod_,
|
&mod_,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
remove.into_any_base()?,
|
remove.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -412,7 +419,7 @@ impl ApubObjectType for Comment {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
&mod_,
|
&mod_,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
undo.into_any_base()?,
|
undo.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -448,7 +455,7 @@ impl ApubLikeableType for Comment {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
&creator,
|
&creator,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
like.into_any_base()?,
|
like.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -481,7 +488,7 @@ impl ApubLikeableType for Comment {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
&creator,
|
&creator,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
dislike.into_any_base()?,
|
dislike.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -522,7 +529,7 @@ impl ApubLikeableType for Comment {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
&creator,
|
&creator,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
undo.into_any_base()?,
|
undo.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -534,7 +541,7 @@ impl ApubLikeableType for Comment {
|
||||||
|
|
||||||
struct MentionsAndAddresses {
|
struct MentionsAndAddresses {
|
||||||
addressed_ccs: Vec<String>,
|
addressed_ccs: Vec<String>,
|
||||||
inboxes: Vec<String>,
|
inboxes: Vec<Url>,
|
||||||
tags: Vec<Mention>,
|
tags: Vec<Mention>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,7 +576,7 @@ async fn collect_non_local_mentions_and_addresses(
|
||||||
.filter(|m| !m.is_local())
|
.filter(|m| !m.is_local())
|
||||||
.collect::<Vec<MentionData>>();
|
.collect::<Vec<MentionData>>();
|
||||||
|
|
||||||
let mut mention_inboxes = Vec::new();
|
let mut mention_inboxes: Vec<Url> = Vec::new();
|
||||||
for mention in &mentions {
|
for mention in &mentions {
|
||||||
// TODO should it be fetching it every time?
|
// TODO should it be fetching it every time?
|
||||||
if let Ok(actor_id) = fetch_webfinger_url(mention, client).await {
|
if let Ok(actor_id) = fetch_webfinger_url(mention, client).await {
|
||||||
|
@ -577,7 +584,7 @@ async fn collect_non_local_mentions_and_addresses(
|
||||||
addressed_ccs.push(actor_id.to_owned().to_string());
|
addressed_ccs.push(actor_id.to_owned().to_string());
|
||||||
|
|
||||||
let mention_user = get_or_fetch_and_upsert_user(&actor_id, client, pool).await?;
|
let mention_user = get_or_fetch_and_upsert_user(&actor_id, client, pool).await?;
|
||||||
let shared_inbox = mention_user.get_shared_inbox_url();
|
let shared_inbox = mention_user.get_shared_inbox_url()?;
|
||||||
|
|
||||||
mention_inboxes.push(shared_inbox);
|
mention_inboxes.push(shared_inbox);
|
||||||
let mut mention_tag = Mention::new();
|
let mut mention_tag = Mention::new();
|
||||||
|
@ -586,7 +593,7 @@ async fn collect_non_local_mentions_and_addresses(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut inboxes = vec![community.get_shared_inbox_url()];
|
let mut inboxes = vec![community.get_shared_inbox_url()?];
|
||||||
inboxes.extend(mention_inboxes);
|
inboxes.extend(mention_inboxes);
|
||||||
inboxes = inboxes.into_iter().unique().collect();
|
inboxes = inboxes.into_iter().unique().collect();
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,7 @@ use crate::{
|
||||||
create_apub_tombstone_response,
|
create_apub_tombstone_response,
|
||||||
create_tombstone,
|
create_tombstone,
|
||||||
extensions::group_extensions::GroupExtension,
|
extensions::group_extensions::GroupExtension,
|
||||||
fetcher::get_or_fetch_and_upsert_user,
|
fetcher::{get_or_fetch_and_upsert_actor, get_or_fetch_and_upsert_user},
|
||||||
get_shared_inbox,
|
|
||||||
insert_activity,
|
insert_activity,
|
||||||
ActorType,
|
ActorType,
|
||||||
FromApub,
|
FromApub,
|
||||||
|
@ -40,6 +39,7 @@ use activitystreams::{
|
||||||
};
|
};
|
||||||
use activitystreams_ext::Ext2;
|
use activitystreams_ext::Ext2;
|
||||||
use actix_web::{body::Body, client::Client, web, HttpResponse};
|
use actix_web::{body::Body, client::Client, web, HttpResponse};
|
||||||
|
use anyhow::Context;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
community::{Community, CommunityForm},
|
community::{Community, CommunityForm},
|
||||||
|
@ -48,7 +48,7 @@ use lemmy_db::{
|
||||||
post::Post,
|
post::Post,
|
||||||
user::User_,
|
user::User_,
|
||||||
};
|
};
|
||||||
use lemmy_utils::convert_datetime;
|
use lemmy_utils::{convert_datetime, get_apub_protocol_string, location_info};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ impl ToApub for Community {
|
||||||
.set_following(self.get_following_url().parse()?)
|
.set_following(self.get_following_url().parse()?)
|
||||||
.set_liked(self.get_liked_url().parse()?)
|
.set_liked(self.get_liked_url().parse()?)
|
||||||
.set_endpoints(Endpoints {
|
.set_endpoints(Endpoints {
|
||||||
shared_inbox: Some(self.get_shared_inbox_url().parse()?),
|
shared_inbox: Some(self.get_shared_inbox_url()?),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ impl ToApub for Community {
|
||||||
Ok(Ext2::new(
|
Ok(Ext2::new(
|
||||||
ap_actor,
|
ap_actor,
|
||||||
group_extension,
|
group_extension,
|
||||||
self.get_public_key_ext(),
|
self.get_public_key_ext()?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,11 +128,11 @@ impl ActorType for Community {
|
||||||
self.actor_id.to_owned()
|
self.actor_id.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn public_key(&self) -> String {
|
fn public_key(&self) -> Option<String> {
|
||||||
self.public_key.to_owned().unwrap()
|
self.public_key.to_owned()
|
||||||
}
|
}
|
||||||
fn private_key(&self) -> String {
|
fn private_key(&self) -> Option<String> {
|
||||||
self.private_key.to_owned().unwrap()
|
self.private_key.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// As a local community, accept the follow request from a remote user.
|
/// As a local community, accept the follow request from a remote user.
|
||||||
|
@ -142,10 +142,14 @@ impl ActorType for Community {
|
||||||
client: &Client,
|
client: &Client,
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let actor_uri = follow.actor()?.as_single_xsd_any_uri().unwrap().to_string();
|
let actor_uri = follow
|
||||||
|
.actor()?
|
||||||
|
.as_single_xsd_any_uri()
|
||||||
|
.context(location_info!())?;
|
||||||
|
let actor = get_or_fetch_and_upsert_actor(actor_uri, client, pool).await?;
|
||||||
|
|
||||||
let mut accept = Accept::new(self.actor_id.to_owned(), follow.into_any_base()?);
|
let mut accept = Accept::new(self.actor_id.to_owned(), follow.into_any_base()?);
|
||||||
let to = format!("{}/inbox", actor_uri);
|
let to = actor.get_inbox_url()?;
|
||||||
accept
|
accept
|
||||||
.set_context(context())
|
.set_context(context())
|
||||||
.set_id(generate_activity_id(AcceptType::Accept)?)
|
.set_id(generate_activity_id(AcceptType::Accept)?)
|
||||||
|
@ -279,7 +283,10 @@ impl ActorType for Community {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For a given community, returns the inboxes of all followers.
|
/// For a given community, returns the inboxes of all followers.
|
||||||
async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<String>, LemmyError> {
|
///
|
||||||
|
/// TODO: this function is very badly implemented, we should just store shared_inbox_url in
|
||||||
|
/// CommunityFollowerView
|
||||||
|
async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
|
||||||
let id = self.id;
|
let id = self.id;
|
||||||
|
|
||||||
let inboxes = blocking(pool, move |conn| {
|
let inboxes = blocking(pool, move |conn| {
|
||||||
|
@ -288,8 +295,22 @@ impl ActorType for Community {
|
||||||
.await??;
|
.await??;
|
||||||
let inboxes = inboxes
|
let inboxes = inboxes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|c| get_shared_inbox(&Url::parse(&c.user_actor_id).unwrap()))
|
.map(|u| -> Result<Url, LemmyError> {
|
||||||
.filter(|s| !s.is_empty())
|
let url = Url::parse(&u.user_actor_id)?;
|
||||||
|
let domain = url.domain().context(location_info!())?;
|
||||||
|
let port = if let Some(port) = url.port() {
|
||||||
|
format!(":{}", port)
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
Ok(Url::parse(&format!(
|
||||||
|
"{}://{}{}/inbox",
|
||||||
|
get_apub_protocol_string(),
|
||||||
|
domain,
|
||||||
|
port,
|
||||||
|
))?)
|
||||||
|
})
|
||||||
|
.filter_map(Result::ok)
|
||||||
.unique()
|
.unique()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -298,7 +319,7 @@ impl ActorType for Community {
|
||||||
|
|
||||||
async fn send_follow(
|
async fn send_follow(
|
||||||
&self,
|
&self,
|
||||||
_follow_actor_id: &str,
|
_follow_actor_id: &Url,
|
||||||
_client: &Client,
|
_client: &Client,
|
||||||
_pool: &DbPool,
|
_pool: &DbPool,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
|
@ -307,7 +328,7 @@ impl ActorType for Community {
|
||||||
|
|
||||||
async fn send_unfollow(
|
async fn send_unfollow(
|
||||||
&self,
|
&self,
|
||||||
_follow_actor_id: &str,
|
_follow_actor_id: &Url,
|
||||||
_client: &Client,
|
_client: &Client,
|
||||||
_pool: &DbPool,
|
_pool: &DbPool,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
|
@ -330,44 +351,50 @@ impl FromApub for CommunityForm {
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
expected_domain: Option<Url>,
|
expected_domain: Option<Url>,
|
||||||
) -> Result<Self, LemmyError> {
|
) -> Result<Self, LemmyError> {
|
||||||
let creator_and_moderator_uris = group.inner.attributed_to().unwrap();
|
let creator_and_moderator_uris = group.inner.attributed_to().context(location_info!())?;
|
||||||
let creator_uri = creator_and_moderator_uris
|
let creator_uri = creator_and_moderator_uris
|
||||||
.as_many()
|
.as_many()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.iter()
|
.iter()
|
||||||
.next()
|
.next()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_xsd_any_uri()
|
.as_xsd_any_uri()
|
||||||
.unwrap();
|
.context(location_info!())?;
|
||||||
|
|
||||||
let creator = get_or_fetch_and_upsert_user(creator_uri, client, pool).await?;
|
let creator = get_or_fetch_and_upsert_user(creator_uri, client, pool).await?;
|
||||||
let name = group
|
let name = group
|
||||||
.inner
|
.inner
|
||||||
.name()
|
.name()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_one()
|
.as_one()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_xsd_string()
|
.as_xsd_string()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
|
.to_string();
|
||||||
|
let title = group
|
||||||
|
.inner
|
||||||
|
.preferred_username()
|
||||||
|
.context(location_info!())?
|
||||||
.to_string();
|
.to_string();
|
||||||
let title = group.inner.preferred_username().unwrap().to_string();
|
|
||||||
// TODO: should be parsed as html and tags like <script> removed (or use markdown source)
|
// TODO: should be parsed as html and tags like <script> removed (or use markdown source)
|
||||||
// -> same for post.content etc
|
// -> same for post.content etc
|
||||||
let description = group
|
let description = group
|
||||||
.inner
|
.inner
|
||||||
.content()
|
.content()
|
||||||
.map(|s| s.as_single_xsd_string().unwrap().into());
|
.map(|s| s.as_single_xsd_string())
|
||||||
|
.flatten()
|
||||||
|
.map(|s| s.to_string());
|
||||||
check_slurs(&name)?;
|
check_slurs(&name)?;
|
||||||
check_slurs(&title)?;
|
check_slurs(&title)?;
|
||||||
check_slurs_opt(&description)?;
|
check_slurs_opt(&description)?;
|
||||||
|
|
||||||
let icon = match group.icon() {
|
let icon = match group.icon() {
|
||||||
Some(any_image) => Some(
|
Some(any_image) => Some(
|
||||||
Image::from_any_base(any_image.as_one().unwrap().clone())
|
Image::from_any_base(any_image.as_one().context(location_info!())?.clone())
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.url()
|
.url()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_single_xsd_any_uri()
|
.as_single_xsd_any_uri()
|
||||||
.map(|u| u.to_string()),
|
.map(|u| u.to_string()),
|
||||||
),
|
),
|
||||||
|
@ -376,11 +403,11 @@ impl FromApub for CommunityForm {
|
||||||
|
|
||||||
let banner = match group.image() {
|
let banner = match group.image() {
|
||||||
Some(any_image) => Some(
|
Some(any_image) => Some(
|
||||||
Image::from_any_base(any_image.as_one().unwrap().clone())
|
Image::from_any_base(any_image.as_one().context(location_info!())?.clone())
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.url()
|
.url()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_single_xsd_any_uri()
|
.as_single_xsd_any_uri()
|
||||||
.map(|u| u.to_string()),
|
.map(|u| u.to_string()),
|
||||||
),
|
),
|
||||||
|
@ -499,13 +526,15 @@ pub async fn do_announce(
|
||||||
|
|
||||||
insert_activity(community.creator_id, announce.clone(), true, pool).await?;
|
insert_activity(community.creator_id, announce.clone(), true, pool).await?;
|
||||||
|
|
||||||
let mut to = community.get_follower_inboxes(pool).await?;
|
let mut to: Vec<Url> = community.get_follower_inboxes(pool).await?;
|
||||||
|
|
||||||
// dont send to the local instance, nor to the instance where the activity originally came from,
|
// dont send to the local instance, nor to the instance where the activity originally came from,
|
||||||
// because that would result in a database error (same data inserted twice)
|
// because that would result in a database error (same data inserted twice)
|
||||||
// this seems to be the "easiest" stable alternative for remove_item()
|
// this seems to be the "easiest" stable alternative for remove_item()
|
||||||
to.retain(|x| *x != sender.get_shared_inbox_url());
|
let sender_shared_inbox = sender.get_shared_inbox_url()?;
|
||||||
to.retain(|x| *x != community.get_shared_inbox_url());
|
to.retain(|x| x != &sender_shared_inbox);
|
||||||
|
let community_shared_inbox = community.get_shared_inbox_url()?;
|
||||||
|
to.retain(|x| x != &community_shared_inbox);
|
||||||
|
|
||||||
send_activity(client, &announce.into_any_base()?, community, to).await?;
|
send_activity(client, &announce.into_any_base()?, community, to).await?;
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,12 @@ use crate::{apub::ActorType, LemmyError};
|
||||||
use activitystreams::unparsed::UnparsedMutExt;
|
use activitystreams::unparsed::UnparsedMutExt;
|
||||||
use activitystreams_ext::UnparsedExtension;
|
use activitystreams_ext::UnparsedExtension;
|
||||||
use actix_web::{client::ClientRequest, HttpRequest};
|
use actix_web::{client::ClientRequest, HttpRequest};
|
||||||
use anyhow::anyhow;
|
use anyhow::{anyhow, Context};
|
||||||
use http_signature_normalization_actix::{
|
use http_signature_normalization_actix::{
|
||||||
digest::{DigestClient, SignExt},
|
digest::{DigestClient, SignExt},
|
||||||
Config,
|
Config,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::location_info;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use openssl::{
|
use openssl::{
|
||||||
hash::MessageDigest,
|
hash::MessageDigest,
|
||||||
|
@ -27,7 +28,7 @@ pub async fn sign(
|
||||||
activity: String,
|
activity: String,
|
||||||
) -> Result<DigestClient<String>, LemmyError> {
|
) -> Result<DigestClient<String>, LemmyError> {
|
||||||
let signing_key_id = format!("{}#main-key", actor.actor_id()?);
|
let signing_key_id = format!("{}#main-key", actor.actor_id()?);
|
||||||
let private_key = actor.private_key();
|
let private_key = actor.private_key().context(location_info!())?;
|
||||||
|
|
||||||
let digest_client = request
|
let digest_client = request
|
||||||
.signature_with_digest(
|
.signature_with_digest(
|
||||||
|
@ -37,8 +38,8 @@ pub async fn sign(
|
||||||
activity,
|
activity,
|
||||||
move |signing_string| {
|
move |signing_string| {
|
||||||
let private_key = PKey::private_key_from_pem(private_key.as_bytes())?;
|
let private_key = PKey::private_key_from_pem(private_key.as_bytes())?;
|
||||||
let mut signer = Signer::new(MessageDigest::sha256(), &private_key).unwrap();
|
let mut signer = Signer::new(MessageDigest::sha256(), &private_key)?;
|
||||||
signer.update(signing_string.as_bytes()).unwrap();
|
signer.update(signing_string.as_bytes())?;
|
||||||
|
|
||||||
Ok(base64::encode(signer.sign_to_vec()?)) as Result<_, LemmyError>
|
Ok(base64::encode(signer.sign_to_vec()?)) as Result<_, LemmyError>
|
||||||
},
|
},
|
||||||
|
@ -49,6 +50,7 @@ pub async fn sign(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify(request: &HttpRequest, actor: &dyn ActorType) -> Result<(), LemmyError> {
|
pub fn verify(request: &HttpRequest, actor: &dyn ActorType) -> Result<(), LemmyError> {
|
||||||
|
let public_key = actor.public_key().context(location_info!())?;
|
||||||
let verified = HTTP_SIG_CONFIG
|
let verified = HTTP_SIG_CONFIG
|
||||||
.begin_verify(
|
.begin_verify(
|
||||||
request.method(),
|
request.method(),
|
||||||
|
@ -58,12 +60,11 @@ pub fn verify(request: &HttpRequest, actor: &dyn ActorType) -> Result<(), LemmyE
|
||||||
.verify(|signature, signing_string| -> Result<bool, LemmyError> {
|
.verify(|signature, signing_string| -> Result<bool, LemmyError> {
|
||||||
debug!(
|
debug!(
|
||||||
"Verifying with key {}, message {}",
|
"Verifying with key {}, message {}",
|
||||||
&actor.public_key(),
|
&public_key, &signing_string
|
||||||
&signing_string
|
|
||||||
);
|
);
|
||||||
let public_key = PKey::public_key_from_pem(actor.public_key().as_bytes())?;
|
let public_key = PKey::public_key_from_pem(public_key.as_bytes())?;
|
||||||
let mut verifier = Verifier::new(MessageDigest::sha256(), &public_key).unwrap();
|
let mut verifier = Verifier::new(MessageDigest::sha256(), &public_key)?;
|
||||||
verifier.update(&signing_string.as_bytes()).unwrap();
|
verifier.update(&signing_string.as_bytes())?;
|
||||||
Ok(verifier.verify(&base64::decode(signature)?)?)
|
Ok(verifier.verify(&base64::decode(signature)?)?)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use activitystreams::{base::BaseExt, collection::OrderedCollection, object::Note, prelude::*};
|
use activitystreams::{base::BaseExt, collection::OrderedCollection, object::Note, prelude::*};
|
||||||
use actix_web::client::Client;
|
use actix_web::client::Client;
|
||||||
use anyhow::anyhow;
|
use anyhow::{anyhow, Context};
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use diesel::{result::Error::NotFound, PgConnection};
|
use diesel::{result::Error::NotFound, PgConnection};
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
|
@ -34,7 +34,7 @@ use lemmy_db::{
|
||||||
Joinable,
|
Joinable,
|
||||||
SearchType,
|
SearchType,
|
||||||
};
|
};
|
||||||
use lemmy_utils::get_apub_protocol_string;
|
use lemmy_utils::{get_apub_protocol_string, location_info};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{fmt::Debug, time::Duration};
|
use std::{fmt::Debug, time::Duration};
|
||||||
|
@ -144,10 +144,10 @@ pub async fn search_by_apub_id(
|
||||||
users: vec![],
|
users: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let domain = query_url.domain().unwrap();
|
let domain = query_url.domain().context("url has no domain")?;
|
||||||
let response = match fetch_remote_object::<SearchAcceptedObjects>(client, &query_url).await? {
|
let response = match fetch_remote_object::<SearchAcceptedObjects>(client, &query_url).await? {
|
||||||
SearchAcceptedObjects::Person(p) => {
|
SearchAcceptedObjects::Person(p) => {
|
||||||
let user_uri = p.inner.id(domain)?.unwrap();
|
let user_uri = p.inner.id(domain)?.context("person has no id")?;
|
||||||
|
|
||||||
let user = get_or_fetch_and_upsert_user(&user_uri, client, pool).await?;
|
let user = get_or_fetch_and_upsert_user(&user_uri, client, pool).await?;
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ pub async fn search_by_apub_id(
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
SearchAcceptedObjects::Group(g) => {
|
SearchAcceptedObjects::Group(g) => {
|
||||||
let community_uri = g.inner.id(domain)?.unwrap();
|
let community_uri = g.inner.id(domain)?.context("group has no id")?;
|
||||||
|
|
||||||
let community = get_or_fetch_and_upsert_community(community_uri, client, pool).await?;
|
let community = get_or_fetch_and_upsert_community(community_uri, client, pool).await?;
|
||||||
|
|
||||||
|
@ -181,10 +181,19 @@ pub async fn search_by_apub_id(
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
SearchAcceptedObjects::Comment(c) => {
|
SearchAcceptedObjects::Comment(c) => {
|
||||||
let post_url = c.in_reply_to().as_ref().unwrap().as_many().unwrap();
|
let post_url = c
|
||||||
|
.in_reply_to()
|
||||||
|
.as_ref()
|
||||||
|
.context(location_info!())?
|
||||||
|
.as_many()
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
// TODO: also fetch parent comments if any
|
// TODO: also fetch parent comments if any
|
||||||
let x = post_url.first().unwrap().as_xsd_any_uri().unwrap();
|
let x = post_url
|
||||||
|
.first()
|
||||||
|
.context(location_info!())?
|
||||||
|
.as_xsd_any_uri()
|
||||||
|
.context(location_info!())?;
|
||||||
let post = fetch_remote_object(client, x).await?;
|
let post = fetch_remote_object(client, x).await?;
|
||||||
let post_form = PostForm::from_apub(&post, client, pool, Some(query_url.clone())).await?;
|
let post_form = PostForm::from_apub(&post, client, pool, Some(query_url.clone())).await?;
|
||||||
let comment_form = CommentForm::from_apub(&c, client, pool, Some(query_url)).await?;
|
let comment_form = CommentForm::from_apub(&c, client, pool, Some(query_url)).await?;
|
||||||
|
@ -312,13 +321,13 @@ async fn fetch_remote_community(
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
// Also add the community moderators too
|
// Also add the community moderators too
|
||||||
let attributed_to = group.inner.attributed_to().unwrap();
|
let attributed_to = group.inner.attributed_to().context(location_info!())?;
|
||||||
let creator_and_moderator_uris: Vec<&Url> = attributed_to
|
let creator_and_moderator_uris: Vec<&Url> = attributed_to
|
||||||
.as_many()
|
.as_many()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.iter()
|
.iter()
|
||||||
.map(|a| a.as_xsd_any_uri().unwrap())
|
.map(|a| a.as_xsd_any_uri().context(""))
|
||||||
.collect();
|
.collect::<Result<Vec<&Url>, anyhow::Error>>()?;
|
||||||
|
|
||||||
let mut creator_and_moderators = Vec::new();
|
let mut creator_and_moderators = Vec::new();
|
||||||
|
|
||||||
|
@ -348,9 +357,9 @@ async fn fetch_remote_community(
|
||||||
// fetch outbox (maybe make this conditional)
|
// fetch outbox (maybe make this conditional)
|
||||||
let outbox =
|
let outbox =
|
||||||
fetch_remote_object::<OrderedCollection>(client, &community.get_outbox_url()?).await?;
|
fetch_remote_object::<OrderedCollection>(client, &community.get_outbox_url()?).await?;
|
||||||
let outbox_items = outbox.items().unwrap().clone();
|
let outbox_items = outbox.items().context(location_info!())?.clone();
|
||||||
for o in outbox_items.many().unwrap() {
|
for o in outbox_items.many().context(location_info!())? {
|
||||||
let page = PageExt::from_any_base(o)?.unwrap();
|
let page = PageExt::from_any_base(o)?.context(location_info!())?;
|
||||||
let post = PostForm::from_apub(&page, client, pool, None).await?;
|
let post = PostForm::from_apub(&page, client, pool, None).await?;
|
||||||
let post_ap_id = post.ap_id.clone();
|
let post_ap_id = post.ap_id.clone();
|
||||||
// Check whether the post already exists in the local db
|
// Check whether the post already exists in the local db
|
||||||
|
@ -452,7 +461,7 @@ pub async fn get_or_fetch_and_insert_comment(
|
||||||
|
|
||||||
// Ok(
|
// Ok(
|
||||||
// items
|
// items
|
||||||
// .unwrap()
|
// .context(location_info!())?
|
||||||
// .map(|obox: &BaseBox| -> Result<PostForm, LemmyError> {
|
// .map(|obox: &BaseBox| -> Result<PostForm, LemmyError> {
|
||||||
// let page = obox.clone().to_concrete::<Page>()?;
|
// let page = obox.clone().to_concrete::<Page>()?;
|
||||||
// PostForm::from_page(&page, conn)
|
// PostForm::from_page(&page, conn)
|
||||||
|
|
|
@ -21,6 +21,8 @@ use activitystreams::{
|
||||||
prelude::ExtendsExt,
|
prelude::ExtendsExt,
|
||||||
};
|
};
|
||||||
use actix_web::{client::Client, HttpResponse};
|
use actix_web::{client::Client, HttpResponse};
|
||||||
|
use anyhow::Context;
|
||||||
|
use lemmy_utils::location_info;
|
||||||
|
|
||||||
pub async fn receive_announce(
|
pub async fn receive_announce(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
||||||
|
@ -28,15 +30,15 @@ pub async fn receive_announce(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let announce = Announce::from_any_base(activity)?.unwrap();
|
let announce = Announce::from_any_base(activity)?.context(location_info!())?;
|
||||||
|
|
||||||
// ensure that announce and community come from the same instance
|
// ensure that announce and community come from the same instance
|
||||||
let community = get_community_id_from_activity(&announce)?;
|
let community = get_community_id_from_activity(&announce)?;
|
||||||
announce.id(community.domain().unwrap())?;
|
announce.id(community.domain().context(location_info!())?)?;
|
||||||
|
|
||||||
let kind = announce.object().as_single_kind_str();
|
let kind = announce.object().as_single_kind_str();
|
||||||
let object = announce.object();
|
let object = announce.object();
|
||||||
let object2 = object.clone().one().unwrap();
|
let object2 = object.clone().one().context(location_info!())?;
|
||||||
match kind {
|
match kind {
|
||||||
Some("Create") => receive_create(object2, client, pool, chat_server).await,
|
Some("Create") => receive_create(object2, client, pool, chat_server).await,
|
||||||
Some("Update") => receive_update(object2, client, pool, chat_server).await,
|
Some("Update") => receive_update(object2, client, pool, chat_server).await,
|
||||||
|
|
|
@ -24,6 +24,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use activitystreams::{activity::Create, base::AnyBase, object::Note, prelude::*};
|
use activitystreams::{activity::Create, base::AnyBase, object::Note, prelude::*};
|
||||||
use actix_web::{client::Client, HttpResponse};
|
use actix_web::{client::Client, HttpResponse};
|
||||||
|
use anyhow::Context;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::{Comment, CommentForm},
|
comment::{Comment, CommentForm},
|
||||||
comment_view::CommentView,
|
comment_view::CommentView,
|
||||||
|
@ -31,7 +32,7 @@ use lemmy_db::{
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
Crud,
|
Crud,
|
||||||
};
|
};
|
||||||
use lemmy_utils::scrape_text_for_mentions;
|
use lemmy_utils::{location_info, scrape_text_for_mentions};
|
||||||
|
|
||||||
pub async fn receive_create(
|
pub async fn receive_create(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
||||||
|
@ -39,11 +40,11 @@ pub async fn receive_create(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let create = Create::from_any_base(activity)?.unwrap();
|
let create = Create::from_any_base(activity)?.context(location_info!())?;
|
||||||
|
|
||||||
// ensure that create and actor come from the same instance
|
// ensure that create and actor come from the same instance
|
||||||
let user = get_user_from_activity(&create, client, pool).await?;
|
let user = get_user_from_activity(&create, client, pool).await?;
|
||||||
create.id(user.actor_id()?.domain().unwrap())?;
|
create.id(user.actor_id()?.domain().context(location_info!())?)?;
|
||||||
|
|
||||||
match create.object().as_single_kind_str() {
|
match create.object().as_single_kind_str() {
|
||||||
Some("Page") => receive_create_post(create, client, pool, chat_server).await,
|
Some("Page") => receive_create_post(create, client, pool, chat_server).await,
|
||||||
|
@ -59,7 +60,8 @@ async fn receive_create_post(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let user = get_user_from_activity(&create, client, pool).await?;
|
let user = get_user_from_activity(&create, client, pool).await?;
|
||||||
let page = PageExt::from_any_base(create.object().to_owned().one().unwrap())?.unwrap();
|
let page = PageExt::from_any_base(create.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let post = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?)).await?;
|
let post = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?)).await?;
|
||||||
|
|
||||||
|
@ -91,7 +93,8 @@ async fn receive_create_comment(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let user = get_user_from_activity(&create, client, pool).await?;
|
let user = get_user_from_activity(&create, client, pool).await?;
|
||||||
let note = Note::from_any_base(create.object().to_owned().one().unwrap())?.unwrap();
|
let note = Note::from_any_base(create.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let comment = CommentForm::from_apub(¬e, client, pool, Some(user.actor_id()?)).await?;
|
let comment = CommentForm::from_apub(¬e, client, pool, Some(user.actor_id()?)).await?;
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use activitystreams::{activity::Delete, base::AnyBase, object::Note, prelude::*};
|
use activitystreams::{activity::Delete, base::AnyBase, object::Note, prelude::*};
|
||||||
use actix_web::{client::Client, HttpResponse};
|
use actix_web::{client::Client, HttpResponse};
|
||||||
|
use anyhow::Context;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::{Comment, CommentForm},
|
comment::{Comment, CommentForm},
|
||||||
comment_view::CommentView,
|
comment_view::CommentView,
|
||||||
|
@ -33,6 +34,7 @@ use lemmy_db::{
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
Crud,
|
Crud,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::location_info;
|
||||||
|
|
||||||
pub async fn receive_delete(
|
pub async fn receive_delete(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
||||||
|
@ -40,7 +42,7 @@ pub async fn receive_delete(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let delete = Delete::from_any_base(activity)?.unwrap();
|
let delete = Delete::from_any_base(activity)?.context(location_info!())?;
|
||||||
match delete.object().as_single_kind_str() {
|
match delete.object().as_single_kind_str() {
|
||||||
Some("Page") => receive_delete_post(delete, client, pool, chat_server).await,
|
Some("Page") => receive_delete_post(delete, client, pool, chat_server).await,
|
||||||
Some("Note") => receive_delete_comment(delete, client, pool, chat_server).await,
|
Some("Note") => receive_delete_comment(delete, client, pool, chat_server).await,
|
||||||
|
@ -56,7 +58,8 @@ async fn receive_delete_post(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let user = get_user_from_activity(&delete, client, pool).await?;
|
let user = get_user_from_activity(&delete, client, pool).await?;
|
||||||
let page = PageExt::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap();
|
let page = PageExt::from_any_base(delete.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let post_ap_id = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?))
|
let post_ap_id = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?))
|
||||||
.await?
|
.await?
|
||||||
|
@ -110,7 +113,8 @@ async fn receive_delete_comment(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let user = get_user_from_activity(&delete, client, pool).await?;
|
let user = get_user_from_activity(&delete, client, pool).await?;
|
||||||
let note = Note::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap();
|
let note = Note::from_any_base(delete.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let comment_ap_id = CommentForm::from_apub(¬e, client, pool, Some(user.actor_id()?))
|
let comment_ap_id = CommentForm::from_apub(¬e, client, pool, Some(user.actor_id()?))
|
||||||
.await?
|
.await?
|
||||||
|
@ -166,7 +170,8 @@ async fn receive_delete_community(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let group = GroupExt::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap();
|
let group = GroupExt::from_any_base(delete.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
let user = get_user_from_activity(&delete, client, pool).await?;
|
let user = get_user_from_activity(&delete, client, pool).await?;
|
||||||
|
|
||||||
let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(user.actor_id()?))
|
let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(user.actor_id()?))
|
||||||
|
|
|
@ -21,6 +21,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use activitystreams::{activity::Dislike, base::AnyBase, object::Note, prelude::*};
|
use activitystreams::{activity::Dislike, base::AnyBase, object::Note, prelude::*};
|
||||||
use actix_web::{client::Client, HttpResponse};
|
use actix_web::{client::Client, HttpResponse};
|
||||||
|
use anyhow::Context;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::{CommentForm, CommentLike, CommentLikeForm},
|
comment::{CommentForm, CommentLike, CommentLikeForm},
|
||||||
comment_view::CommentView,
|
comment_view::CommentView,
|
||||||
|
@ -28,6 +29,7 @@ use lemmy_db::{
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
Likeable,
|
Likeable,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::location_info;
|
||||||
|
|
||||||
pub async fn receive_dislike(
|
pub async fn receive_dislike(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
||||||
|
@ -35,7 +37,7 @@ pub async fn receive_dislike(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let dislike = Dislike::from_any_base(activity)?.unwrap();
|
let dislike = Dislike::from_any_base(activity)?.context(location_info!())?;
|
||||||
match dislike.object().as_single_kind_str() {
|
match dislike.object().as_single_kind_str() {
|
||||||
Some("Page") => receive_dislike_post(dislike, client, pool, chat_server).await,
|
Some("Page") => receive_dislike_post(dislike, client, pool, chat_server).await,
|
||||||
Some("Note") => receive_dislike_comment(dislike, client, pool, chat_server).await,
|
Some("Note") => receive_dislike_comment(dislike, client, pool, chat_server).await,
|
||||||
|
@ -50,7 +52,14 @@ async fn receive_dislike_post(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let user = get_user_from_activity(&dislike, client, pool).await?;
|
let user = get_user_from_activity(&dislike, client, pool).await?;
|
||||||
let page = PageExt::from_any_base(dislike.object().to_owned().one().unwrap())?.unwrap();
|
let page = PageExt::from_any_base(
|
||||||
|
dislike
|
||||||
|
.object()
|
||||||
|
.to_owned()
|
||||||
|
.one()
|
||||||
|
.context(location_info!())?,
|
||||||
|
)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let post = PostForm::from_apub(&page, client, pool, None).await?;
|
let post = PostForm::from_apub(&page, client, pool, None).await?;
|
||||||
|
|
||||||
|
@ -90,7 +99,14 @@ async fn receive_dislike_comment(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let note = Note::from_any_base(dislike.object().to_owned().one().unwrap())?.unwrap();
|
let note = Note::from_any_base(
|
||||||
|
dislike
|
||||||
|
.object()
|
||||||
|
.to_owned()
|
||||||
|
.one()
|
||||||
|
.context(location_info!())?,
|
||||||
|
)?
|
||||||
|
.context(location_info!())?;
|
||||||
let user = get_user_from_activity(&dislike, client, pool).await?;
|
let user = get_user_from_activity(&dislike, client, pool).await?;
|
||||||
|
|
||||||
let comment = CommentForm::from_apub(¬e, client, pool, None).await?;
|
let comment = CommentForm::from_apub(¬e, client, pool, None).await?;
|
||||||
|
|
|
@ -21,6 +21,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use activitystreams::{activity::Like, base::AnyBase, object::Note, prelude::*};
|
use activitystreams::{activity::Like, base::AnyBase, object::Note, prelude::*};
|
||||||
use actix_web::{client::Client, HttpResponse};
|
use actix_web::{client::Client, HttpResponse};
|
||||||
|
use anyhow::Context;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::{CommentForm, CommentLike, CommentLikeForm},
|
comment::{CommentForm, CommentLike, CommentLikeForm},
|
||||||
comment_view::CommentView,
|
comment_view::CommentView,
|
||||||
|
@ -28,6 +29,7 @@ use lemmy_db::{
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
Likeable,
|
Likeable,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::location_info;
|
||||||
|
|
||||||
pub async fn receive_like(
|
pub async fn receive_like(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
||||||
|
@ -35,7 +37,7 @@ pub async fn receive_like(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let like = Like::from_any_base(activity)?.unwrap();
|
let like = Like::from_any_base(activity)?.context(location_info!())?;
|
||||||
match like.object().as_single_kind_str() {
|
match like.object().as_single_kind_str() {
|
||||||
Some("Page") => receive_like_post(like, client, pool, chat_server).await,
|
Some("Page") => receive_like_post(like, client, pool, chat_server).await,
|
||||||
Some("Note") => receive_like_comment(like, client, pool, chat_server).await,
|
Some("Note") => receive_like_comment(like, client, pool, chat_server).await,
|
||||||
|
@ -50,7 +52,8 @@ async fn receive_like_post(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let user = get_user_from_activity(&like, client, pool).await?;
|
let user = get_user_from_activity(&like, client, pool).await?;
|
||||||
let page = PageExt::from_any_base(like.object().to_owned().one().unwrap())?.unwrap();
|
let page = PageExt::from_any_base(like.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let post = PostForm::from_apub(&page, client, pool, None).await?;
|
let post = PostForm::from_apub(&page, client, pool, None).await?;
|
||||||
|
|
||||||
|
@ -90,7 +93,8 @@ async fn receive_like_comment(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let note = Note::from_any_base(like.object().to_owned().one().unwrap())?.unwrap();
|
let note = Note::from_any_base(like.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
let user = get_user_from_activity(&like, client, pool).await?;
|
let user = get_user_from_activity(&like, client, pool).await?;
|
||||||
|
|
||||||
let comment = CommentForm::from_apub(¬e, client, pool, None).await?;
|
let comment = CommentForm::from_apub(¬e, client, pool, None).await?;
|
||||||
|
|
|
@ -24,7 +24,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use activitystreams::{activity::Remove, base::AnyBase, object::Note, prelude::*};
|
use activitystreams::{activity::Remove, base::AnyBase, object::Note, prelude::*};
|
||||||
use actix_web::{client::Client, HttpResponse};
|
use actix_web::{client::Client, HttpResponse};
|
||||||
use anyhow::anyhow;
|
use anyhow::{anyhow, Context};
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::{Comment, CommentForm},
|
comment::{Comment, CommentForm},
|
||||||
comment_view::CommentView,
|
comment_view::CommentView,
|
||||||
|
@ -35,6 +35,7 @@ use lemmy_db::{
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
Crud,
|
Crud,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::location_info;
|
||||||
|
|
||||||
pub async fn receive_remove(
|
pub async fn receive_remove(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
||||||
|
@ -42,7 +43,7 @@ pub async fn receive_remove(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let remove = Remove::from_any_base(activity)?.unwrap();
|
let remove = Remove::from_any_base(activity)?.context(location_info!())?;
|
||||||
let actor = get_user_from_activity(&remove, client, pool).await?;
|
let actor = get_user_from_activity(&remove, client, pool).await?;
|
||||||
let community = get_community_id_from_activity(&remove)?;
|
let community = get_community_id_from_activity(&remove)?;
|
||||||
if actor.actor_id()?.domain() != community.domain() {
|
if actor.actor_id()?.domain() != community.domain() {
|
||||||
|
@ -64,7 +65,8 @@ async fn receive_remove_post(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let mod_ = get_user_from_activity(&remove, client, pool).await?;
|
let mod_ = get_user_from_activity(&remove, client, pool).await?;
|
||||||
let page = PageExt::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap();
|
let page = PageExt::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let post_ap_id = PostForm::from_apub(&page, client, pool, None)
|
let post_ap_id = PostForm::from_apub(&page, client, pool, None)
|
||||||
.await?
|
.await?
|
||||||
|
@ -118,7 +120,8 @@ async fn receive_remove_comment(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let mod_ = get_user_from_activity(&remove, client, pool).await?;
|
let mod_ = get_user_from_activity(&remove, client, pool).await?;
|
||||||
let note = Note::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap();
|
let note = Note::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let comment_ap_id = CommentForm::from_apub(¬e, client, pool, None)
|
let comment_ap_id = CommentForm::from_apub(¬e, client, pool, None)
|
||||||
.await?
|
.await?
|
||||||
|
@ -175,7 +178,8 @@ async fn receive_remove_community(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let mod_ = get_user_from_activity(&remove, client, pool).await?;
|
let mod_ = get_user_from_activity(&remove, client, pool).await?;
|
||||||
let group = GroupExt::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap();
|
let group = GroupExt::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(mod_.actor_id()?))
|
let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(mod_.actor_id()?))
|
||||||
.await?
|
.await?
|
||||||
|
|
|
@ -28,7 +28,7 @@ use activitystreams::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use actix_web::{client::Client, HttpResponse};
|
use actix_web::{client::Client, HttpResponse};
|
||||||
use anyhow::anyhow;
|
use anyhow::{anyhow, Context};
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::{Comment, CommentForm, CommentLike, CommentLikeForm},
|
comment::{Comment, CommentForm, CommentLike, CommentLikeForm},
|
||||||
comment_view::CommentView,
|
comment_view::CommentView,
|
||||||
|
@ -40,6 +40,7 @@ use lemmy_db::{
|
||||||
Crud,
|
Crud,
|
||||||
Likeable,
|
Likeable,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::location_info;
|
||||||
|
|
||||||
pub async fn receive_undo(
|
pub async fn receive_undo(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
||||||
|
@ -47,7 +48,7 @@ pub async fn receive_undo(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let undo = Undo::from_any_base(activity)?.unwrap();
|
let undo = Undo::from_any_base(activity)?.context(location_info!())?;
|
||||||
match undo.object().as_single_kind_str() {
|
match undo.object().as_single_kind_str() {
|
||||||
Some("Delete") => receive_undo_delete(undo, client, pool, chat_server).await,
|
Some("Delete") => receive_undo_delete(undo, client, pool, chat_server).await,
|
||||||
Some("Remove") => receive_undo_remove(undo, client, pool, chat_server).await,
|
Some("Remove") => receive_undo_remove(undo, client, pool, chat_server).await,
|
||||||
|
@ -62,10 +63,14 @@ where
|
||||||
T: AsBase<A> + ActorAndObjectRef,
|
T: AsBase<A> + ActorAndObjectRef,
|
||||||
{
|
{
|
||||||
let outer_actor = outer_activity.actor()?;
|
let outer_actor = outer_activity.actor()?;
|
||||||
let outer_actor_uri = outer_actor.as_single_xsd_any_uri().unwrap();
|
let outer_actor_uri = outer_actor
|
||||||
|
.as_single_xsd_any_uri()
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let inner_actor = inner_activity.actor()?;
|
let inner_actor = inner_activity.actor()?;
|
||||||
let inner_actor_uri = inner_actor.as_single_xsd_any_uri().unwrap();
|
let inner_actor_uri = inner_actor
|
||||||
|
.as_single_xsd_any_uri()
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
if outer_actor_uri.domain() != inner_actor_uri.domain() {
|
if outer_actor_uri.domain() != inner_actor_uri.domain() {
|
||||||
Err(anyhow!("Cant undo activities from a different instance").into())
|
Err(anyhow!("Cant undo activities from a different instance").into())
|
||||||
|
@ -80,9 +85,13 @@ async fn receive_undo_delete(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let delete = Delete::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap();
|
let delete = Delete::from_any_base(undo.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
check_is_undo_valid(&undo, &delete)?;
|
check_is_undo_valid(&undo, &delete)?;
|
||||||
let type_ = delete.object().as_single_kind_str().unwrap();
|
let type_ = delete
|
||||||
|
.object()
|
||||||
|
.as_single_kind_str()
|
||||||
|
.context(location_info!())?;
|
||||||
match type_ {
|
match type_ {
|
||||||
"Note" => receive_undo_delete_comment(undo, &delete, client, pool, chat_server).await,
|
"Note" => receive_undo_delete_comment(undo, &delete, client, pool, chat_server).await,
|
||||||
"Page" => receive_undo_delete_post(undo, &delete, client, pool, chat_server).await,
|
"Page" => receive_undo_delete_post(undo, &delete, client, pool, chat_server).await,
|
||||||
|
@ -97,10 +106,14 @@ async fn receive_undo_remove(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let remove = Remove::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap();
|
let remove = Remove::from_any_base(undo.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
check_is_undo_valid(&undo, &remove)?;
|
check_is_undo_valid(&undo, &remove)?;
|
||||||
|
|
||||||
let type_ = remove.object().as_single_kind_str().unwrap();
|
let type_ = remove
|
||||||
|
.object()
|
||||||
|
.as_single_kind_str()
|
||||||
|
.context(location_info!())?;
|
||||||
match type_ {
|
match type_ {
|
||||||
"Note" => receive_undo_remove_comment(undo, &remove, client, pool, chat_server).await,
|
"Note" => receive_undo_remove_comment(undo, &remove, client, pool, chat_server).await,
|
||||||
"Page" => receive_undo_remove_post(undo, &remove, client, pool, chat_server).await,
|
"Page" => receive_undo_remove_post(undo, &remove, client, pool, chat_server).await,
|
||||||
|
@ -115,10 +128,14 @@ async fn receive_undo_like(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let like = Like::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap();
|
let like = Like::from_any_base(undo.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
check_is_undo_valid(&undo, &like)?;
|
check_is_undo_valid(&undo, &like)?;
|
||||||
|
|
||||||
let type_ = like.object().as_single_kind_str().unwrap();
|
let type_ = like
|
||||||
|
.object()
|
||||||
|
.as_single_kind_str()
|
||||||
|
.context(location_info!())?;
|
||||||
match type_ {
|
match type_ {
|
||||||
"Note" => receive_undo_like_comment(undo, &like, client, pool, chat_server).await,
|
"Note" => receive_undo_like_comment(undo, &like, client, pool, chat_server).await,
|
||||||
"Page" => receive_undo_like_post(undo, &like, client, pool, chat_server).await,
|
"Page" => receive_undo_like_post(undo, &like, client, pool, chat_server).await,
|
||||||
|
@ -132,12 +149,16 @@ async fn receive_undo_dislike(
|
||||||
_pool: &DbPool,
|
_pool: &DbPool,
|
||||||
_chat_server: ChatServerParam,
|
_chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let dislike = Dislike::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap();
|
let dislike = Dislike::from_any_base(undo.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
check_is_undo_valid(&undo, &dislike)?;
|
check_is_undo_valid(&undo, &dislike)?;
|
||||||
|
|
||||||
// TODO: need to implement Undo<Dislike>
|
// TODO: need to implement Undo<Dislike>
|
||||||
|
|
||||||
let type_ = dislike.object().as_single_kind_str().unwrap();
|
let type_ = dislike
|
||||||
|
.object()
|
||||||
|
.as_single_kind_str()
|
||||||
|
.context(location_info!())?;
|
||||||
Err(anyhow!("Undo Delete type {} not supported", type_).into())
|
Err(anyhow!("Undo Delete type {} not supported", type_).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +170,8 @@ async fn receive_undo_delete_comment(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let user = get_user_from_activity(delete, client, pool).await?;
|
let user = get_user_from_activity(delete, client, pool).await?;
|
||||||
let note = Note::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap();
|
let note = Note::from_any_base(delete.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let comment_ap_id = CommentForm::from_apub(¬e, client, pool, Some(user.actor_id()?))
|
let comment_ap_id = CommentForm::from_apub(¬e, client, pool, Some(user.actor_id()?))
|
||||||
.await?
|
.await?
|
||||||
|
@ -207,7 +229,8 @@ async fn receive_undo_remove_comment(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let mod_ = get_user_from_activity(remove, client, pool).await?;
|
let mod_ = get_user_from_activity(remove, client, pool).await?;
|
||||||
let note = Note::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap();
|
let note = Note::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let comment_ap_id = CommentForm::from_apub(¬e, client, pool, None)
|
let comment_ap_id = CommentForm::from_apub(¬e, client, pool, None)
|
||||||
.await?
|
.await?
|
||||||
|
@ -265,7 +288,8 @@ async fn receive_undo_delete_post(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let user = get_user_from_activity(delete, client, pool).await?;
|
let user = get_user_from_activity(delete, client, pool).await?;
|
||||||
let page = PageExt::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap();
|
let page = PageExt::from_any_base(delete.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let post_ap_id = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?))
|
let post_ap_id = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?))
|
||||||
.await?
|
.await?
|
||||||
|
@ -320,7 +344,8 @@ async fn receive_undo_remove_post(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let mod_ = get_user_from_activity(remove, client, pool).await?;
|
let mod_ = get_user_from_activity(remove, client, pool).await?;
|
||||||
let page = PageExt::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap();
|
let page = PageExt::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let post_ap_id = PostForm::from_apub(&page, client, pool, None)
|
let post_ap_id = PostForm::from_apub(&page, client, pool, None)
|
||||||
.await?
|
.await?
|
||||||
|
@ -375,7 +400,8 @@ async fn receive_undo_delete_community(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let user = get_user_from_activity(delete, client, pool).await?;
|
let user = get_user_from_activity(delete, client, pool).await?;
|
||||||
let group = GroupExt::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap();
|
let group = GroupExt::from_any_base(delete.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(user.actor_id()?))
|
let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(user.actor_id()?))
|
||||||
.await?
|
.await?
|
||||||
|
@ -441,7 +467,8 @@ async fn receive_undo_remove_community(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let mod_ = get_user_from_activity(remove, client, pool).await?;
|
let mod_ = get_user_from_activity(remove, client, pool).await?;
|
||||||
let group = GroupExt::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap();
|
let group = GroupExt::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(mod_.actor_id()?))
|
let community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(mod_.actor_id()?))
|
||||||
.await?
|
.await?
|
||||||
|
@ -507,7 +534,8 @@ async fn receive_undo_like_comment(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let user = get_user_from_activity(like, client, pool).await?;
|
let user = get_user_from_activity(like, client, pool).await?;
|
||||||
let note = Note::from_any_base(like.object().to_owned().one().unwrap())?.unwrap();
|
let note = Note::from_any_base(like.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let comment = CommentForm::from_apub(¬e, client, pool, None).await?;
|
let comment = CommentForm::from_apub(¬e, client, pool, None).await?;
|
||||||
|
|
||||||
|
@ -553,7 +581,8 @@ async fn receive_undo_like_post(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let user = get_user_from_activity(like, client, pool).await?;
|
let user = get_user_from_activity(like, client, pool).await?;
|
||||||
let page = PageExt::from_any_base(like.object().to_owned().one().unwrap())?.unwrap();
|
let page = PageExt::from_any_base(like.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let post = PostForm::from_apub(&page, client, pool, None).await?;
|
let post = PostForm::from_apub(&page, client, pool, None).await?;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use activitystreams::{activity::Update, base::AnyBase, object::Note, prelude::*};
|
use activitystreams::{activity::Update, base::AnyBase, object::Note, prelude::*};
|
||||||
use actix_web::{client::Client, HttpResponse};
|
use actix_web::{client::Client, HttpResponse};
|
||||||
|
use anyhow::Context;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::{Comment, CommentForm},
|
comment::{Comment, CommentForm},
|
||||||
comment_view::CommentView,
|
comment_view::CommentView,
|
||||||
|
@ -32,7 +33,7 @@ use lemmy_db::{
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
Crud,
|
Crud,
|
||||||
};
|
};
|
||||||
use lemmy_utils::scrape_text_for_mentions;
|
use lemmy_utils::{location_info, scrape_text_for_mentions};
|
||||||
|
|
||||||
pub async fn receive_update(
|
pub async fn receive_update(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
||||||
|
@ -40,11 +41,11 @@ pub async fn receive_update(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let update = Update::from_any_base(activity)?.unwrap();
|
let update = Update::from_any_base(activity)?.context(location_info!())?;
|
||||||
|
|
||||||
// ensure that update and actor come from the same instance
|
// ensure that update and actor come from the same instance
|
||||||
let user = get_user_from_activity(&update, client, pool).await?;
|
let user = get_user_from_activity(&update, client, pool).await?;
|
||||||
update.id(user.actor_id()?.domain().unwrap())?;
|
update.id(user.actor_id()?.domain().context(location_info!())?)?;
|
||||||
|
|
||||||
match update.object().as_single_kind_str() {
|
match update.object().as_single_kind_str() {
|
||||||
Some("Page") => receive_update_post(update, client, pool, chat_server).await,
|
Some("Page") => receive_update_post(update, client, pool, chat_server).await,
|
||||||
|
@ -60,7 +61,8 @@ async fn receive_update_post(
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let user = get_user_from_activity(&update, client, pool).await?;
|
let user = get_user_from_activity(&update, client, pool).await?;
|
||||||
let page = PageExt::from_any_base(update.object().to_owned().one().unwrap())?.unwrap();
|
let page = PageExt::from_any_base(update.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let post = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?)).await?;
|
let post = PostForm::from_apub(&page, client, pool, Some(user.actor_id()?)).await?;
|
||||||
|
|
||||||
|
@ -97,7 +99,8 @@ async fn receive_update_comment(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let note = Note::from_any_base(update.object().to_owned().one().unwrap())?.unwrap();
|
let note = Note::from_any_base(update.object().to_owned().one().context(location_info!())?)?
|
||||||
|
.context(location_info!())?;
|
||||||
let user = get_user_from_activity(&update, client, pool).await?;
|
let user = get_user_from_activity(&update, client, pool).await?;
|
||||||
|
|
||||||
let comment = CommentForm::from_apub(¬e, client, pool, Some(user.actor_id()?)).await?;
|
let comment = CommentForm::from_apub(¬e, client, pool, Some(user.actor_id()?)).await?;
|
||||||
|
|
|
@ -16,12 +16,13 @@ use activitystreams::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use actix_web::{client::Client, web, HttpRequest, HttpResponse};
|
use actix_web::{client::Client, web, HttpRequest, HttpResponse};
|
||||||
use anyhow::anyhow;
|
use anyhow::{anyhow, Context};
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
community::{Community, CommunityFollower, CommunityFollowerForm},
|
community::{Community, CommunityFollower, CommunityFollowerForm},
|
||||||
user::User_,
|
user::User_,
|
||||||
Followable,
|
Followable,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::location_info;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -62,7 +63,10 @@ pub async fn community_inbox(
|
||||||
"Community {} received activity {:?}",
|
"Community {} received activity {:?}",
|
||||||
&community.name, &activity
|
&community.name, &activity
|
||||||
);
|
);
|
||||||
let user_uri = activity.actor()?.as_single_xsd_any_uri().unwrap();
|
let user_uri = activity
|
||||||
|
.actor()?
|
||||||
|
.as_single_xsd_any_uri()
|
||||||
|
.context(location_info!())?;
|
||||||
check_is_apub_id_valid(user_uri)?;
|
check_is_apub_id_valid(user_uri)?;
|
||||||
|
|
||||||
let user = get_or_fetch_and_upsert_user(&user_uri, &client, &db).await?;
|
let user = get_or_fetch_and_upsert_user(&user_uri, &client, &db).await?;
|
||||||
|
@ -70,7 +74,7 @@ pub async fn community_inbox(
|
||||||
verify(&request, &user)?;
|
verify(&request, &user)?;
|
||||||
|
|
||||||
let any_base = activity.clone().into_any_base()?;
|
let any_base = activity.clone().into_any_base()?;
|
||||||
let kind = activity.kind().unwrap();
|
let kind = activity.kind().context(location_info!())?;
|
||||||
let user_id = user.id;
|
let user_id = user.id;
|
||||||
let res = match kind {
|
let res = match kind {
|
||||||
ValidTypes::Follow => handle_follow(any_base, user, community, &client, &db).await,
|
ValidTypes::Follow => handle_follow(any_base, user, community, &client, &db).await,
|
||||||
|
@ -90,7 +94,7 @@ async fn handle_follow(
|
||||||
client: &Client,
|
client: &Client,
|
||||||
db: &DbPoolParam,
|
db: &DbPoolParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let follow = Follow::from_any_base(activity)?.unwrap();
|
let follow = Follow::from_any_base(activity)?.context(location_info!())?;
|
||||||
let community_follower_form = CommunityFollowerForm {
|
let community_follower_form = CommunityFollowerForm {
|
||||||
community_id: community.id,
|
community_id: community.id,
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
|
@ -113,7 +117,7 @@ async fn handle_undo_follow(
|
||||||
community: Community,
|
community: Community,
|
||||||
db: &DbPoolParam,
|
db: &DbPoolParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let _undo = Undo::from_any_base(activity)?.unwrap();
|
let _undo = Undo::from_any_base(activity)?.context(location_info!())?;
|
||||||
|
|
||||||
let community_follower_form = CommunityFollowerForm {
|
let community_follower_form = CommunityFollowerForm {
|
||||||
community_id: community.id,
|
community_id: community.id,
|
||||||
|
|
|
@ -31,7 +31,9 @@ use activitystreams::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use actix_web::{client::Client, web, HttpRequest, HttpResponse};
|
use actix_web::{client::Client, web, HttpRequest, HttpResponse};
|
||||||
|
use anyhow::Context;
|
||||||
use lemmy_db::user::User_;
|
use lemmy_db::user::User_;
|
||||||
|
use lemmy_utils::location_info;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -67,7 +69,11 @@ pub async fn shared_inbox(
|
||||||
let json = serde_json::to_string(&activity)?;
|
let json = serde_json::to_string(&activity)?;
|
||||||
debug!("Shared inbox received activity: {}", json);
|
debug!("Shared inbox received activity: {}", json);
|
||||||
|
|
||||||
let sender = &activity.actor()?.to_owned().single_xsd_any_uri().unwrap();
|
let sender = &activity
|
||||||
|
.actor()?
|
||||||
|
.to_owned()
|
||||||
|
.single_xsd_any_uri()
|
||||||
|
.context(location_info!())?;
|
||||||
let community = get_community_id_from_activity(&activity)?;
|
let community = get_community_id_from_activity(&activity)?;
|
||||||
|
|
||||||
check_is_apub_id_valid(sender)?;
|
check_is_apub_id_valid(sender)?;
|
||||||
|
@ -77,7 +83,7 @@ pub async fn shared_inbox(
|
||||||
verify(&request, actor.as_ref())?;
|
verify(&request, actor.as_ref())?;
|
||||||
|
|
||||||
let any_base = activity.clone().into_any_base()?;
|
let any_base = activity.clone().into_any_base()?;
|
||||||
let kind = activity.kind().unwrap();
|
let kind = activity.kind().context(location_info!())?;
|
||||||
let res = match kind {
|
let res = match kind {
|
||||||
ValidTypes::Announce => receive_announce(any_base, &client, &pool, chat_server).await,
|
ValidTypes::Announce => receive_announce(any_base, &client, &pool, chat_server).await,
|
||||||
ValidTypes::Create => receive_create(any_base, &client, &pool, chat_server).await,
|
ValidTypes::Create => receive_create(any_base, &client, &pool, chat_server).await,
|
||||||
|
@ -112,7 +118,7 @@ where
|
||||||
T: AsBase<A> + ActorAndObjectRef,
|
T: AsBase<A> + ActorAndObjectRef,
|
||||||
{
|
{
|
||||||
let actor = activity.actor()?;
|
let actor = activity.actor()?;
|
||||||
let user_uri = actor.as_single_xsd_any_uri().unwrap();
|
let user_uri = actor.as_single_xsd_any_uri().context(location_info!())?;
|
||||||
get_or_fetch_and_upsert_user(&user_uri, client, pool).await
|
get_or_fetch_and_upsert_user(&user_uri, client, pool).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,9 +128,15 @@ pub(in crate::apub::inbox) fn get_community_id_from_activity<T, A>(
|
||||||
where
|
where
|
||||||
T: AsBase<A> + ActorAndObjectRef + AsObject<A>,
|
T: AsBase<A> + ActorAndObjectRef + AsObject<A>,
|
||||||
{
|
{
|
||||||
let cc = activity.cc().unwrap();
|
let cc = activity.cc().context(location_info!())?;
|
||||||
let cc = cc.as_many().unwrap();
|
let cc = cc.as_many().context(location_info!())?;
|
||||||
Ok(cc.first().unwrap().as_xsd_any_uri().unwrap().to_owned())
|
Ok(
|
||||||
|
cc.first()
|
||||||
|
.context(location_info!())?
|
||||||
|
.as_xsd_any_uri()
|
||||||
|
.context(location_info!())?
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::apub::inbox) async fn announce_if_community_is_local<T, Kind>(
|
pub(in crate::apub::inbox) async fn announce_if_community_is_local<T, Kind>(
|
||||||
|
@ -139,9 +151,13 @@ where
|
||||||
Kind: Serialize,
|
Kind: Serialize,
|
||||||
<T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
|
<T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let cc = activity.cc().unwrap();
|
let cc = activity.cc().context(location_info!())?;
|
||||||
let cc = cc.as_many().unwrap();
|
let cc = cc.as_many().context(location_info!())?;
|
||||||
let community_followers_uri = cc.first().unwrap().as_xsd_any_uri().unwrap();
|
let community_followers_uri = cc
|
||||||
|
.first()
|
||||||
|
.context(location_info!())?
|
||||||
|
.as_xsd_any_uri()
|
||||||
|
.context(location_info!())?;
|
||||||
// TODO: this is hacky but seems to be the only way to get the community ID
|
// TODO: this is hacky but seems to be the only way to get the community ID
|
||||||
let community_uri = community_followers_uri
|
let community_uri = community_followers_uri
|
||||||
.to_string()
|
.to_string()
|
||||||
|
|
|
@ -20,6 +20,7 @@ use activitystreams::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use actix_web::{client::Client, web, HttpRequest, HttpResponse};
|
use actix_web::{client::Client, web, HttpRequest, HttpResponse};
|
||||||
|
use anyhow::Context;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
community::{CommunityFollower, CommunityFollowerForm},
|
community::{CommunityFollower, CommunityFollowerForm},
|
||||||
naive_now,
|
naive_now,
|
||||||
|
@ -29,6 +30,7 @@ use lemmy_db::{
|
||||||
Crud,
|
Crud,
|
||||||
Followable,
|
Followable,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::location_info;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -58,7 +60,10 @@ pub async fn user_inbox(
|
||||||
let username = path.into_inner();
|
let username = path.into_inner();
|
||||||
debug!("User {} received activity: {:?}", &username, &activity);
|
debug!("User {} received activity: {:?}", &username, &activity);
|
||||||
|
|
||||||
let actor_uri = activity.actor()?.as_single_xsd_any_uri().unwrap();
|
let actor_uri = activity
|
||||||
|
.actor()?
|
||||||
|
.as_single_xsd_any_uri()
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
check_is_apub_id_valid(actor_uri)?;
|
check_is_apub_id_valid(actor_uri)?;
|
||||||
|
|
||||||
|
@ -66,7 +71,7 @@ pub async fn user_inbox(
|
||||||
verify(&request, actor.as_ref())?;
|
verify(&request, actor.as_ref())?;
|
||||||
|
|
||||||
let any_base = activity.clone().into_any_base()?;
|
let any_base = activity.clone().into_any_base()?;
|
||||||
let kind = activity.kind().unwrap();
|
let kind = activity.kind().context(location_info!())?;
|
||||||
let res = match kind {
|
let res = match kind {
|
||||||
ValidTypes::Accept => receive_accept(any_base, username, &client, &pool).await,
|
ValidTypes::Accept => receive_accept(any_base, username, &client, &pool).await,
|
||||||
ValidTypes::Create => {
|
ValidTypes::Create => {
|
||||||
|
@ -94,8 +99,12 @@ async fn receive_accept(
|
||||||
client: &Client,
|
client: &Client,
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let accept = Accept::from_any_base(activity)?.unwrap();
|
let accept = Accept::from_any_base(activity)?.context(location_info!())?;
|
||||||
let community_uri = accept.actor()?.to_owned().single_xsd_any_uri().unwrap();
|
let community_uri = accept
|
||||||
|
.actor()?
|
||||||
|
.to_owned()
|
||||||
|
.single_xsd_any_uri()
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let community = get_or_fetch_and_upsert_community(&community_uri, client, pool).await?;
|
let community = get_or_fetch_and_upsert_community(&community_uri, client, pool).await?;
|
||||||
|
|
||||||
|
@ -123,10 +132,17 @@ async fn receive_create_private_message(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let create = Create::from_any_base(activity)?.unwrap();
|
let create = Create::from_any_base(activity)?.context(location_info!())?;
|
||||||
let note = Note::from_any_base(create.object().as_one().unwrap().to_owned())?.unwrap();
|
let note = Note::from_any_base(
|
||||||
|
create
|
||||||
|
.object()
|
||||||
|
.as_one()
|
||||||
|
.context(location_info!())?
|
||||||
|
.to_owned(),
|
||||||
|
)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let domain = Some(create.id_unchecked().unwrap().to_owned());
|
let domain = Some(create.id_unchecked().context(location_info!())?.to_owned());
|
||||||
let private_message = PrivateMessageForm::from_apub(¬e, client, pool, domain).await?;
|
let private_message = PrivateMessageForm::from_apub(¬e, client, pool, domain).await?;
|
||||||
|
|
||||||
let inserted_private_message = blocking(pool, move |conn| {
|
let inserted_private_message = blocking(pool, move |conn| {
|
||||||
|
@ -159,10 +175,17 @@ async fn receive_update_private_message(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let update = Update::from_any_base(activity)?.unwrap();
|
let update = Update::from_any_base(activity)?.context(location_info!())?;
|
||||||
let note = Note::from_any_base(update.object().as_one().unwrap().to_owned())?.unwrap();
|
let note = Note::from_any_base(
|
||||||
|
update
|
||||||
|
.object()
|
||||||
|
.as_one()
|
||||||
|
.context(location_info!())?
|
||||||
|
.to_owned(),
|
||||||
|
)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let domain = Some(update.id_unchecked().unwrap().to_owned());
|
let domain = Some(update.id_unchecked().context(location_info!())?.to_owned());
|
||||||
let private_message_form = PrivateMessageForm::from_apub(¬e, client, pool, domain).await?;
|
let private_message_form = PrivateMessageForm::from_apub(¬e, client, pool, domain).await?;
|
||||||
|
|
||||||
let private_message_ap_id = private_message_form.ap_id.clone();
|
let private_message_ap_id = private_message_form.ap_id.clone();
|
||||||
|
@ -203,10 +226,17 @@ async fn receive_delete_private_message(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let delete = Delete::from_any_base(activity)?.unwrap();
|
let delete = Delete::from_any_base(activity)?.context(location_info!())?;
|
||||||
let note = Note::from_any_base(delete.object().as_one().unwrap().to_owned())?.unwrap();
|
let note = Note::from_any_base(
|
||||||
|
delete
|
||||||
|
.object()
|
||||||
|
.as_one()
|
||||||
|
.context(location_info!())?
|
||||||
|
.to_owned(),
|
||||||
|
)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let domain = Some(delete.id_unchecked().unwrap().to_owned());
|
let domain = Some(delete.id_unchecked().context(location_info!())?.to_owned());
|
||||||
let private_message_form = PrivateMessageForm::from_apub(¬e, client, pool, domain).await?;
|
let private_message_form = PrivateMessageForm::from_apub(¬e, client, pool, domain).await?;
|
||||||
|
|
||||||
let private_message_ap_id = private_message_form.ap_id;
|
let private_message_ap_id = private_message_form.ap_id;
|
||||||
|
@ -259,11 +289,19 @@ async fn receive_undo_delete_private_message(
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
chat_server: ChatServerParam,
|
chat_server: ChatServerParam,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let undo = Undo::from_any_base(activity)?.unwrap();
|
let undo = Undo::from_any_base(activity)?.context(location_info!())?;
|
||||||
let delete = Delete::from_any_base(undo.object().as_one().unwrap().to_owned())?.unwrap();
|
let delete = Delete::from_any_base(undo.object().as_one().context(location_info!())?.to_owned())?
|
||||||
let note = Note::from_any_base(delete.object().as_one().unwrap().to_owned())?.unwrap();
|
.context(location_info!())?;
|
||||||
|
let note = Note::from_any_base(
|
||||||
|
delete
|
||||||
|
.object()
|
||||||
|
.as_one()
|
||||||
|
.context(location_info!())?
|
||||||
|
.to_owned(),
|
||||||
|
)?
|
||||||
|
.context(location_info!())?;
|
||||||
|
|
||||||
let domain = Some(undo.id_unchecked().unwrap().to_owned());
|
let domain = Some(undo.id_unchecked().context(location_info!())?.to_owned());
|
||||||
let private_message = PrivateMessageForm::from_apub(¬e, client, pool, domain).await?;
|
let private_message = PrivateMessageForm::from_apub(¬e, client, pool, domain).await?;
|
||||||
|
|
||||||
let private_message_ap_id = private_message.ap_id.clone();
|
let private_message_ap_id = private_message.ap_id.clone();
|
||||||
|
|
|
@ -30,10 +30,16 @@ use activitystreams::{
|
||||||
};
|
};
|
||||||
use activitystreams_ext::{Ext1, Ext2};
|
use activitystreams_ext::{Ext1, Ext2};
|
||||||
use actix_web::{body::Body, client::Client, HttpResponse};
|
use actix_web::{body::Body, client::Client, HttpResponse};
|
||||||
use anyhow::anyhow;
|
use anyhow::{anyhow, Context};
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use lemmy_db::{activity::do_insert_activity, user::User_};
|
use lemmy_db::{activity::do_insert_activity, user::User_};
|
||||||
use lemmy_utils::{convert_datetime, get_apub_protocol_string, settings::Settings, MentionData};
|
use lemmy_utils::{
|
||||||
|
convert_datetime,
|
||||||
|
get_apub_protocol_string,
|
||||||
|
location_info,
|
||||||
|
settings::Settings,
|
||||||
|
MentionData,
|
||||||
|
};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use url::{ParseError, Url};
|
use url::{ParseError, Url};
|
||||||
|
@ -80,7 +86,12 @@ fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> {
|
||||||
// instance. replace is needed to remove the port in our federation test setup.
|
// instance. replace is needed to remove the port in our federation test setup.
|
||||||
let settings = Settings::get();
|
let settings = Settings::get();
|
||||||
let local_instance = settings.hostname.split(':').collect::<Vec<&str>>();
|
let local_instance = settings.hostname.split(':').collect::<Vec<&str>>();
|
||||||
allowed_instances.push(local_instance.first().unwrap().to_string());
|
allowed_instances.push(
|
||||||
|
local_instance
|
||||||
|
.first()
|
||||||
|
.context(location_info!())?
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
match apub_id.domain() {
|
match apub_id.domain() {
|
||||||
Some(d) => {
|
Some(d) => {
|
||||||
|
@ -197,10 +208,10 @@ where
|
||||||
T: Base + AsBase<Kind>,
|
T: Base + AsBase<Kind>,
|
||||||
{
|
{
|
||||||
let actor_id = if let Some(url) = expected_domain {
|
let actor_id = if let Some(url) = expected_domain {
|
||||||
let domain = url.domain().unwrap();
|
let domain = url.domain().context(location_info!())?;
|
||||||
apub.id(domain)?.unwrap()
|
apub.id(domain)?.context(location_info!())?
|
||||||
} else {
|
} else {
|
||||||
let actor_id = apub.id_unchecked().unwrap();
|
let actor_id = apub.id_unchecked().context(location_info!())?;
|
||||||
check_is_apub_id_valid(&actor_id)?;
|
check_is_apub_id_valid(&actor_id)?;
|
||||||
actor_id
|
actor_id
|
||||||
};
|
};
|
||||||
|
@ -229,25 +240,13 @@ pub trait ApubLikeableType {
|
||||||
) -> Result<(), LemmyError>;
|
) -> Result<(), LemmyError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_shared_inbox(actor_id: &Url) -> String {
|
|
||||||
format!(
|
|
||||||
"{}://{}{}/inbox",
|
|
||||||
&actor_id.scheme(),
|
|
||||||
&actor_id.host_str().unwrap(),
|
|
||||||
if let Some(port) = actor_id.port() {
|
|
||||||
format!(":{}", port)
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
pub trait ActorType {
|
pub trait ActorType {
|
||||||
fn actor_id_str(&self) -> String;
|
fn actor_id_str(&self) -> String;
|
||||||
|
|
||||||
fn public_key(&self) -> String;
|
// TODO: every actor should have a public key, so this shouldnt be an option (needs to be fixed in db)
|
||||||
fn private_key(&self) -> String;
|
fn public_key(&self) -> Option<String>;
|
||||||
|
fn private_key(&self) -> Option<String>;
|
||||||
|
|
||||||
/// numeric id in the database, used for insert_activity
|
/// numeric id in the database, used for insert_activity
|
||||||
fn user_id(&self) -> i32;
|
fn user_id(&self) -> i32;
|
||||||
|
@ -257,13 +256,13 @@ pub trait ActorType {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
async fn send_follow(
|
async fn send_follow(
|
||||||
&self,
|
&self,
|
||||||
follow_actor_id: &str,
|
follow_actor_id: &Url,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
) -> Result<(), LemmyError>;
|
) -> Result<(), LemmyError>;
|
||||||
async fn send_unfollow(
|
async fn send_unfollow(
|
||||||
&self,
|
&self,
|
||||||
follow_actor_id: &str,
|
follow_actor_id: &Url,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
) -> Result<(), LemmyError>;
|
) -> Result<(), LemmyError>;
|
||||||
|
@ -303,7 +302,7 @@ pub trait ActorType {
|
||||||
) -> Result<(), LemmyError>;
|
) -> Result<(), LemmyError>;
|
||||||
|
|
||||||
/// For a given community, returns the inboxes of all followers.
|
/// For a given community, returns the inboxes of all followers.
|
||||||
async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<String>, LemmyError>;
|
async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError>;
|
||||||
|
|
||||||
fn actor_id(&self) -> Result<Url, ParseError> {
|
fn actor_id(&self) -> Result<Url, ParseError> {
|
||||||
Url::parse(&self.actor_id_str())
|
Url::parse(&self.actor_id_str())
|
||||||
|
@ -314,9 +313,19 @@ pub trait ActorType {
|
||||||
Url::parse(&format!("{}/inbox", &self.actor_id_str()))
|
Url::parse(&format!("{}/inbox", &self.actor_id_str()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make this return `Result<Url, ParseError>
|
fn get_shared_inbox_url(&self) -> Result<Url, LemmyError> {
|
||||||
fn get_shared_inbox_url(&self) -> String {
|
let actor_id = self.actor_id()?;
|
||||||
get_shared_inbox(&self.actor_id().unwrap())
|
let url = format!(
|
||||||
|
"{}://{}{}/inbox",
|
||||||
|
&actor_id.scheme(),
|
||||||
|
&actor_id.host_str().context(location_info!())?,
|
||||||
|
if let Some(port) = actor_id.port() {
|
||||||
|
format!(":{}", port)
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
Ok(Url::parse(&url)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_outbox_url(&self) -> Result<Url, ParseError> {
|
fn get_outbox_url(&self) -> Result<Url, ParseError> {
|
||||||
|
@ -335,13 +344,15 @@ pub trait ActorType {
|
||||||
format!("{}/liked", &self.actor_id_str())
|
format!("{}/liked", &self.actor_id_str())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_public_key_ext(&self) -> PublicKeyExtension {
|
fn get_public_key_ext(&self) -> Result<PublicKeyExtension, LemmyError> {
|
||||||
|
Ok(
|
||||||
PublicKey {
|
PublicKey {
|
||||||
id: format!("{}#main-key", self.actor_id_str()),
|
id: format!("{}#main-key", self.actor_id_str()),
|
||||||
owner: self.actor_id_str(),
|
owner: self.actor_id_str(),
|
||||||
public_key_pem: self.public_key(),
|
public_key_pem: self.public_key().context(location_info!())?,
|
||||||
}
|
}
|
||||||
.to_ext()
|
.to_ext(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,19 +32,20 @@ use activitystreams::{
|
||||||
Update,
|
Update,
|
||||||
},
|
},
|
||||||
context,
|
context,
|
||||||
object::{kind::PageType, Image, Page, Tombstone},
|
object::{kind::PageType, Image, Object, Page, Tombstone},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
public,
|
public,
|
||||||
};
|
};
|
||||||
use activitystreams_ext::Ext1;
|
use activitystreams_ext::Ext1;
|
||||||
use actix_web::{body::Body, client::Client, web, HttpResponse};
|
use actix_web::{body::Body, client::Client, web, HttpResponse};
|
||||||
|
use anyhow::Context;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
community::Community,
|
community::Community,
|
||||||
post::{Post, PostForm},
|
post::{Post, PostForm},
|
||||||
user::User_,
|
user::User_,
|
||||||
Crud,
|
Crud,
|
||||||
};
|
};
|
||||||
use lemmy_utils::{convert_datetime, remove_slurs};
|
use lemmy_utils::{convert_datetime, location_info, remove_slurs};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -147,6 +148,50 @@ impl ToApub for Post {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct EmbedType {
|
||||||
|
title: Option<String>,
|
||||||
|
description: Option<String>,
|
||||||
|
html: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_embed_from_apub(
|
||||||
|
page: &Ext1<Object<PageType>, PageExtension>,
|
||||||
|
) -> Result<EmbedType, LemmyError> {
|
||||||
|
match page.inner.preview() {
|
||||||
|
Some(preview) => {
|
||||||
|
let preview_page = Page::from_any_base(preview.one().context(location_info!())?.to_owned())?
|
||||||
|
.context(location_info!())?;
|
||||||
|
let title = preview_page
|
||||||
|
.name()
|
||||||
|
.map(|n| n.one())
|
||||||
|
.flatten()
|
||||||
|
.map(|s| s.as_xsd_string())
|
||||||
|
.flatten()
|
||||||
|
.map(|s| s.to_string());
|
||||||
|
let description = preview_page
|
||||||
|
.summary()
|
||||||
|
.map(|s| s.as_single_xsd_string())
|
||||||
|
.flatten()
|
||||||
|
.map(|s| s.to_string());
|
||||||
|
let html = preview_page
|
||||||
|
.content()
|
||||||
|
.map(|c| c.as_single_xsd_string())
|
||||||
|
.flatten()
|
||||||
|
.map(|s| s.to_string());
|
||||||
|
Ok(EmbedType {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
html,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => Ok(EmbedType {
|
||||||
|
title: None,
|
||||||
|
description: None,
|
||||||
|
html: None,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl FromApub for PostForm {
|
impl FromApub for PostForm {
|
||||||
type ApubType = PageExt;
|
type ApubType = PageExt;
|
||||||
|
@ -163,9 +208,9 @@ impl FromApub for PostForm {
|
||||||
.inner
|
.inner
|
||||||
.attributed_to()
|
.attributed_to()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_single_xsd_any_uri()
|
.as_single_xsd_any_uri()
|
||||||
.unwrap();
|
.context(location_info!())?;
|
||||||
|
|
||||||
let creator = get_or_fetch_and_upsert_user(creator_actor_id, client, pool).await?;
|
let creator = get_or_fetch_and_upsert_user(creator_actor_id, client, pool).await?;
|
||||||
|
|
||||||
|
@ -173,57 +218,52 @@ impl FromApub for PostForm {
|
||||||
.inner
|
.inner
|
||||||
.to()
|
.to()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_single_xsd_any_uri()
|
.as_single_xsd_any_uri()
|
||||||
.unwrap();
|
.context(location_info!())?;
|
||||||
|
|
||||||
let community = get_or_fetch_and_upsert_community(community_actor_id, client, pool).await?;
|
let community = get_or_fetch_and_upsert_community(community_actor_id, client, pool).await?;
|
||||||
|
|
||||||
let thumbnail_url = match &page.inner.image() {
|
let thumbnail_url = match &page.inner.image() {
|
||||||
Some(any_image) => Image::from_any_base(any_image.to_owned().as_one().unwrap().to_owned())?
|
Some(any_image) => Image::from_any_base(
|
||||||
.unwrap()
|
any_image
|
||||||
|
.to_owned()
|
||||||
|
.as_one()
|
||||||
|
.context(location_info!())?
|
||||||
|
.to_owned(),
|
||||||
|
)?
|
||||||
|
.context(location_info!())?
|
||||||
.url()
|
.url()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_single_xsd_any_uri()
|
.as_single_xsd_any_uri()
|
||||||
.map(|u| u.to_string()),
|
.map(|u| u.to_string()),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (embed_title, embed_description, embed_html) = match page.inner.preview() {
|
let embed = extract_embed_from_apub(page)?;
|
||||||
Some(preview) => {
|
|
||||||
let preview_page = Page::from_any_base(preview.one().unwrap().to_owned())?.unwrap();
|
|
||||||
let name = preview_page
|
|
||||||
.name()
|
|
||||||
.map(|n| n.as_one().unwrap().as_xsd_string().unwrap().to_string());
|
|
||||||
let summary = preview_page
|
|
||||||
.summary()
|
|
||||||
.map(|s| s.as_single_xsd_string().unwrap().to_string());
|
|
||||||
let content = preview_page
|
|
||||||
.content()
|
|
||||||
.map(|c| c.as_single_xsd_string().unwrap().to_string());
|
|
||||||
(name, summary, content)
|
|
||||||
}
|
|
||||||
None => (None, None, None),
|
|
||||||
};
|
|
||||||
|
|
||||||
let name = page
|
let name = page
|
||||||
.inner
|
.inner
|
||||||
.summary()
|
.summary()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_single_xsd_string()
|
.as_single_xsd_string()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.to_string();
|
.to_string();
|
||||||
let url = page
|
let url = page
|
||||||
.inner
|
.inner
|
||||||
.url()
|
.url()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|u| u.as_single_xsd_string().unwrap().to_string());
|
.map(|u| u.as_single_xsd_string())
|
||||||
|
.flatten()
|
||||||
|
.map(|s| s.to_string());
|
||||||
let body = page
|
let body = page
|
||||||
.inner
|
.inner
|
||||||
.content()
|
.content()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|c| c.as_single_xsd_string().unwrap().to_string());
|
.map(|c| c.as_single_xsd_string())
|
||||||
|
.flatten()
|
||||||
|
.map(|s| s.to_string());
|
||||||
check_slurs(&name)?;
|
check_slurs(&name)?;
|
||||||
let body_slurs_removed = body.map(|b| remove_slurs(&b));
|
let body_slurs_removed = body.map(|b| remove_slurs(&b));
|
||||||
Ok(PostForm {
|
Ok(PostForm {
|
||||||
|
@ -247,9 +287,9 @@ impl FromApub for PostForm {
|
||||||
deleted: None,
|
deleted: None,
|
||||||
nsfw: ext.sensitive,
|
nsfw: ext.sensitive,
|
||||||
stickied: Some(ext.stickied),
|
stickied: Some(ext.stickied),
|
||||||
embed_title,
|
embed_title: embed.title,
|
||||||
embed_description,
|
embed_description: embed.description,
|
||||||
embed_html,
|
embed_html: embed.html,
|
||||||
thumbnail_url,
|
thumbnail_url,
|
||||||
ap_id: check_actor_domain(page, expected_domain)?,
|
ap_id: check_actor_domain(page, expected_domain)?,
|
||||||
local: false,
|
local: false,
|
||||||
|
@ -281,7 +321,7 @@ impl ApubObjectType for Post {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
creator,
|
creator,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
create.into_any_base()?,
|
create.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -312,7 +352,7 @@ impl ApubObjectType for Post {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
creator,
|
creator,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
update.into_any_base()?,
|
update.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -342,7 +382,7 @@ impl ApubObjectType for Post {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
creator,
|
creator,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
delete.into_any_base()?,
|
delete.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -380,7 +420,7 @@ impl ApubObjectType for Post {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
creator,
|
creator,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
undo.into_any_base()?,
|
undo.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -410,7 +450,7 @@ impl ApubObjectType for Post {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
mod_,
|
mod_,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
remove.into_any_base()?,
|
remove.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -448,7 +488,7 @@ impl ApubObjectType for Post {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
mod_,
|
mod_,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
undo.into_any_base()?,
|
undo.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -481,7 +521,7 @@ impl ApubLikeableType for Post {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
&creator,
|
&creator,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
like.into_any_base()?,
|
like.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -511,7 +551,7 @@ impl ApubLikeableType for Post {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
&creator,
|
&creator,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
dislike.into_any_base()?,
|
dislike.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
@ -549,7 +589,7 @@ impl ApubLikeableType for Post {
|
||||||
send_activity_to_community(
|
send_activity_to_community(
|
||||||
&creator,
|
&creator,
|
||||||
&community,
|
&community,
|
||||||
vec![community.get_shared_inbox_url()],
|
vec![community.get_shared_inbox_url()?],
|
||||||
undo.into_any_base()?,
|
undo.into_any_base()?,
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
create_tombstone,
|
create_tombstone,
|
||||||
fetcher::get_or_fetch_and_upsert_user,
|
fetcher::get_or_fetch_and_upsert_user,
|
||||||
insert_activity,
|
insert_activity,
|
||||||
|
ActorType,
|
||||||
ApubObjectType,
|
ApubObjectType,
|
||||||
FromApub,
|
FromApub,
|
||||||
ToApub,
|
ToApub,
|
||||||
|
@ -27,12 +28,13 @@ use activitystreams::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use actix_web::client::Client;
|
use actix_web::client::Client;
|
||||||
|
use anyhow::Context;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
private_message::{PrivateMessage, PrivateMessageForm},
|
private_message::{PrivateMessage, PrivateMessageForm},
|
||||||
user::User_,
|
user::User_,
|
||||||
Crud,
|
Crud,
|
||||||
};
|
};
|
||||||
use lemmy_utils::convert_datetime;
|
use lemmy_utils::{convert_datetime, location_info};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
|
@ -81,15 +83,20 @@ impl FromApub for PrivateMessageForm {
|
||||||
) -> Result<PrivateMessageForm, LemmyError> {
|
) -> Result<PrivateMessageForm, LemmyError> {
|
||||||
let creator_actor_id = note
|
let creator_actor_id = note
|
||||||
.attributed_to()
|
.attributed_to()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.clone()
|
.clone()
|
||||||
.single_xsd_any_uri()
|
.single_xsd_any_uri()
|
||||||
.unwrap();
|
.context(location_info!())?;
|
||||||
|
|
||||||
let creator = get_or_fetch_and_upsert_user(&creator_actor_id, client, pool).await?;
|
let creator = get_or_fetch_and_upsert_user(&creator_actor_id, client, pool).await?;
|
||||||
let recipient_actor_id = note.to().unwrap().clone().single_xsd_any_uri().unwrap();
|
let recipient_actor_id = note
|
||||||
|
.to()
|
||||||
|
.context(location_info!())?
|
||||||
|
.clone()
|
||||||
|
.single_xsd_any_uri()
|
||||||
|
.context(location_info!())?;
|
||||||
let recipient = get_or_fetch_and_upsert_user(&recipient_actor_id, client, pool).await?;
|
let recipient = get_or_fetch_and_upsert_user(&recipient_actor_id, client, pool).await?;
|
||||||
let ap_id = note.id_unchecked().unwrap().to_string();
|
let ap_id = note.id_unchecked().context(location_info!())?.to_string();
|
||||||
check_is_apub_id_valid(&Url::parse(&ap_id)?)?;
|
check_is_apub_id_valid(&Url::parse(&ap_id)?)?;
|
||||||
|
|
||||||
Ok(PrivateMessageForm {
|
Ok(PrivateMessageForm {
|
||||||
|
@ -97,9 +104,9 @@ impl FromApub for PrivateMessageForm {
|
||||||
recipient_id: recipient.id,
|
recipient_id: recipient.id,
|
||||||
content: note
|
content: note
|
||||||
.content()
|
.content()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_single_xsd_string()
|
.as_single_xsd_string()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.to_string(),
|
.to_string(),
|
||||||
published: note.published().map(|u| u.to_owned().naive_local()),
|
published: note.published().map(|u| u.to_owned().naive_local()),
|
||||||
updated: note.updated().map(|u| u.to_owned().naive_local()),
|
updated: note.updated().map(|u| u.to_owned().naive_local()),
|
||||||
|
@ -126,7 +133,7 @@ impl ApubObjectType for PrivateMessage {
|
||||||
let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??;
|
let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??;
|
||||||
|
|
||||||
let mut create = Create::new(creator.actor_id.to_owned(), note.into_any_base()?);
|
let mut create = Create::new(creator.actor_id.to_owned(), note.into_any_base()?);
|
||||||
let to = format!("{}/inbox", recipient.actor_id);
|
let to = recipient.get_inbox_url()?;
|
||||||
create
|
create
|
||||||
.set_context(context())
|
.set_context(context())
|
||||||
.set_id(generate_activity_id(CreateType::Create)?)
|
.set_id(generate_activity_id(CreateType::Create)?)
|
||||||
|
@ -151,7 +158,7 @@ impl ApubObjectType for PrivateMessage {
|
||||||
let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??;
|
let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??;
|
||||||
|
|
||||||
let mut update = Update::new(creator.actor_id.to_owned(), note.into_any_base()?);
|
let mut update = Update::new(creator.actor_id.to_owned(), note.into_any_base()?);
|
||||||
let to = format!("{}/inbox", recipient.actor_id);
|
let to = recipient.get_inbox_url()?;
|
||||||
update
|
update
|
||||||
.set_context(context())
|
.set_context(context())
|
||||||
.set_id(generate_activity_id(UpdateType::Update)?)
|
.set_id(generate_activity_id(UpdateType::Update)?)
|
||||||
|
@ -175,7 +182,7 @@ impl ApubObjectType for PrivateMessage {
|
||||||
let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??;
|
let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??;
|
||||||
|
|
||||||
let mut delete = Delete::new(creator.actor_id.to_owned(), note.into_any_base()?);
|
let mut delete = Delete::new(creator.actor_id.to_owned(), note.into_any_base()?);
|
||||||
let to = format!("{}/inbox", recipient.actor_id);
|
let to = recipient.get_inbox_url()?;
|
||||||
delete
|
delete
|
||||||
.set_context(context())
|
.set_context(context())
|
||||||
.set_id(generate_activity_id(DeleteType::Delete)?)
|
.set_id(generate_activity_id(DeleteType::Delete)?)
|
||||||
|
@ -199,7 +206,7 @@ impl ApubObjectType for PrivateMessage {
|
||||||
let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??;
|
let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??;
|
||||||
|
|
||||||
let mut delete = Delete::new(creator.actor_id.to_owned(), note.into_any_base()?);
|
let mut delete = Delete::new(creator.actor_id.to_owned(), note.into_any_base()?);
|
||||||
let to = format!("{}/inbox", recipient.actor_id);
|
let to = recipient.get_inbox_url()?;
|
||||||
delete
|
delete
|
||||||
.set_context(context())
|
.set_context(context())
|
||||||
.set_id(generate_activity_id(DeleteType::Delete)?)
|
.set_id(generate_activity_id(DeleteType::Delete)?)
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::{
|
||||||
activities::{generate_activity_id, send_activity},
|
activities::{generate_activity_id, send_activity},
|
||||||
check_actor_domain,
|
check_actor_domain,
|
||||||
create_apub_response,
|
create_apub_response,
|
||||||
|
fetcher::get_or_fetch_and_upsert_actor,
|
||||||
insert_activity,
|
insert_activity,
|
||||||
ActorType,
|
ActorType,
|
||||||
FromApub,
|
FromApub,
|
||||||
|
@ -28,11 +29,12 @@ use activitystreams::{
|
||||||
};
|
};
|
||||||
use activitystreams_ext::Ext1;
|
use activitystreams_ext::Ext1;
|
||||||
use actix_web::{body::Body, client::Client, web, HttpResponse};
|
use actix_web::{body::Body, client::Client, web, HttpResponse};
|
||||||
|
use anyhow::Context;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
naive_now,
|
naive_now,
|
||||||
user::{UserForm, User_},
|
user::{UserForm, User_},
|
||||||
};
|
};
|
||||||
use lemmy_utils::convert_datetime;
|
use lemmy_utils::{convert_datetime, location_info};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -82,7 +84,7 @@ impl ToApub for User_ {
|
||||||
.set_following(self.get_following_url().parse()?)
|
.set_following(self.get_following_url().parse()?)
|
||||||
.set_liked(self.get_liked_url().parse()?)
|
.set_liked(self.get_liked_url().parse()?)
|
||||||
.set_endpoints(Endpoints {
|
.set_endpoints(Endpoints {
|
||||||
shared_inbox: Some(self.get_shared_inbox_url().parse()?),
|
shared_inbox: Some(self.get_shared_inbox_url()?),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -90,7 +92,7 @@ impl ToApub for User_ {
|
||||||
ap_actor.set_preferred_username(i.to_owned());
|
ap_actor.set_preferred_username(i.to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Ext1::new(ap_actor, self.get_public_key_ext()))
|
Ok(Ext1::new(ap_actor, self.get_public_key_ext()?))
|
||||||
}
|
}
|
||||||
fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
|
fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
|
@ -103,26 +105,27 @@ impl ActorType for User_ {
|
||||||
self.actor_id.to_owned()
|
self.actor_id.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn public_key(&self) -> String {
|
fn public_key(&self) -> Option<String> {
|
||||||
self.public_key.to_owned().unwrap()
|
self.public_key.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn private_key(&self) -> String {
|
fn private_key(&self) -> Option<String> {
|
||||||
self.private_key.to_owned().unwrap()
|
self.private_key.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// As a given local user, send out a follow request to a remote community.
|
/// As a given local user, send out a follow request to a remote community.
|
||||||
async fn send_follow(
|
async fn send_follow(
|
||||||
&self,
|
&self,
|
||||||
follow_actor_id: &str,
|
follow_actor_id: &Url,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let mut follow = Follow::new(self.actor_id.to_owned(), follow_actor_id);
|
let mut follow = Follow::new(self.actor_id.to_owned(), follow_actor_id.as_str());
|
||||||
follow
|
follow
|
||||||
.set_context(context())
|
.set_context(context())
|
||||||
.set_id(generate_activity_id(FollowType::Follow)?);
|
.set_id(generate_activity_id(FollowType::Follow)?);
|
||||||
let to = format!("{}/inbox", follow_actor_id);
|
let follow_actor = get_or_fetch_and_upsert_actor(follow_actor_id, client, pool).await?;
|
||||||
|
let to = follow_actor.get_inbox_url()?;
|
||||||
|
|
||||||
insert_activity(self.id, follow.clone(), true, pool).await?;
|
insert_activity(self.id, follow.clone(), true, pool).await?;
|
||||||
|
|
||||||
|
@ -132,16 +135,17 @@ impl ActorType for User_ {
|
||||||
|
|
||||||
async fn send_unfollow(
|
async fn send_unfollow(
|
||||||
&self,
|
&self,
|
||||||
follow_actor_id: &str,
|
follow_actor_id: &Url,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let mut follow = Follow::new(self.actor_id.to_owned(), follow_actor_id);
|
let mut follow = Follow::new(self.actor_id.to_owned(), follow_actor_id.as_str());
|
||||||
follow
|
follow
|
||||||
.set_context(context())
|
.set_context(context())
|
||||||
.set_id(generate_activity_id(FollowType::Follow)?);
|
.set_id(generate_activity_id(FollowType::Follow)?);
|
||||||
|
let follow_actor = get_or_fetch_and_upsert_actor(follow_actor_id, client, pool).await?;
|
||||||
|
|
||||||
let to = format!("{}/inbox", follow_actor_id);
|
let to = follow_actor.get_inbox_url()?;
|
||||||
|
|
||||||
// Undo that fake activity
|
// Undo that fake activity
|
||||||
let mut undo = Undo::new(Url::parse(&self.actor_id)?, follow.into_any_base()?);
|
let mut undo = Undo::new(Url::parse(&self.actor_id)?, follow.into_any_base()?);
|
||||||
|
@ -200,7 +204,7 @@ impl ActorType for User_ {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_follower_inboxes(&self, _pool: &DbPool) -> Result<Vec<String>, LemmyError> {
|
async fn get_follower_inboxes(&self, _pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,11 +225,10 @@ impl FromApub for UserForm {
|
||||||
) -> Result<Self, LemmyError> {
|
) -> Result<Self, LemmyError> {
|
||||||
let avatar = match person.icon() {
|
let avatar = match person.icon() {
|
||||||
Some(any_image) => Some(
|
Some(any_image) => Some(
|
||||||
Image::from_any_base(any_image.as_one().unwrap().clone())
|
Image::from_any_base(any_image.as_one().context(location_info!())?.clone())?
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.unwrap()
|
|
||||||
.url()
|
.url()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_single_xsd_any_uri()
|
.as_single_xsd_any_uri()
|
||||||
.map(|u| u.to_string()),
|
.map(|u| u.to_string()),
|
||||||
),
|
),
|
||||||
|
@ -234,11 +237,11 @@ impl FromApub for UserForm {
|
||||||
|
|
||||||
let banner = match person.image() {
|
let banner = match person.image() {
|
||||||
Some(any_image) => Some(
|
Some(any_image) => Some(
|
||||||
Image::from_any_base(any_image.as_one().unwrap().clone())
|
Image::from_any_base(any_image.as_one().context(location_info!())?.clone())
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.url()
|
.url()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_single_xsd_any_uri()
|
.as_single_xsd_any_uri()
|
||||||
.map(|u| u.to_string()),
|
.map(|u| u.to_string()),
|
||||||
),
|
),
|
||||||
|
@ -247,17 +250,19 @@ impl FromApub for UserForm {
|
||||||
|
|
||||||
let name = person
|
let name = person
|
||||||
.name()
|
.name()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.one()
|
.one()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.as_xsd_string()
|
.as_xsd_string()
|
||||||
.unwrap()
|
.context(location_info!())?
|
||||||
.to_string();
|
.to_string();
|
||||||
let preferred_username = person.inner.preferred_username().map(|u| u.to_string());
|
let preferred_username = person.inner.preferred_username().map(|u| u.to_string());
|
||||||
let bio = person
|
let bio = person
|
||||||
.inner
|
.inner
|
||||||
.summary()
|
.summary()
|
||||||
.map(|s| s.as_single_xsd_string().unwrap().into());
|
.map(|s| s.as_single_xsd_string())
|
||||||
|
.flatten()
|
||||||
|
.map(|s| s.to_string());
|
||||||
check_slurs(&name)?;
|
check_slurs(&name)?;
|
||||||
check_slurs_opt(&preferred_username)?;
|
check_slurs_opt(&preferred_username)?;
|
||||||
check_slurs_opt(&bio)?;
|
check_slurs_opt(&bio)?;
|
||||||
|
|
Loading…
Reference in a new issue