use std::io::{Error, ErrorKind};
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> {
DateTime::<Utc>::from_utc(ndt, Utc)
}
// Dont actually add to the community followers here, because you need
// to wait for the accept
user
- .send_follow(&community.actor_id, &self.client, pool)
+ .send_follow(&community.actor_id()?, &self.client, pool)
.await?;
} else {
user
- .send_unfollow(&community.actor_id, &self.client, pool)
+ .send_unfollow(&community.actor_id()?, &self.client, pool)
.await?;
let unfollow = move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form);
if blocking(pool, unfollow).await?.is_err() {
pub async fn send_activity_to_community(
creator: &User_,
community: &Community,
- to: Vec<String>,
+ to: Vec<Url>,
activity: AnyBase,
client: &Client,
pool: &DbPool,
client: &Client,
activity: &AnyBase,
actor: &dyn ActorType,
- to: Vec<String>,
+ to: Vec<Url>,
) -> Result<(), LemmyError> {
let activity = serde_json::to_string(&activity)?;
debug!("Sending activitypub activity {} to {:?}", activity, to);
- for t in to {
- let to_url = Url::parse(&t)?;
+ for to_url in to {
check_is_apub_id_valid(&to_url)?;
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 {
Ok(signed) => Ok(signed.send().await),
public,
};
use actix_web::{body::Body, client::Client, web::Path, HttpResponse};
+use anyhow::Context;
use itertools::Itertools;
use lemmy_db::{
comment::{Comment, CommentForm},
user::User_,
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 serde::Deserialize;
use serde_json::Error;
) -> Result<CommentForm, LemmyError> {
let creator_actor_id = ¬e
.attributed_to()
- .unwrap()
+ .context(location_info!())?
.as_single_xsd_any_uri()
- .unwrap();
+ .context(location_info!())?;
let creator = get_or_fetch_and_upsert_user(creator_actor_id, client, pool).await?;
let mut in_reply_tos = note
.in_reply_to()
.as_ref()
- .unwrap()
+ .context(location_info!())?
.as_many()
- .unwrap()
+ .context(location_info!())?
.iter()
- .map(|i| i.as_xsd_any_uri().unwrap());
- let post_ap_id = in_reply_tos.next().unwrap();
+ .map(|i| i.as_xsd_any_uri().context(""));
+ 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.
let post = get_or_fetch_and_insert_post(&post_ap_id, client, pool).await?;
// For deeply nested comments, FromApub automatically gets called recursively
let parent_id: Option<i32> = match in_reply_tos.next() {
Some(parent_comment_uri) => {
- let parent_comment_ap_id = &parent_comment_uri;
+ let parent_comment_ap_id = &parent_comment_uri?;
let parent_comment =
get_or_fetch_and_insert_comment(&parent_comment_ap_id, client, pool).await?;
};
let content = note
.content()
- .unwrap()
+ .context(location_info!())?
.as_single_xsd_string()
- .unwrap()
+ .context(location_info!())?
.to_string();
let content_slurs_removed = remove_slurs(&content);
send_activity_to_community(
&creator,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
delete.into_any_base()?,
client,
pool,
send_activity_to_community(
&creator,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
undo.into_any_base()?,
client,
pool,
send_activity_to_community(
&mod_,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
remove.into_any_base()?,
client,
pool,
send_activity_to_community(
&mod_,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
undo.into_any_base()?,
client,
pool,
send_activity_to_community(
&creator,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
like.into_any_base()?,
client,
pool,
send_activity_to_community(
&creator,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
dislike.into_any_base()?,
client,
pool,
send_activity_to_community(
&creator,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
undo.into_any_base()?,
client,
pool,
struct MentionsAndAddresses {
addressed_ccs: Vec<String>,
- inboxes: Vec<String>,
+ inboxes: Vec<Url>,
tags: Vec<Mention>,
}
.filter(|m| !m.is_local())
.collect::<Vec<MentionData>>();
- let mut mention_inboxes = Vec::new();
+ let mut mention_inboxes: Vec<Url> = Vec::new();
for mention in &mentions {
// TODO should it be fetching it every time?
if let Ok(actor_id) = fetch_webfinger_url(mention, client).await {
addressed_ccs.push(actor_id.to_owned().to_string());
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);
let mut mention_tag = Mention::new();
}
}
- let mut inboxes = vec![community.get_shared_inbox_url()];
+ let mut inboxes = vec![community.get_shared_inbox_url()?];
inboxes.extend(mention_inboxes);
inboxes = inboxes.into_iter().unique().collect();
create_apub_tombstone_response,
create_tombstone,
extensions::group_extensions::GroupExtension,
- fetcher::get_or_fetch_and_upsert_user,
- get_shared_inbox,
+ fetcher::{get_or_fetch_and_upsert_actor, get_or_fetch_and_upsert_user},
insert_activity,
ActorType,
FromApub,
};
use activitystreams_ext::Ext2;
use actix_web::{body::Body, client::Client, web, HttpResponse};
+use anyhow::Context;
use itertools::Itertools;
use lemmy_db::{
community::{Community, CommunityForm},
post::Post,
user::User_,
};
-use lemmy_utils::convert_datetime;
+use lemmy_utils::{convert_datetime, get_apub_protocol_string, location_info};
use serde::Deserialize;
use url::Url;
.set_following(self.get_following_url().parse()?)
.set_liked(self.get_liked_url().parse()?)
.set_endpoints(Endpoints {
- shared_inbox: Some(self.get_shared_inbox_url().parse()?),
+ shared_inbox: Some(self.get_shared_inbox_url()?),
..Default::default()
});
Ok(Ext2::new(
ap_actor,
group_extension,
- self.get_public_key_ext(),
+ self.get_public_key_ext()?,
))
}
self.actor_id.to_owned()
}
- fn public_key(&self) -> String {
- self.public_key.to_owned().unwrap()
+ fn public_key(&self) -> Option<String> {
+ self.public_key.to_owned()
}
- fn private_key(&self) -> String {
- self.private_key.to_owned().unwrap()
+ fn private_key(&self) -> Option<String> {
+ self.private_key.to_owned()
}
/// As a local community, accept the follow request from a remote user.
client: &Client,
pool: &DbPool,
) -> 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 to = format!("{}/inbox", actor_uri);
+ let to = actor.get_inbox_url()?;
accept
.set_context(context())
.set_id(generate_activity_id(AcceptType::Accept)?)
}
/// 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 inboxes = blocking(pool, move |conn| {
.await??;
let inboxes = inboxes
.into_iter()
- .map(|c| get_shared_inbox(&Url::parse(&c.user_actor_id).unwrap()))
- .filter(|s| !s.is_empty())
+ .map(|u| -> Result<Url, LemmyError> {
+ 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()
.collect();
async fn send_follow(
&self,
- _follow_actor_id: &str,
+ _follow_actor_id: &Url,
_client: &Client,
_pool: &DbPool,
) -> Result<(), LemmyError> {
async fn send_unfollow(
&self,
- _follow_actor_id: &str,
+ _follow_actor_id: &Url,
_client: &Client,
_pool: &DbPool,
) -> Result<(), LemmyError> {
pool: &DbPool,
expected_domain: Option<Url>,
) -> 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
.as_many()
- .unwrap()
+ .context(location_info!())?
.iter()
.next()
- .unwrap()
+ .context(location_info!())?
.as_xsd_any_uri()
- .unwrap();
+ .context(location_info!())?;
let creator = get_or_fetch_and_upsert_user(creator_uri, client, pool).await?;
let name = group
.inner
.name()
- .unwrap()
+ .context(location_info!())?
.as_one()
- .unwrap()
+ .context(location_info!())?
.as_xsd_string()
- .unwrap()
+ .context(location_info!())?
+ .to_string();
+ let title = group
+ .inner
+ .preferred_username()
+ .context(location_info!())?
.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)
// -> same for post.content etc
let description = group
.inner
.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(&title)?;
check_slurs_opt(&description)?;
let icon = match group.icon() {
Some(any_image) => Some(
- Image::from_any_base(any_image.as_one().unwrap().clone())
- .unwrap()
- .unwrap()
+ Image::from_any_base(any_image.as_one().context(location_info!())?.clone())
+ .context(location_info!())?
+ .context(location_info!())?
.url()
- .unwrap()
+ .context(location_info!())?
.as_single_xsd_any_uri()
.map(|u| u.to_string()),
),
let banner = match group.image() {
Some(any_image) => Some(
- Image::from_any_base(any_image.as_one().unwrap().clone())
- .unwrap()
- .unwrap()
+ Image::from_any_base(any_image.as_one().context(location_info!())?.clone())
+ .context(location_info!())?
+ .context(location_info!())?
.url()
- .unwrap()
+ .context(location_info!())?
.as_single_xsd_any_uri()
.map(|u| u.to_string()),
),
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,
// because that would result in a database error (same data inserted twice)
// this seems to be the "easiest" stable alternative for remove_item()
- to.retain(|x| *x != sender.get_shared_inbox_url());
- to.retain(|x| *x != community.get_shared_inbox_url());
+ let sender_shared_inbox = sender.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?;
use activitystreams::unparsed::UnparsedMutExt;
use activitystreams_ext::UnparsedExtension;
use actix_web::{client::ClientRequest, HttpRequest};
-use anyhow::anyhow;
+use anyhow::{anyhow, Context};
use http_signature_normalization_actix::{
digest::{DigestClient, SignExt},
Config,
};
+use lemmy_utils::location_info;
use log::debug;
use openssl::{
hash::MessageDigest,
activity: String,
) -> Result<DigestClient<String>, LemmyError> {
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
.signature_with_digest(
activity,
move |signing_string| {
let private_key = PKey::private_key_from_pem(private_key.as_bytes())?;
- let mut signer = Signer::new(MessageDigest::sha256(), &private_key).unwrap();
- signer.update(signing_string.as_bytes()).unwrap();
+ let mut signer = Signer::new(MessageDigest::sha256(), &private_key)?;
+ signer.update(signing_string.as_bytes())?;
Ok(base64::encode(signer.sign_to_vec()?)) as 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
.begin_verify(
request.method(),
.verify(|signature, signing_string| -> Result<bool, LemmyError> {
debug!(
"Verifying with key {}, message {}",
- &actor.public_key(),
- &signing_string
+ &public_key, &signing_string
);
- let public_key = PKey::public_key_from_pem(actor.public_key().as_bytes())?;
- let mut verifier = Verifier::new(MessageDigest::sha256(), &public_key).unwrap();
- verifier.update(&signing_string.as_bytes()).unwrap();
+ let public_key = PKey::public_key_from_pem(public_key.as_bytes())?;
+ let mut verifier = Verifier::new(MessageDigest::sha256(), &public_key)?;
+ verifier.update(&signing_string.as_bytes())?;
Ok(verifier.verify(&base64::decode(signature)?)?)
})?;
};
use activitystreams::{base::BaseExt, collection::OrderedCollection, object::Note, prelude::*};
use actix_web::client::Client;
-use anyhow::anyhow;
+use anyhow::{anyhow, Context};
use chrono::NaiveDateTime;
use diesel::{result::Error::NotFound, PgConnection};
use lemmy_db::{
Joinable,
SearchType,
};
-use lemmy_utils::get_apub_protocol_string;
+use lemmy_utils::{get_apub_protocol_string, location_info};
use log::debug;
use serde::Deserialize;
use std::{fmt::Debug, time::Duration};
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? {
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?;
response
}
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?;
response
}
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
- 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_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?;
.await??;
// 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
.as_many()
- .unwrap()
+ .context(location_info!())?
.iter()
- .map(|a| a.as_xsd_any_uri().unwrap())
- .collect();
+ .map(|a| a.as_xsd_any_uri().context(""))
+ .collect::<Result<Vec<&Url>, anyhow::Error>>()?;
let mut creator_and_moderators = Vec::new();
// fetch outbox (maybe make this conditional)
let outbox =
fetch_remote_object::<OrderedCollection>(client, &community.get_outbox_url()?).await?;
- let outbox_items = outbox.items().unwrap().clone();
- for o in outbox_items.many().unwrap() {
- let page = PageExt::from_any_base(o)?.unwrap();
+ let outbox_items = outbox.items().context(location_info!())?.clone();
+ for o in outbox_items.many().context(location_info!())? {
+ let page = PageExt::from_any_base(o)?.context(location_info!())?;
let post = PostForm::from_apub(&page, client, pool, None).await?;
let post_ap_id = post.ap_id.clone();
// Check whether the post already exists in the local db
// Ok(
// items
-// .unwrap()
+// .context(location_info!())?
// .map(|obox: &BaseBox| -> Result<PostForm, LemmyError> {
// let page = obox.clone().to_concrete::<Page>()?;
// PostForm::from_page(&page, conn)
prelude::ExtendsExt,
};
use actix_web::{client::Client, HttpResponse};
+use anyhow::Context;
+use lemmy_utils::location_info;
pub async fn receive_announce(
activity: AnyBase,
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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
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 object = announce.object();
- let object2 = object.clone().one().unwrap();
+ let object2 = object.clone().one().context(location_info!())?;
match kind {
Some("Create") => receive_create(object2, client, pool, chat_server).await,
Some("Update") => receive_update(object2, client, pool, chat_server).await,
};
use activitystreams::{activity::Create, base::AnyBase, object::Note, prelude::*};
use actix_web::{client::Client, HttpResponse};
+use anyhow::Context;
use lemmy_db::{
comment::{Comment, CommentForm},
comment_view::CommentView,
post_view::PostView,
Crud,
};
-use lemmy_utils::scrape_text_for_mentions;
+use lemmy_utils::{location_info, scrape_text_for_mentions};
pub async fn receive_create(
activity: AnyBase,
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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
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() {
Some("Page") => receive_create_post(create, client, pool, chat_server).await,
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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?;
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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?;
};
use activitystreams::{activity::Delete, base::AnyBase, object::Note, prelude::*};
use actix_web::{client::Client, HttpResponse};
+use anyhow::Context;
use lemmy_db::{
comment::{Comment, CommentForm},
comment_view::CommentView,
post_view::PostView,
Crud,
};
+use lemmy_utils::location_info;
pub async fn receive_delete(
activity: AnyBase,
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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() {
Some("Page") => receive_delete_post(delete, client, pool, chat_server).await,
Some("Note") => receive_delete_comment(delete, client, pool, chat_server).await,
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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()?))
.await?
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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()?))
.await?
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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 community_actor_id = CommunityForm::from_apub(&group, client, pool, Some(user.actor_id()?))
};
use activitystreams::{activity::Dislike, base::AnyBase, object::Note, prelude::*};
use actix_web::{client::Client, HttpResponse};
+use anyhow::Context;
use lemmy_db::{
comment::{CommentForm, CommentLike, CommentLikeForm},
comment_view::CommentView,
post_view::PostView,
Likeable,
};
+use lemmy_utils::location_info;
pub async fn receive_dislike(
activity: AnyBase,
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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() {
Some("Page") => receive_dislike_post(dislike, client, pool, chat_server).await,
Some("Note") => receive_dislike_comment(dislike, client, pool, chat_server).await,
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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?;
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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 comment = CommentForm::from_apub(¬e, client, pool, None).await?;
};
use activitystreams::{activity::Like, base::AnyBase, object::Note, prelude::*};
use actix_web::{client::Client, HttpResponse};
+use anyhow::Context;
use lemmy_db::{
comment::{CommentForm, CommentLike, CommentLikeForm},
comment_view::CommentView,
post_view::PostView,
Likeable,
};
+use lemmy_utils::location_info;
pub async fn receive_like(
activity: AnyBase,
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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() {
Some("Page") => receive_like_post(like, client, pool, chat_server).await,
Some("Note") => receive_like_comment(like, client, pool, chat_server).await,
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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?;
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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 comment = CommentForm::from_apub(¬e, client, pool, None).await?;
};
use activitystreams::{activity::Remove, base::AnyBase, object::Note, prelude::*};
use actix_web::{client::Client, HttpResponse};
-use anyhow::anyhow;
+use anyhow::{anyhow, Context};
use lemmy_db::{
comment::{Comment, CommentForm},
comment_view::CommentView,
post_view::PostView,
Crud,
};
+use lemmy_utils::location_info;
pub async fn receive_remove(
activity: AnyBase,
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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 community = get_community_id_from_activity(&remove)?;
if actor.actor_id()?.domain() != community.domain() {
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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)
.await?
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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)
.await?
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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()?))
.await?
prelude::*,
};
use actix_web::{client::Client, HttpResponse};
-use anyhow::anyhow;
+use anyhow::{anyhow, Context};
use lemmy_db::{
comment::{Comment, CommentForm, CommentLike, CommentLikeForm},
comment_view::CommentView,
Crud,
Likeable,
};
+use lemmy_utils::location_info;
pub async fn receive_undo(
activity: AnyBase,
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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() {
Some("Delete") => receive_undo_delete(undo, client, pool, chat_server).await,
Some("Remove") => receive_undo_remove(undo, client, pool, chat_server).await,
T: AsBase<A> + ActorAndObjectRef,
{
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_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() {
Err(anyhow!("Cant undo activities from a different instance").into())
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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)?;
- let type_ = delete.object().as_single_kind_str().unwrap();
+ let type_ = delete
+ .object()
+ .as_single_kind_str()
+ .context(location_info!())?;
match type_ {
"Note" => receive_undo_delete_comment(undo, &delete, client, pool, chat_server).await,
"Page" => receive_undo_delete_post(undo, &delete, client, pool, chat_server).await,
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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)?;
- let type_ = remove.object().as_single_kind_str().unwrap();
+ let type_ = remove
+ .object()
+ .as_single_kind_str()
+ .context(location_info!())?;
match type_ {
"Note" => receive_undo_remove_comment(undo, &remove, client, pool, chat_server).await,
"Page" => receive_undo_remove_post(undo, &remove, client, pool, chat_server).await,
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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)?;
- let type_ = like.object().as_single_kind_str().unwrap();
+ let type_ = like
+ .object()
+ .as_single_kind_str()
+ .context(location_info!())?;
match type_ {
"Note" => receive_undo_like_comment(undo, &like, client, pool, chat_server).await,
"Page" => receive_undo_like_post(undo, &like, client, pool, chat_server).await,
_pool: &DbPool,
_chat_server: ChatServerParam,
) -> 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)?;
// 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())
}
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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()?))
.await?
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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)
.await?
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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()?))
.await?
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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)
.await?
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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()?))
.await?
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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()?))
.await?
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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?;
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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?;
};
use activitystreams::{activity::Update, base::AnyBase, object::Note, prelude::*};
use actix_web::{client::Client, HttpResponse};
+use anyhow::Context;
use lemmy_db::{
comment::{Comment, CommentForm},
comment_view::CommentView,
post_view::PostView,
Crud,
};
-use lemmy_utils::scrape_text_for_mentions;
+use lemmy_utils::{location_info, scrape_text_for_mentions};
pub async fn receive_update(
activity: AnyBase,
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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
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() {
Some("Page") => receive_update_post(update, client, pool, chat_server).await,
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
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?;
pool: &DbPool,
chat_server: ChatServerParam,
) -> 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 comment = CommentForm::from_apub(¬e, client, pool, Some(user.actor_id()?)).await?;
prelude::*,
};
use actix_web::{client::Client, web, HttpRequest, HttpResponse};
-use anyhow::anyhow;
+use anyhow::{anyhow, Context};
use lemmy_db::{
community::{Community, CommunityFollower, CommunityFollowerForm},
user::User_,
Followable,
};
+use lemmy_utils::location_info;
use log::debug;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
"Community {} received 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)?;
let user = get_or_fetch_and_upsert_user(&user_uri, &client, &db).await?;
verify(&request, &user)?;
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 res = match kind {
ValidTypes::Follow => handle_follow(any_base, user, community, &client, &db).await,
client: &Client,
db: &DbPoolParam,
) -> 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 {
community_id: community.id,
user_id: user.id,
community: Community,
db: &DbPoolParam,
) -> 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 {
community_id: community.id,
prelude::*,
};
use actix_web::{client::Client, web, HttpRequest, HttpResponse};
+use anyhow::Context;
use lemmy_db::user::User_;
+use lemmy_utils::location_info;
use log::debug;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
let json = serde_json::to_string(&activity)?;
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)?;
check_is_apub_id_valid(sender)?;
verify(&request, actor.as_ref())?;
let any_base = activity.clone().into_any_base()?;
- let kind = activity.kind().unwrap();
+ let kind = activity.kind().context(location_info!())?;
let res = match kind {
ValidTypes::Announce => receive_announce(any_base, &client, &pool, chat_server).await,
ValidTypes::Create => receive_create(any_base, &client, &pool, chat_server).await,
T: AsBase<A> + ActorAndObjectRef,
{
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
}
where
T: AsBase<A> + ActorAndObjectRef + AsObject<A>,
{
- let cc = activity.cc().unwrap();
- let cc = cc.as_many().unwrap();
- Ok(cc.first().unwrap().as_xsd_any_uri().unwrap().to_owned())
+ let cc = activity.cc().context(location_info!())?;
+ let cc = cc.as_many().context(location_info!())?;
+ 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>(
Kind: Serialize,
<T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
{
- let cc = activity.cc().unwrap();
- let cc = cc.as_many().unwrap();
- let community_followers_uri = cc.first().unwrap().as_xsd_any_uri().unwrap();
+ let cc = activity.cc().context(location_info!())?;
+ let cc = cc.as_many().context(location_info!())?;
+ 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
let community_uri = community_followers_uri
.to_string()
prelude::*,
};
use actix_web::{client::Client, web, HttpRequest, HttpResponse};
+use anyhow::Context;
use lemmy_db::{
community::{CommunityFollower, CommunityFollowerForm},
naive_now,
Crud,
Followable,
};
+use lemmy_utils::location_info;
use log::debug;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
let username = path.into_inner();
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)?;
verify(&request, actor.as_ref())?;
let any_base = activity.clone().into_any_base()?;
- let kind = activity.kind().unwrap();
+ let kind = activity.kind().context(location_info!())?;
let res = match kind {
ValidTypes::Accept => receive_accept(any_base, username, &client, &pool).await,
ValidTypes::Create => {
client: &Client,
pool: &DbPool,
) -> Result<HttpResponse, LemmyError> {
- let accept = Accept::from_any_base(activity)?.unwrap();
- let community_uri = accept.actor()?.to_owned().single_xsd_any_uri().unwrap();
+ let accept = Accept::from_any_base(activity)?.context(location_info!())?;
+ 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?;
pool: &DbPool,
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
- let create = Create::from_any_base(activity)?.unwrap();
- let note = Note::from_any_base(create.object().as_one().unwrap().to_owned())?.unwrap();
-
- let domain = Some(create.id_unchecked().unwrap().to_owned());
+ let create = Create::from_any_base(activity)?.context(location_info!())?;
+ let note = Note::from_any_base(
+ create
+ .object()
+ .as_one()
+ .context(location_info!())?
+ .to_owned(),
+ )?
+ .context(location_info!())?;
+
+ let domain = Some(create.id_unchecked().context(location_info!())?.to_owned());
let private_message = PrivateMessageForm::from_apub(¬e, client, pool, domain).await?;
let inserted_private_message = blocking(pool, move |conn| {
pool: &DbPool,
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
- let update = Update::from_any_base(activity)?.unwrap();
- let note = Note::from_any_base(update.object().as_one().unwrap().to_owned())?.unwrap();
-
- let domain = Some(update.id_unchecked().unwrap().to_owned());
+ let update = Update::from_any_base(activity)?.context(location_info!())?;
+ let note = Note::from_any_base(
+ update
+ .object()
+ .as_one()
+ .context(location_info!())?
+ .to_owned(),
+ )?
+ .context(location_info!())?;
+
+ 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_ap_id = private_message_form.ap_id.clone();
pool: &DbPool,
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
- let delete = Delete::from_any_base(activity)?.unwrap();
- let note = Note::from_any_base(delete.object().as_one().unwrap().to_owned())?.unwrap();
-
- let domain = Some(delete.id_unchecked().unwrap().to_owned());
+ let delete = Delete::from_any_base(activity)?.context(location_info!())?;
+ let note = Note::from_any_base(
+ delete
+ .object()
+ .as_one()
+ .context(location_info!())?
+ .to_owned(),
+ )?
+ .context(location_info!())?;
+
+ 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_ap_id = private_message_form.ap_id;
pool: &DbPool,
chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
- let undo = Undo::from_any_base(activity)?.unwrap();
- let delete = Delete::from_any_base(undo.object().as_one().unwrap().to_owned())?.unwrap();
- let note = Note::from_any_base(delete.object().as_one().unwrap().to_owned())?.unwrap();
-
- let domain = Some(undo.id_unchecked().unwrap().to_owned());
+ let undo = Undo::from_any_base(activity)?.context(location_info!())?;
+ let delete = Delete::from_any_base(undo.object().as_one().context(location_info!())?.to_owned())?
+ .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().context(location_info!())?.to_owned());
let private_message = PrivateMessageForm::from_apub(¬e, client, pool, domain).await?;
let private_message_ap_id = private_message.ap_id.clone();
};
use activitystreams_ext::{Ext1, Ext2};
use actix_web::{body::Body, client::Client, HttpResponse};
-use anyhow::anyhow;
+use anyhow::{anyhow, Context};
use chrono::NaiveDateTime;
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 serde::Serialize;
use url::{ParseError, Url};
// instance. replace is needed to remove the port in our federation test setup.
let settings = Settings::get();
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() {
Some(d) => {
T: Base + AsBase<Kind>,
{
let actor_id = if let Some(url) = expected_domain {
- let domain = url.domain().unwrap();
- apub.id(domain)?.unwrap()
+ let domain = url.domain().context(location_info!())?;
+ apub.id(domain)?.context(location_info!())?
} else {
- let actor_id = apub.id_unchecked().unwrap();
+ let actor_id = apub.id_unchecked().context(location_info!())?;
check_is_apub_id_valid(&actor_id)?;
actor_id
};
) -> 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)]
pub trait ActorType {
fn actor_id_str(&self) -> String;
- fn public_key(&self) -> String;
- fn private_key(&self) -> String;
+ // TODO: every actor should have a public key, so this shouldnt be an option (needs to be fixed in db)
+ fn public_key(&self) -> Option<String>;
+ fn private_key(&self) -> Option<String>;
/// numeric id in the database, used for insert_activity
fn user_id(&self) -> i32;
#[allow(unused_variables)]
async fn send_follow(
&self,
- follow_actor_id: &str,
+ follow_actor_id: &Url,
client: &Client,
pool: &DbPool,
) -> Result<(), LemmyError>;
async fn send_unfollow(
&self,
- follow_actor_id: &str,
+ follow_actor_id: &Url,
client: &Client,
pool: &DbPool,
) -> Result<(), LemmyError>;
) -> Result<(), LemmyError>;
/// 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> {
Url::parse(&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) -> String {
- get_shared_inbox(&self.actor_id().unwrap())
+ fn get_shared_inbox_url(&self) -> Result<Url, LemmyError> {
+ let actor_id = self.actor_id()?;
+ 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> {
format!("{}/liked", &self.actor_id_str())
}
- fn get_public_key_ext(&self) -> PublicKeyExtension {
- PublicKey {
- id: format!("{}#main-key", self.actor_id_str()),
- owner: self.actor_id_str(),
- public_key_pem: self.public_key(),
- }
- .to_ext()
+ fn get_public_key_ext(&self) -> Result<PublicKeyExtension, LemmyError> {
+ Ok(
+ PublicKey {
+ id: format!("{}#main-key", self.actor_id_str()),
+ owner: self.actor_id_str(),
+ public_key_pem: self.public_key().context(location_info!())?,
+ }
+ .to_ext(),
+ )
}
}
Update,
},
context,
- object::{kind::PageType, Image, Page, Tombstone},
+ object::{kind::PageType, Image, Object, Page, Tombstone},
prelude::*,
public,
};
use activitystreams_ext::Ext1;
use actix_web::{body::Body, client::Client, web, HttpResponse};
+use anyhow::Context;
use lemmy_db::{
community::Community,
post::{Post, PostForm},
user::User_,
Crud,
};
-use lemmy_utils::{convert_datetime, remove_slurs};
+use lemmy_utils::{convert_datetime, location_info, remove_slurs};
use serde::Deserialize;
use url::Url;
}
}
+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)]
impl FromApub for PostForm {
type ApubType = PageExt;
.inner
.attributed_to()
.as_ref()
- .unwrap()
+ .context(location_info!())?
.as_single_xsd_any_uri()
- .unwrap();
+ .context(location_info!())?;
let creator = get_or_fetch_and_upsert_user(creator_actor_id, client, pool).await?;
.inner
.to()
.as_ref()
- .unwrap()
+ .context(location_info!())?
.as_single_xsd_any_uri()
- .unwrap();
+ .context(location_info!())?;
let community = get_or_fetch_and_upsert_community(community_actor_id, client, pool).await?;
let thumbnail_url = match &page.inner.image() {
- Some(any_image) => Image::from_any_base(any_image.to_owned().as_one().unwrap().to_owned())?
- .unwrap()
- .url()
- .unwrap()
- .as_single_xsd_any_uri()
- .map(|u| u.to_string()),
+ Some(any_image) => Image::from_any_base(
+ any_image
+ .to_owned()
+ .as_one()
+ .context(location_info!())?
+ .to_owned(),
+ )?
+ .context(location_info!())?
+ .url()
+ .context(location_info!())?
+ .as_single_xsd_any_uri()
+ .map(|u| u.to_string()),
None => None,
};
- let (embed_title, embed_description, embed_html) = match page.inner.preview() {
- 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 embed = extract_embed_from_apub(page)?;
let name = page
.inner
.summary()
.as_ref()
- .unwrap()
+ .context(location_info!())?
.as_single_xsd_string()
- .unwrap()
+ .context(location_info!())?
.to_string();
let url = page
.inner
.url()
.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
.inner
.content()
.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)?;
let body_slurs_removed = body.map(|b| remove_slurs(&b));
Ok(PostForm {
deleted: None,
nsfw: ext.sensitive,
stickied: Some(ext.stickied),
- embed_title,
- embed_description,
- embed_html,
+ embed_title: embed.title,
+ embed_description: embed.description,
+ embed_html: embed.html,
thumbnail_url,
ap_id: check_actor_domain(page, expected_domain)?,
local: false,
send_activity_to_community(
creator,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
create.into_any_base()?,
client,
pool,
send_activity_to_community(
creator,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
update.into_any_base()?,
client,
pool,
send_activity_to_community(
creator,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
delete.into_any_base()?,
client,
pool,
send_activity_to_community(
creator,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
undo.into_any_base()?,
client,
pool,
send_activity_to_community(
mod_,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
remove.into_any_base()?,
client,
pool,
send_activity_to_community(
mod_,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
undo.into_any_base()?,
client,
pool,
send_activity_to_community(
&creator,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
like.into_any_base()?,
client,
pool,
send_activity_to_community(
&creator,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
dislike.into_any_base()?,
client,
pool,
send_activity_to_community(
&creator,
&community,
- vec![community.get_shared_inbox_url()],
+ vec![community.get_shared_inbox_url()?],
undo.into_any_base()?,
client,
pool,
create_tombstone,
fetcher::get_or_fetch_and_upsert_user,
insert_activity,
+ ActorType,
ApubObjectType,
FromApub,
ToApub,
prelude::*,
};
use actix_web::client::Client;
+use anyhow::Context;
use lemmy_db::{
private_message::{PrivateMessage, PrivateMessageForm},
user::User_,
Crud,
};
-use lemmy_utils::convert_datetime;
+use lemmy_utils::{convert_datetime, location_info};
use url::Url;
#[async_trait::async_trait(?Send)]
) -> Result<PrivateMessageForm, LemmyError> {
let creator_actor_id = note
.attributed_to()
- .unwrap()
+ .context(location_info!())?
.clone()
.single_xsd_any_uri()
- .unwrap();
+ .context(location_info!())?;
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 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)?)?;
Ok(PrivateMessageForm {
recipient_id: recipient.id,
content: note
.content()
- .unwrap()
+ .context(location_info!())?
.as_single_xsd_string()
- .unwrap()
+ .context(location_info!())?
.to_string(),
published: note.published().map(|u| u.to_owned().naive_local()),
updated: note.updated().map(|u| u.to_owned().naive_local()),
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 to = format!("{}/inbox", recipient.actor_id);
+ let to = recipient.get_inbox_url()?;
create
.set_context(context())
.set_id(generate_activity_id(CreateType::Create)?)
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 to = format!("{}/inbox", recipient.actor_id);
+ let to = recipient.get_inbox_url()?;
update
.set_context(context())
.set_id(generate_activity_id(UpdateType::Update)?)
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 to = format!("{}/inbox", recipient.actor_id);
+ let to = recipient.get_inbox_url()?;
delete
.set_context(context())
.set_id(generate_activity_id(DeleteType::Delete)?)
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 to = format!("{}/inbox", recipient.actor_id);
+ let to = recipient.get_inbox_url()?;
delete
.set_context(context())
.set_id(generate_activity_id(DeleteType::Delete)?)
activities::{generate_activity_id, send_activity},
check_actor_domain,
create_apub_response,
+ fetcher::get_or_fetch_and_upsert_actor,
insert_activity,
ActorType,
FromApub,
};
use activitystreams_ext::Ext1;
use actix_web::{body::Body, client::Client, web, HttpResponse};
+use anyhow::Context;
use lemmy_db::{
naive_now,
user::{UserForm, User_},
};
-use lemmy_utils::convert_datetime;
+use lemmy_utils::{convert_datetime, location_info};
use serde::Deserialize;
use url::Url;
.set_following(self.get_following_url().parse()?)
.set_liked(self.get_liked_url().parse()?)
.set_endpoints(Endpoints {
- shared_inbox: Some(self.get_shared_inbox_url().parse()?),
+ shared_inbox: Some(self.get_shared_inbox_url()?),
..Default::default()
});
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> {
unimplemented!()
self.actor_id.to_owned()
}
- fn public_key(&self) -> String {
- self.public_key.to_owned().unwrap()
+ fn public_key(&self) -> Option<String> {
+ self.public_key.to_owned()
}
- fn private_key(&self) -> String {
- self.private_key.to_owned().unwrap()
+ fn private_key(&self) -> Option<String> {
+ self.private_key.to_owned()
}
/// As a given local user, send out a follow request to a remote community.
async fn send_follow(
&self,
- follow_actor_id: &str,
+ follow_actor_id: &Url,
client: &Client,
pool: &DbPool,
) -> 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
.set_context(context())
.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?;
async fn send_unfollow(
&self,
- follow_actor_id: &str,
+ follow_actor_id: &Url,
client: &Client,
pool: &DbPool,
) -> 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
.set_context(context())
.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
let mut undo = Undo::new(Url::parse(&self.actor_id)?, follow.into_any_base()?);
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!()
}
) -> Result<Self, LemmyError> {
let avatar = match person.icon() {
Some(any_image) => Some(
- Image::from_any_base(any_image.as_one().unwrap().clone())
- .unwrap()
- .unwrap()
+ Image::from_any_base(any_image.as_one().context(location_info!())?.clone())?
+ .context(location_info!())?
.url()
- .unwrap()
+ .context(location_info!())?
.as_single_xsd_any_uri()
.map(|u| u.to_string()),
),
let banner = match person.image() {
Some(any_image) => Some(
- Image::from_any_base(any_image.as_one().unwrap().clone())
- .unwrap()
- .unwrap()
+ Image::from_any_base(any_image.as_one().context(location_info!())?.clone())
+ .context(location_info!())?
+ .context(location_info!())?
.url()
- .unwrap()
+ .context(location_info!())?
.as_single_xsd_any_uri()
.map(|u| u.to_string()),
),
let name = person
.name()
- .unwrap()
+ .context(location_info!())?
.one()
- .unwrap()
+ .context(location_info!())?
.as_xsd_string()
- .unwrap()
+ .context(location_info!())?
.to_string();
let preferred_username = person.inner.preferred_username().map(|u| u.to_string());
let bio = person
.inner
.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_opt(&preferred_username)?;
check_slurs_opt(&bio)?;