2020-05-16 14:04:08 +00:00
|
|
|
use crate::{
|
|
|
|
apub::{
|
2020-08-04 14:39:55 +00:00
|
|
|
check_is_apub_id_valid,
|
2020-05-16 14:04:08 +00:00
|
|
|
extensions::signatures::verify,
|
2020-08-04 14:39:55 +00:00
|
|
|
fetcher::get_or_fetch_and_upsert_user,
|
2020-07-29 11:46:11 +00:00
|
|
|
insert_activity,
|
|
|
|
ActorType,
|
2020-05-16 14:04:08 +00:00
|
|
|
},
|
2020-07-01 12:54:29 +00:00
|
|
|
blocking,
|
2020-08-18 13:43:50 +00:00
|
|
|
LemmyContext,
|
2020-07-01 12:54:29 +00:00
|
|
|
LemmyError,
|
2020-05-16 14:04:08 +00:00
|
|
|
};
|
2020-08-01 13:25:17 +00:00
|
|
|
use activitystreams::{
|
2020-08-04 14:39:55 +00:00
|
|
|
activity::{ActorAndObject, Follow, Undo},
|
|
|
|
base::AnyBase,
|
2020-07-17 21:11:07 +00:00
|
|
|
prelude::*,
|
|
|
|
};
|
2020-08-18 13:43:50 +00:00
|
|
|
use actix_web::{web, HttpRequest, HttpResponse};
|
2020-08-11 14:31:05 +00:00
|
|
|
use anyhow::{anyhow, Context};
|
2020-07-10 18:15:41 +00:00
|
|
|
use lemmy_db::{
|
|
|
|
community::{Community, CommunityFollower, CommunityFollowerForm},
|
|
|
|
user::User_,
|
|
|
|
Followable,
|
|
|
|
};
|
2020-08-11 14:31:05 +00:00
|
|
|
use lemmy_utils::location_info;
|
2020-05-16 14:04:08 +00:00
|
|
|
use log::debug;
|
2020-08-04 14:39:55 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2020-07-01 12:54:29 +00:00
|
|
|
use std::fmt::Debug;
|
2020-04-15 18:12:25 +00:00
|
|
|
|
2020-08-04 14:39:55 +00:00
|
|
|
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
|
|
|
|
#[serde(rename_all = "PascalCase")]
|
|
|
|
pub enum ValidTypes {
|
|
|
|
Follow,
|
|
|
|
Undo,
|
2020-04-15 18:12:25 +00:00
|
|
|
}
|
|
|
|
|
2020-08-04 14:39:55 +00:00
|
|
|
pub type AcceptedActivities = ActorAndObject<ValidTypes>;
|
2020-05-14 15:44:01 +00:00
|
|
|
|
2020-04-17 15:33:55 +00:00
|
|
|
/// Handler for all incoming activities to community inboxes.
|
2020-04-15 18:12:25 +00:00
|
|
|
pub async fn community_inbox(
|
2020-04-19 17:35:40 +00:00
|
|
|
request: HttpRequest,
|
2020-08-04 14:39:55 +00:00
|
|
|
input: web::Json<AcceptedActivities>,
|
2020-04-17 17:34:18 +00:00
|
|
|
path: web::Path<String>,
|
2020-08-18 13:43:50 +00:00
|
|
|
context: web::Data<LemmyContext>,
|
2020-07-01 12:54:29 +00:00
|
|
|
) -> Result<HttpResponse, LemmyError> {
|
2020-08-04 14:39:55 +00:00
|
|
|
let activity = input.into_inner();
|
2020-07-01 12:54:29 +00:00
|
|
|
|
|
|
|
let path = path.into_inner();
|
2020-08-18 13:43:50 +00:00
|
|
|
let community = blocking(&context.pool(), move |conn| {
|
|
|
|
Community::read_from_name(&conn, &path)
|
|
|
|
})
|
|
|
|
.await??;
|
2020-07-01 12:54:29 +00:00
|
|
|
|
2020-05-06 17:10:36 +00:00
|
|
|
if !community.local {
|
2020-07-01 12:54:29 +00:00
|
|
|
return Err(
|
2020-08-01 14:04:42 +00:00
|
|
|
anyhow!(
|
2020-07-01 12:54:29 +00:00
|
|
|
"Received activity is addressed to remote community {}",
|
|
|
|
&community.actor_id
|
|
|
|
)
|
|
|
|
.into(),
|
|
|
|
);
|
2020-05-06 17:10:36 +00:00
|
|
|
}
|
2020-04-17 14:55:28 +00:00
|
|
|
debug!(
|
|
|
|
"Community {} received activity {:?}",
|
2020-08-04 14:39:55 +00:00
|
|
|
&community.name, &activity
|
2020-04-17 14:55:28 +00:00
|
|
|
);
|
2020-08-11 14:31:05 +00:00
|
|
|
let user_uri = activity
|
|
|
|
.actor()?
|
|
|
|
.as_single_xsd_any_uri()
|
|
|
|
.context(location_info!())?;
|
2020-08-04 14:39:55 +00:00
|
|
|
check_is_apub_id_valid(user_uri)?;
|
2020-04-24 14:04:36 +00:00
|
|
|
|
2020-08-18 13:43:50 +00:00
|
|
|
let user = get_or_fetch_and_upsert_user(&user_uri, &context).await?;
|
2020-04-24 14:04:36 +00:00
|
|
|
|
2020-05-14 13:38:07 +00:00
|
|
|
verify(&request, &user)?;
|
2020-04-24 14:04:36 +00:00
|
|
|
|
2020-08-04 14:39:55 +00:00
|
|
|
let any_base = activity.clone().into_any_base()?;
|
2020-08-11 14:31:05 +00:00
|
|
|
let kind = activity.kind().context(location_info!())?;
|
2020-08-06 19:44:47 +00:00
|
|
|
let user_id = user.id;
|
|
|
|
let res = match kind {
|
2020-08-18 13:43:50 +00:00
|
|
|
ValidTypes::Follow => handle_follow(any_base, user, community, &context).await,
|
|
|
|
ValidTypes::Undo => handle_undo_follow(any_base, user, community, &context).await,
|
2020-08-06 19:44:47 +00:00
|
|
|
};
|
|
|
|
|
2020-08-18 13:43:50 +00:00
|
|
|
insert_activity(user_id, activity.clone(), false, context.pool()).await?;
|
2020-08-06 19:44:47 +00:00
|
|
|
res
|
2020-05-14 15:44:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Handle a follow request from a remote user, adding it to the local database and returning an
|
|
|
|
/// Accept activity.
|
2020-07-01 12:54:29 +00:00
|
|
|
async fn handle_follow(
|
2020-08-04 14:39:55 +00:00
|
|
|
activity: AnyBase,
|
2020-07-01 12:54:29 +00:00
|
|
|
user: User_,
|
|
|
|
community: Community,
|
2020-08-18 13:43:50 +00:00
|
|
|
context: &LemmyContext,
|
2020-07-01 12:54:29 +00:00
|
|
|
) -> Result<HttpResponse, LemmyError> {
|
2020-08-11 14:31:05 +00:00
|
|
|
let follow = Follow::from_any_base(activity)?.context(location_info!())?;
|
2020-04-15 18:12:25 +00:00
|
|
|
let community_follower_form = CommunityFollowerForm {
|
|
|
|
community_id: community.id,
|
|
|
|
user_id: user.id,
|
|
|
|
};
|
2020-04-24 14:04:36 +00:00
|
|
|
|
2020-04-25 02:34:51 +00:00
|
|
|
// This will fail if they're already a follower, but ignore the error.
|
2020-08-18 13:43:50 +00:00
|
|
|
blocking(&context.pool(), move |conn| {
|
2020-07-01 12:54:29 +00:00
|
|
|
CommunityFollower::follow(&conn, &community_follower_form).ok()
|
|
|
|
})
|
|
|
|
.await?;
|
2020-04-24 14:04:36 +00:00
|
|
|
|
2020-08-18 13:43:50 +00:00
|
|
|
community.send_accept_follow(follow, context).await?;
|
2020-04-26 17:20:42 +00:00
|
|
|
|
2020-04-15 18:12:25 +00:00
|
|
|
Ok(HttpResponse::Ok().finish())
|
|
|
|
}
|
2020-05-04 02:41:45 +00:00
|
|
|
|
2020-07-01 12:54:29 +00:00
|
|
|
async fn handle_undo_follow(
|
2020-08-04 14:39:55 +00:00
|
|
|
activity: AnyBase,
|
2020-07-01 12:54:29 +00:00
|
|
|
user: User_,
|
|
|
|
community: Community,
|
2020-08-18 13:43:50 +00:00
|
|
|
context: &LemmyContext,
|
2020-07-01 12:54:29 +00:00
|
|
|
) -> Result<HttpResponse, LemmyError> {
|
2020-08-11 14:31:05 +00:00
|
|
|
let _undo = Undo::from_any_base(activity)?.context(location_info!())?;
|
2020-05-04 02:41:45 +00:00
|
|
|
|
|
|
|
let community_follower_form = CommunityFollowerForm {
|
|
|
|
community_id: community.id,
|
|
|
|
user_id: user.id,
|
|
|
|
};
|
|
|
|
|
2020-07-01 12:54:29 +00:00
|
|
|
// This will fail if they aren't a follower, but ignore the error.
|
2020-08-18 13:43:50 +00:00
|
|
|
blocking(&context.pool(), move |conn| {
|
2020-07-01 12:54:29 +00:00
|
|
|
CommunityFollower::unfollow(&conn, &community_follower_form).ok()
|
|
|
|
})
|
|
|
|
.await?;
|
2020-05-04 02:41:45 +00:00
|
|
|
|
|
|
|
Ok(HttpResponse::Ok().finish())
|
|
|
|
}
|