lemmy/server/src/apub/community_inbox.rs

137 lines
3.6 KiB
Rust
Raw Normal View History

2020-05-16 14:04:08 +00:00
use crate::{
apub::{
extensions::signatures::verify,
fetcher::{get_or_fetch_and_upsert_remote_community, get_or_fetch_and_upsert_remote_user},
insert_activity,
2020-05-16 14:04:08 +00:00
ActorType,
},
blocking,
2020-05-16 14:04:08 +00:00
routes::{ChatServerParam, DbPoolParam},
LemmyError,
2020-05-16 14:04:08 +00:00
};
2020-06-03 15:54:15 +00:00
use activitystreams::activity::Undo;
use activitystreams_new::activity::Follow;
use actix_web::{client::Client, web, HttpRequest, HttpResponse};
use lemmy_db::{
community::{Community, CommunityFollower, CommunityFollowerForm},
user::User_,
Followable,
};
2020-05-16 14:04:08 +00:00
use log::debug;
2020-05-30 17:44:50 +00:00
use serde::Deserialize;
use std::fmt::Debug;
#[serde(untagged)]
2020-04-17 14:55:28 +00:00
#[derive(Deserialize, Debug)]
pub enum CommunityAcceptedObjects {
Follow(Follow),
2020-05-04 02:41:45 +00:00
Undo(Undo),
}
2020-05-14 15:44:01 +00:00
impl CommunityAcceptedObjects {
fn follow(&self) -> Result<Follow, LemmyError> {
2020-05-14 15:44:01 +00:00
match self {
CommunityAcceptedObjects::Follow(f) => Ok(f.to_owned()),
CommunityAcceptedObjects::Undo(u) => Ok(
u.undo_props
.get_object_base_box()
.to_owned()
.unwrap()
.to_owned()
.into_concrete::<Follow>()?,
),
}
}
}
2020-04-17 15:33:55 +00:00
/// Handler for all incoming activities to community inboxes.
pub async fn community_inbox(
2020-04-19 17:35:40 +00:00
request: HttpRequest,
input: web::Json<CommunityAcceptedObjects>,
2020-04-17 17:34:18 +00:00
path: web::Path<String>,
2020-04-24 14:04:36 +00:00
db: DbPoolParam,
client: web::Data<Client>,
2020-05-30 17:44:50 +00:00
_chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> {
let input = input.into_inner();
let path = path.into_inner();
let community = blocking(&db, move |conn| Community::read_from_name(&conn, &path)).await??;
2020-05-06 17:10:36 +00:00
if !community.local {
return Err(
format_err!(
"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-05-06 17:10:36 +00:00
&community.name, &input
2020-04-17 14:55:28 +00:00
);
2020-05-14 15:44:01 +00:00
let follow = input.follow()?;
2020-06-03 15:54:15 +00:00
let user_uri = follow.actor.as_single_xsd_any_uri().unwrap().to_string();
let community_uri = follow.object.as_single_xsd_any_uri().unwrap().to_string();
2020-04-24 14:04:36 +00:00
let user = get_or_fetch_and_upsert_remote_user(&user_uri, &client, &db).await?;
let community = get_or_fetch_and_upsert_remote_community(&community_uri, &client, &db).await?;
2020-04-24 14:04:36 +00:00
verify(&request, &user)?;
2020-04-24 14:04:36 +00:00
2020-05-14 15:44:01 +00:00
match input {
CommunityAcceptedObjects::Follow(f) => handle_follow(f, user, community, &client, db).await,
CommunityAcceptedObjects::Undo(u) => handle_undo_follow(u, user, community, db).await,
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.
async fn handle_follow(
follow: Follow,
user: User_,
community: Community,
client: &Client,
db: DbPoolParam,
) -> Result<HttpResponse, LemmyError> {
insert_activity(user.id, follow.clone(), false, &db).await?;
2020-04-27 22:17:02 +00:00
let community_follower_form = CommunityFollowerForm {
community_id: community.id,
user_id: user.id,
};
2020-04-24 14:04:36 +00:00
// This will fail if they're already a follower, but ignore the error.
blocking(&db, move |conn| {
CommunityFollower::follow(&conn, &community_follower_form).ok()
})
.await?;
2020-04-24 14:04:36 +00:00
community.send_accept_follow(&follow, &client, &db).await?;
Ok(HttpResponse::Ok().finish())
}
2020-05-04 02:41:45 +00:00
async fn handle_undo_follow(
undo: Undo,
user: User_,
community: Community,
db: DbPoolParam,
) -> Result<HttpResponse, LemmyError> {
insert_activity(user.id, undo, false, &db).await?;
2020-05-04 02:41:45 +00:00
let community_follower_form = CommunityFollowerForm {
community_id: community.id,
user_id: user.id,
};
// This will fail if they aren't a follower, but ignore the error.
blocking(&db, move |conn| {
CommunityFollower::unfollow(&conn, &community_follower_form).ok()
})
.await?;
2020-05-04 02:41:45 +00:00
Ok(HttpResponse::Ok().finish())
}