mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-14 08:23:59 +00:00
133 lines
3.5 KiB
Rust
133 lines
3.5 KiB
Rust
use crate::{
|
|
apub::{
|
|
extensions::signatures::verify,
|
|
fetcher::{get_or_fetch_and_upsert_remote_community, get_or_fetch_and_upsert_remote_user},
|
|
insert_activity,
|
|
ActorType,
|
|
},
|
|
blocking,
|
|
routes::{ChatServerParam, DbPoolParam},
|
|
LemmyError,
|
|
};
|
|
use activitystreams_new::{
|
|
activity::{Follow, Undo},
|
|
prelude::*,
|
|
};
|
|
use actix_web::{client::Client, web, HttpRequest, HttpResponse};
|
|
use lemmy_db::{
|
|
community::{Community, CommunityFollower, CommunityFollowerForm},
|
|
user::User_,
|
|
Followable,
|
|
};
|
|
use log::debug;
|
|
use serde::Deserialize;
|
|
use std::fmt::Debug;
|
|
|
|
#[serde(untagged)]
|
|
#[derive(Deserialize, Debug)]
|
|
pub enum CommunityAcceptedObjects {
|
|
Follow(Follow),
|
|
Undo(Undo),
|
|
}
|
|
|
|
impl CommunityAcceptedObjects {
|
|
fn follow(&self) -> Result<Follow, LemmyError> {
|
|
match self {
|
|
CommunityAcceptedObjects::Follow(f) => Ok(f.to_owned()),
|
|
CommunityAcceptedObjects::Undo(u) => {
|
|
Ok(Follow::from_any_base(u.object().as_one().unwrap().to_owned())?.unwrap())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Handler for all incoming activities to community inboxes.
|
|
pub async fn community_inbox(
|
|
request: HttpRequest,
|
|
input: web::Json<CommunityAcceptedObjects>,
|
|
path: web::Path<String>,
|
|
db: DbPoolParam,
|
|
client: web::Data<Client>,
|
|
_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??;
|
|
|
|
if !community.local {
|
|
return Err(
|
|
format_err!(
|
|
"Received activity is addressed to remote community {}",
|
|
&community.actor_id
|
|
)
|
|
.into(),
|
|
);
|
|
}
|
|
debug!(
|
|
"Community {} received activity {:?}",
|
|
&community.name, &input
|
|
);
|
|
let follow = input.follow()?;
|
|
let user_uri = follow.actor()?.as_single_xsd_any_uri().unwrap();
|
|
let community_uri = follow.object().as_single_xsd_any_uri().unwrap();
|
|
|
|
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?;
|
|
|
|
verify(&request, &user)?;
|
|
|
|
match input {
|
|
CommunityAcceptedObjects::Follow(f) => handle_follow(f, user, community, &client, db).await,
|
|
CommunityAcceptedObjects::Undo(u) => handle_undo_follow(u, user, community, db).await,
|
|
}
|
|
}
|
|
|
|
/// 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?;
|
|
|
|
let community_follower_form = CommunityFollowerForm {
|
|
community_id: community.id,
|
|
user_id: user.id,
|
|
};
|
|
|
|
// 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?;
|
|
|
|
community.send_accept_follow(follow, &client, &db).await?;
|
|
|
|
Ok(HttpResponse::Ok().finish())
|
|
}
|
|
|
|
async fn handle_undo_follow(
|
|
undo: Undo,
|
|
user: User_,
|
|
community: Community,
|
|
db: DbPoolParam,
|
|
) -> Result<HttpResponse, LemmyError> {
|
|
insert_activity(user.id, undo, false, &db).await?;
|
|
|
|
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?;
|
|
|
|
Ok(HttpResponse::Ok().finish())
|
|
}
|