lemmy/crates/apub/src/activity_lists.rs
Nutomic ad90cd77f9
Implement private communities (#5076)
* add private visibility

* filter private communities in post_view.rs

* also filter in comment_view

* community follower state

* remove unused method

* sql fmt

* add CommunityFollower.approved_by

* implement api endpoints

* api changes

* only admins can create private community for now

* add local api tests

* fix api tests

* follow remote private community

* use authorized fetch for content in private community

* federate community visibility

* dont mark content in private community as public

* expose ApprovalRequired in api

* also check content fetchable for outbox/featured

* address private community content to followers

* implement reject activity

* fix tests

* add files

* remove local api tests

* dont use delay

* is_new_instance

* single query for is_new_instance

* return subscribed type for pending follow

* working

* need to catch errors in waitUntil

* clippy

* fix query

* lint for unused async

* diesel.toml comment

* add comment

* avoid db reads

* rename approved_by to approver_id

* add helper

* form init

* list pending follows should return items for all communities

* clippy

* ci

* fix down migration

* fix api tests

* references

* rename

* run git diff

* ci

* fix schema check

* fix joins

* ci

* ci

* skip_serializing_none

* fix test

---------

Co-authored-by: Dessalines <dessalines@users.noreply.github.com>
2024-11-07 05:49:05 -05:00

172 lines
5.5 KiB
Rust

use crate::{
objects::community::ApubCommunity,
protocol::{
activities::{
block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
community::{
announce::{AnnounceActivity, RawAnnouncableActivities},
collection_add::CollectionAdd,
collection_remove::CollectionRemove,
lock_page::{LockPage, UndoLockPage},
report::Report,
update::UpdateCommunity,
},
create_or_update::{
chat_message::CreateOrUpdateChatMessage,
note::CreateOrUpdateNote,
page::CreateOrUpdatePage,
},
deletion::{delete::Delete, undo_delete::UndoDelete},
following::{
accept::AcceptFollow,
follow::Follow,
reject::RejectFollow,
undo_follow::UndoFollow,
},
voting::{undo_vote::UndoVote, vote::Vote},
},
objects::page::Page,
InCommunity,
},
};
use activitypub_federation::{config::Data, traits::ActivityHandler};
use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
use serde::{Deserialize, Serialize};
use url::Url;
/// List of activities which the shared inbox can handle.
///
/// This could theoretically be defined as an enum with variants `GroupInboxActivities` and
/// `PersonInboxActivities`. In practice we need to write it out manually so that priorities
/// are handled correctly.
#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(untagged)]
#[enum_delegate::implement(ActivityHandler)]
pub enum SharedInboxActivities {
Follow(Follow),
AcceptFollow(AcceptFollow),
RejectFollow(RejectFollow),
UndoFollow(UndoFollow),
CreateOrUpdatePrivateMessage(CreateOrUpdateChatMessage),
Report(Report),
AnnounceActivity(AnnounceActivity),
/// This is a catch-all and needs to be last
RawAnnouncableActivities(RawAnnouncableActivities),
}
/// List of activities which the group inbox can handle.
#[derive(Debug, Deserialize, Serialize)]
#[serde(untagged)]
#[enum_delegate::implement(ActivityHandler)]
pub enum GroupInboxActivities {
Follow(Follow),
UndoFollow(UndoFollow),
Report(Report),
/// This is a catch-all and needs to be last
AnnouncableActivities(RawAnnouncableActivities),
}
/// List of activities which the person inbox can handle.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)]
#[enum_delegate::implement(ActivityHandler)]
pub enum PersonInboxActivities {
Follow(Follow),
AcceptFollow(AcceptFollow),
RejectFollow(RejectFollow),
UndoFollow(UndoFollow),
CreateOrUpdatePrivateMessage(CreateOrUpdateChatMessage),
Delete(Delete),
UndoDelete(UndoDelete),
AnnounceActivity(AnnounceActivity),
/// User can also receive some "announcable" activities, eg a comment mention.
AnnouncableActivities(AnnouncableActivities),
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)]
#[enum_delegate::implement(ActivityHandler)]
pub enum AnnouncableActivities {
CreateOrUpdateComment(CreateOrUpdateNote),
CreateOrUpdatePost(CreateOrUpdatePage),
Vote(Vote),
UndoVote(UndoVote),
Delete(Delete),
UndoDelete(UndoDelete),
UpdateCommunity(UpdateCommunity),
BlockUser(BlockUser),
UndoBlockUser(UndoBlockUser),
CollectionAdd(CollectionAdd),
CollectionRemove(CollectionRemove),
LockPost(LockPage),
UndoLockPost(UndoLockPage),
// For compatibility with Pleroma/Mastodon (send only)
Page(Page),
}
#[async_trait::async_trait]
impl InCommunity for AnnouncableActivities {
#[tracing::instrument(skip(self, context))]
async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<ApubCommunity> {
use AnnouncableActivities::*;
match self {
CreateOrUpdateComment(a) => a.community(context).await,
CreateOrUpdatePost(a) => a.community(context).await,
Vote(a) => a.community(context).await,
UndoVote(a) => a.community(context).await,
Delete(a) => a.community(context).await,
UndoDelete(a) => a.community(context).await,
UpdateCommunity(a) => a.community(context).await,
BlockUser(a) => a.community(context).await,
UndoBlockUser(a) => a.community(context).await,
CollectionAdd(a) => a.community(context).await,
CollectionRemove(a) => a.community(context).await,
LockPost(a) => a.community(context).await,
UndoLockPost(a) => a.community(context).await,
Page(_) => Err(LemmyErrorType::NotFound.into()),
}
}
}
#[cfg(test)]
mod tests {
use crate::{
activity_lists::{GroupInboxActivities, PersonInboxActivities, SharedInboxActivities},
protocol::tests::{test_json, test_parse_lemmy_item},
};
use lemmy_utils::error::LemmyResult;
#[test]
fn test_group_inbox() -> LemmyResult<()> {
test_parse_lemmy_item::<GroupInboxActivities>("assets/lemmy/activities/following/follow.json")?;
test_parse_lemmy_item::<GroupInboxActivities>(
"assets/lemmy/activities/create_or_update/create_note.json",
)?;
Ok(())
}
#[test]
fn test_person_inbox() -> LemmyResult<()> {
test_parse_lemmy_item::<PersonInboxActivities>(
"assets/lemmy/activities/following/accept.json",
)?;
test_parse_lemmy_item::<PersonInboxActivities>(
"assets/lemmy/activities/create_or_update/create_note.json",
)?;
test_parse_lemmy_item::<PersonInboxActivities>(
"assets/lemmy/activities/create_or_update/create_private_message.json",
)?;
test_json::<PersonInboxActivities>("assets/mastodon/activities/follow.json")?;
Ok(())
}
#[test]
fn test_shared_inbox() -> LemmyResult<()> {
test_parse_lemmy_item::<SharedInboxActivities>(
"assets/lemmy/activities/deletion/delete_user.json",
)?;
Ok(())
}
}