name = "lemmy_api"
version = "0.16.5"
dependencies = [
- "activitypub_federation",
"actix-web",
"anyhow",
"async-trait",
"chrono",
"diesel",
"lemmy_api_common",
- "lemmy_apub",
"lemmy_db_schema",
"lemmy_db_views",
"lemmy_db_views_actor",
"async-trait",
"bcrypt",
"lemmy_api_common",
- "lemmy_apub",
"lemmy_db_schema",
"lemmy_db_views",
"lemmy_db_views_actor",
"reqwest-retry",
"reqwest-tracing",
"serde",
+ "serde_json",
"tracing",
"tracing-actix-web",
"tracing-error",
doku = { workspace = true }
parking_lot = { workspace = true }
reqwest-retry = { workspace = true }
+serde_json = { workspace = true }
tracing-opentelemetry = { workspace = true, optional = true }
opentelemetry = { workspace = true, optional = true }
console-subscriber = { version = "0.1.8", optional = true }
let gammaCommunity = (
await resolveCommunity(gamma, communityRes.community.actor_id)
).community.unwrap();
- let gammaFollow = await followCommunity(
+ await followCommunity(
gamma,
true,
gammaCommunity.community.id
);
- expect(gammaFollow.community_view.subscribed).toBe("Subscribed");
+ gammaCommunity = (
+ await resolveCommunity(gamma, communityRes.community.actor_id)
+ ).community.unwrap();
+ expect(gammaCommunity.subscribed).toBe("Subscribed");
let gammaPost = (await createPost(gamma, gammaCommunity.community.id))
.post_view;
expect(gammaPost.post.id).toBeDefined();
test("Follow federated community", async () => {
let betaCommunity = (await resolveBetaCommunity(alpha)).community.unwrap();
- let follow = await followCommunity(alpha, true, betaCommunity.community.id);
+ await followCommunity(alpha, true, betaCommunity.community.id);
+ betaCommunity = (await resolveBetaCommunity(alpha)).community.unwrap();
// Make sure the follow response went through
- expect(follow.community_view.community.local).toBe(false);
- expect(follow.community_view.community.name).toBe("main");
- expect(follow.community_view.subscribed).toBe(SubscribedType.Subscribed);
+ expect(betaCommunity.community.local).toBe(false);
+ expect(betaCommunity.community.name).toBe("main");
+ expect(betaCommunity.subscribed).toBe(SubscribedType.Subscribed);
// Check it from local
let site = await getSite(alpha);
doctest = false
[dependencies]
-lemmy_apub = { workspace = true }
lemmy_utils = { workspace = true }
lemmy_db_schema = { workspace = true, features = ["full"] }
lemmy_db_views = { workspace = true, features = ["full"] }
lemmy_db_views_moderator = { workspace = true, features = ["full"] }
lemmy_db_views_actor = { workspace = true, features = ["full"] }
lemmy_api_common = { workspace = true, features = ["full"] }
-activitypub_federation = { workspace = true }
diesel = { workspace = true }
bcrypt = { workspace = true }
chrono = { workspace = true }
use actix_web::web::Data;
use lemmy_api_common::{
comment::{CommentResponse, CreateCommentLike},
+ context::LemmyContext,
utils::{check_community_ban, check_downvotes_enabled, get_local_user_view_from_jwt},
websocket::{send::send_comment_ws_message, UserOperation},
- LemmyContext,
-};
-use lemmy_apub::{
- fetcher::post_or_comment::PostOrComment,
- protocol::activities::voting::{
- undo_vote::UndoVote,
- vote::{Vote, VoteType},
- },
};
use lemmy_db_schema::{
newtypes::LocalUserId,
};
use lemmy_db_views::structs::{CommentView, LocalUserView};
use lemmy_utils::{error::LemmyError, ConnectionId};
-use std::convert::TryInto;
#[async_trait::async_trait(?Send)]
impl Perform for CreateCommentLike {
CommentLike::remove(context.pool(), person_id, comment_id).await?;
// Only add the like if the score isnt 0
- let comment = orig_comment.comment;
- let object = PostOrComment::Comment(Box::new(comment.into()));
let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
if do_add {
let like_form2 = like_form.clone();
CommentLike::like(context.pool(), &like_form2)
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_like_comment"))?;
-
- Vote::send(
- &object,
- &local_user_view.person.clone().into(),
- orig_comment.community.id,
- like_form.score.try_into()?,
- context,
- )
- .await?;
- } else {
- // API doesn't distinguish between Undo/Like and Undo/Dislike
- UndoVote::send(
- &object,
- &local_user_view.person.clone().into(),
- orig_comment.community.id,
- VoteType::Like,
- context,
- )
- .await?;
}
send_comment_ws_message(
use actix_web::web::Data;
use lemmy_api_common::{
comment::{CommentResponse, SaveComment},
+ context::LemmyContext,
utils::get_local_user_view_from_jwt,
- LemmyContext,
};
use lemmy_db_schema::{
source::comment::{CommentSaved, CommentSavedForm},
use crate::{check_report_reason, Perform};
-use activitypub_federation::core::object_id::ObjectId;
use actix_web::web::Data;
use lemmy_api_common::{
comment::{CommentReportResponse, CreateCommentReport},
+ context::LemmyContext,
utils::{check_community_ban, get_local_user_view_from_jwt},
websocket::{messages::SendModRoomMessage, UserOperation},
- LemmyContext,
};
-use lemmy_apub::protocol::activities::community::report::Report;
use lemmy_db_schema::{
source::{
comment_report::{CommentReport, CommentReportForm},
websocket_id,
});
- Report::send(
- ObjectId::new(comment_view.comment.ap_id),
- &local_user_view.person.into(),
- ObjectId::new(comment_view.community.actor_id),
- reason.to_string(),
- context,
- )
- .await?;
-
Ok(res)
}
}
use actix_web::web::Data;
use lemmy_api_common::{
comment::{ListCommentReports, ListCommentReportsResponse},
+ context::LemmyContext,
utils::get_local_user_view_from_jwt,
- LemmyContext,
};
use lemmy_db_views::comment_report_view::CommentReportQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use actix_web::web::Data;
use lemmy_api_common::{
comment::{CommentReportResponse, ResolveCommentReport},
+ context::LemmyContext,
utils::{get_local_user_view_from_jwt, is_mod_or_admin},
websocket::{messages::SendModRoomMessage, UserOperation},
- LemmyContext,
};
use lemmy_db_schema::{source::comment_report::CommentReport, traits::Reportable};
use lemmy_db_views::structs::CommentReportView;
use actix_web::web::Data;
use lemmy_api_common::{
community::{AddModToCommunity, AddModToCommunityResponse},
+ context::LemmyContext,
utils::{get_local_user_view_from_jwt, is_mod_or_admin},
websocket::{messages::SendCommunityRoomMessage, UserOperation},
- LemmyContext,
-};
-use lemmy_apub::{
- objects::{community::ApubCommunity, person::ApubPerson},
- protocol::activities::community::{add_mod::AddMod, remove_mod::RemoveMod},
};
use lemmy_db_schema::{
source::{
community::{Community, CommunityModerator, CommunityModeratorForm},
moderator::{ModAddCommunity, ModAddCommunityForm},
- person::Person,
},
traits::{Crud, Joinable},
};
ModAddCommunity::create(context.pool(), &form).await?;
- // Send to federated instances
- let updated_mod_id = data.person_id;
- let updated_mod: ApubPerson = Person::read(context.pool(), updated_mod_id).await?.into();
- let community: ApubCommunity = community.into();
- if data.added {
- AddMod::send(
- &community,
- &updated_mod,
- &local_user_view.person.into(),
- context,
- )
- .await?;
- } else {
- RemoveMod::send(
- &community,
- &updated_mod,
- &local_user_view.person.into(),
- context,
- )
- .await?;
- }
-
// Note: in case a remote mod is added, this returns the old moderators list, it will only get
// updated once we receive an activity from the community (like `Announce/Add/Moderator`)
let community_id = data.community_id;
use actix_web::web::Data;
use lemmy_api_common::{
community::{BanFromCommunity, BanFromCommunityResponse},
+ context::LemmyContext,
utils::{get_local_user_view_from_jwt, is_mod_or_admin, remove_user_data_in_community},
websocket::{messages::SendCommunityRoomMessage, UserOperation},
- LemmyContext,
-};
-use lemmy_apub::{
- activities::block::SiteOrCommunity,
- objects::{community::ApubCommunity, person::ApubPerson},
- protocol::activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
};
use lemmy_db_schema::{
source::{
community::{
- Community,
CommunityFollower,
CommunityFollowerForm,
CommunityPersonBan,
CommunityPersonBanForm,
},
moderator::{ModBanFromCommunity, ModBanFromCommunityForm},
- person::Person,
},
traits::{Bannable, Crud, Followable},
};
expires: Some(expires),
};
- let community: ApubCommunity = Community::read(context.pool(), community_id).await?.into();
- let banned_person: ApubPerson = Person::read(context.pool(), banned_person_id).await?.into();
-
if data.ban {
CommunityPersonBan::ban(context.pool(), &community_user_ban_form)
.await
CommunityFollower::unfollow(context.pool(), &community_follower_form)
.await
.ok();
-
- BlockUser::send(
- &SiteOrCommunity::Community(community),
- &banned_person,
- &local_user_view.person.clone().into(),
- remove_data,
- data.reason.clone(),
- expires,
- context,
- )
- .await?;
} else {
CommunityPersonBan::unban(context.pool(), &community_user_ban_form)
.await
.map_err(|e| LemmyError::from_error_message(e, "community_user_already_banned"))?;
- UndoBlockUser::send(
- &SiteOrCommunity::Community(community),
- &banned_person,
- &local_user_view.person.clone().into(),
- data.reason.clone(),
- context,
- )
- .await?;
}
// Remove/Restore their data if that's desired
use actix_web::web::Data;
use lemmy_api_common::{
community::{BlockCommunity, BlockCommunityResponse},
+ context::LemmyContext,
utils::get_local_user_view_from_jwt,
- LemmyContext,
};
-use lemmy_apub::protocol::activities::following::undo_follow::UndoFollow;
use lemmy_db_schema::{
source::{
- community::{Community, CommunityFollower, CommunityFollowerForm},
+ community::{CommunityFollower, CommunityFollowerForm},
community_block::{CommunityBlock, CommunityBlockForm},
},
- traits::{Blockable, Crud, Followable},
+ traits::{Blockable, Followable},
};
use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{error::LemmyError, ConnectionId};
CommunityFollower::unfollow(context.pool(), &community_follower_form)
.await
.ok();
- let community = Community::read(context.pool(), community_id).await?;
- UndoFollow::send(&local_user_view.person.into(), &community.into(), context).await?;
} else {
CommunityBlock::unblock(context.pool(), &community_block_form)
.await
use actix_web::web::Data;
use lemmy_api_common::{
community::{CommunityResponse, FollowCommunity},
+ context::LemmyContext,
utils::{check_community_ban, check_community_deleted_or_removed, get_local_user_view_from_jwt},
- LemmyContext,
-};
-use lemmy_apub::{
- objects::community::ApubCommunity,
- protocol::activities::following::{
- follow::Follow as FollowCommunityApub,
- undo_follow::UndoFollow,
- },
};
use lemmy_db_schema::{
source::community::{Community, CommunityFollower, CommunityFollowerForm},
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let community_id = data.community_id;
- let community: ApubCommunity = Community::read(context.pool(), community_id).await?.into();
+ let community = Community::read(context.pool(), community_id).await?;
let community_follower_form = CommunityFollowerForm {
community_id: data.community_id,
person_id: local_user_view.person.id,
pending: false,
};
- if community.local {
- if data.follow {
- check_community_ban(local_user_view.person.id, community_id, context.pool()).await?;
- check_community_deleted_or_removed(community_id, context.pool()).await?;
+ if community.local && data.follow {
+ check_community_ban(local_user_view.person.id, community_id, context.pool()).await?;
+ check_community_deleted_or_removed(community_id, context.pool()).await?;
- CommunityFollower::follow(context.pool(), &community_follower_form)
- .await
- .map_err(|e| LemmyError::from_error_message(e, "community_follower_already_exists"))?;
- } else {
- CommunityFollower::unfollow(context.pool(), &community_follower_form)
- .await
- .map_err(|e| LemmyError::from_error_message(e, "community_follower_already_exists"))?;
- }
- } else if data.follow {
- // Dont actually add to the community followers here, because you need
- // to wait for the accept
- FollowCommunityApub::send(&local_user_view.person.clone().into(), &community, context)
- .await?;
- } else {
- UndoFollow::send(&local_user_view.person.clone().into(), &community, context).await?;
+ CommunityFollower::follow(context.pool(), &community_follower_form)
+ .await
+ .map_err(|e| LemmyError::from_error_message(e, "community_follower_already_exists"))?;
+ }
+ if !data.follow {
CommunityFollower::unfollow(context.pool(), &community_follower_form)
.await
.map_err(|e| LemmyError::from_error_message(e, "community_follower_already_exists"))?;
use actix_web::web::Data;
use lemmy_api_common::{
community::{CommunityResponse, HideCommunity},
+ context::LemmyContext,
utils::{get_local_user_view_from_jwt, is_admin},
websocket::{send::send_community_ws_message, UserOperationCrud},
- LemmyContext,
};
-use lemmy_apub::protocol::activities::community::update::UpdateCommunity;
use lemmy_db_schema::{
source::{
community::{Community, CommunityUpdateForm},
};
let community_id = data.community_id;
- let updated_community = Community::update(context.pool(), community_id, &community_form)
+ Community::update(context.pool(), community_id, &community_form)
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_community_hidden_status"))?;
ModHideCommunity::create(context.pool(), &mod_hide_community_form).await?;
- UpdateCommunity::send(
- updated_community.into(),
- &local_user_view.person.into(),
- context,
- )
- .await?;
-
let op = UserOperationCrud::EditCommunity;
send_community_ws_message(data.community_id, op, websocket_id, None, context).await
}
use anyhow::Context;
use lemmy_api_common::{
community::{GetCommunityResponse, TransferCommunity},
+ context::LemmyContext,
utils::get_local_user_view_from_jwt,
- LemmyContext,
};
use lemmy_db_schema::{
source::{
-use actix_web::{web, web::Data};
+use actix_web::web::Data;
use captcha::Captcha;
-use lemmy_api_common::{
- comment::{
- CreateCommentLike,
- CreateCommentReport,
- ListCommentReports,
- ResolveCommentReport,
- SaveComment,
- },
- community::{
- AddModToCommunity,
- BanFromCommunity,
- BlockCommunity,
- FollowCommunity,
- TransferCommunity,
- },
- person::{
- AddAdmin,
- BanPerson,
- BlockPerson,
- ChangePassword,
- GetBannedPersons,
- GetCaptcha,
- GetPersonMentions,
- GetReplies,
- GetReportCount,
- GetUnreadCount,
- Login,
- MarkAllAsRead,
- MarkCommentReplyAsRead,
- MarkPersonMentionAsRead,
- PasswordChangeAfterReset,
- PasswordReset,
- SaveUserSettings,
- VerifyEmail,
- },
- post::{
- CreatePostLike,
- CreatePostReport,
- GetSiteMetadata,
- ListPostReports,
- LockPost,
- MarkPostAsRead,
- ResolvePostReport,
- SavePost,
- StickyPost,
- },
- private_message::{
- CreatePrivateMessageReport,
- ListPrivateMessageReports,
- MarkPrivateMessageAsRead,
- ResolvePrivateMessageReport,
- },
- site::{
- ApproveRegistrationApplication,
- GetModlog,
- GetUnreadRegistrationApplicationCount,
- LeaveAdmin,
- ListRegistrationApplications,
- PurgeComment,
- PurgeCommunity,
- PurgePerson,
- PurgePost,
- ResolveObject,
- Search,
- },
- utils::local_site_to_slur_regex,
- websocket::{
- serialize_websocket_message,
- structs::{CommunityJoin, ModJoin, PostJoin, UserJoin},
- UserOperation,
- },
- LemmyContext,
-};
+use lemmy_api_common::{context::LemmyContext, utils::local_site_to_slur_regex};
use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_utils::{error::LemmyError, utils::check_slurs, ConnectionId};
-use serde::Deserialize;
mod comment;
mod comment_report;
) -> Result<Self::Response, LemmyError>;
}
-pub async fn match_websocket_operation(
- context: LemmyContext,
- id: ConnectionId,
- op: UserOperation,
- data: &str,
-) -> Result<String, LemmyError> {
- match op {
- // User ops
- UserOperation::Login => do_websocket_operation::<Login>(context, id, op, data).await,
- UserOperation::GetCaptcha => do_websocket_operation::<GetCaptcha>(context, id, op, data).await,
- UserOperation::GetReplies => do_websocket_operation::<GetReplies>(context, id, op, data).await,
- UserOperation::AddAdmin => do_websocket_operation::<AddAdmin>(context, id, op, data).await,
- UserOperation::GetUnreadRegistrationApplicationCount => {
- do_websocket_operation::<GetUnreadRegistrationApplicationCount>(context, id, op, data).await
- }
- UserOperation::ListRegistrationApplications => {
- do_websocket_operation::<ListRegistrationApplications>(context, id, op, data).await
- }
- UserOperation::ApproveRegistrationApplication => {
- do_websocket_operation::<ApproveRegistrationApplication>(context, id, op, data).await
- }
- UserOperation::BanPerson => do_websocket_operation::<BanPerson>(context, id, op, data).await,
- UserOperation::GetBannedPersons => {
- do_websocket_operation::<GetBannedPersons>(context, id, op, data).await
- }
- UserOperation::BlockPerson => {
- do_websocket_operation::<BlockPerson>(context, id, op, data).await
- }
- UserOperation::GetPersonMentions => {
- do_websocket_operation::<GetPersonMentions>(context, id, op, data).await
- }
- UserOperation::MarkPersonMentionAsRead => {
- do_websocket_operation::<MarkPersonMentionAsRead>(context, id, op, data).await
- }
- UserOperation::MarkCommentReplyAsRead => {
- do_websocket_operation::<MarkCommentReplyAsRead>(context, id, op, data).await
- }
- UserOperation::MarkAllAsRead => {
- do_websocket_operation::<MarkAllAsRead>(context, id, op, data).await
- }
- UserOperation::PasswordReset => {
- do_websocket_operation::<PasswordReset>(context, id, op, data).await
- }
- UserOperation::PasswordChange => {
- do_websocket_operation::<PasswordChangeAfterReset>(context, id, op, data).await
- }
- UserOperation::UserJoin => do_websocket_operation::<UserJoin>(context, id, op, data).await,
- UserOperation::PostJoin => do_websocket_operation::<PostJoin>(context, id, op, data).await,
- UserOperation::CommunityJoin => {
- do_websocket_operation::<CommunityJoin>(context, id, op, data).await
- }
- UserOperation::ModJoin => do_websocket_operation::<ModJoin>(context, id, op, data).await,
- UserOperation::SaveUserSettings => {
- do_websocket_operation::<SaveUserSettings>(context, id, op, data).await
- }
- UserOperation::ChangePassword => {
- do_websocket_operation::<ChangePassword>(context, id, op, data).await
- }
- UserOperation::GetReportCount => {
- do_websocket_operation::<GetReportCount>(context, id, op, data).await
- }
- UserOperation::GetUnreadCount => {
- do_websocket_operation::<GetUnreadCount>(context, id, op, data).await
- }
- UserOperation::VerifyEmail => {
- do_websocket_operation::<VerifyEmail>(context, id, op, data).await
- }
-
- // Private Message ops
- UserOperation::MarkPrivateMessageAsRead => {
- do_websocket_operation::<MarkPrivateMessageAsRead>(context, id, op, data).await
- }
- UserOperation::CreatePrivateMessageReport => {
- do_websocket_operation::<CreatePrivateMessageReport>(context, id, op, data).await
- }
- UserOperation::ResolvePrivateMessageReport => {
- do_websocket_operation::<ResolvePrivateMessageReport>(context, id, op, data).await
- }
- UserOperation::ListPrivateMessageReports => {
- do_websocket_operation::<ListPrivateMessageReports>(context, id, op, data).await
- }
-
- // Site ops
- UserOperation::GetModlog => do_websocket_operation::<GetModlog>(context, id, op, data).await,
- UserOperation::PurgePerson => {
- do_websocket_operation::<PurgePerson>(context, id, op, data).await
- }
- UserOperation::PurgeCommunity => {
- do_websocket_operation::<PurgeCommunity>(context, id, op, data).await
- }
- UserOperation::PurgePost => do_websocket_operation::<PurgePost>(context, id, op, data).await,
- UserOperation::PurgeComment => {
- do_websocket_operation::<PurgeComment>(context, id, op, data).await
- }
- UserOperation::Search => do_websocket_operation::<Search>(context, id, op, data).await,
- UserOperation::ResolveObject => {
- do_websocket_operation::<ResolveObject>(context, id, op, data).await
- }
- UserOperation::TransferCommunity => {
- do_websocket_operation::<TransferCommunity>(context, id, op, data).await
- }
- UserOperation::LeaveAdmin => do_websocket_operation::<LeaveAdmin>(context, id, op, data).await,
-
- // Community ops
- UserOperation::FollowCommunity => {
- do_websocket_operation::<FollowCommunity>(context, id, op, data).await
- }
- UserOperation::BlockCommunity => {
- do_websocket_operation::<BlockCommunity>(context, id, op, data).await
- }
- UserOperation::BanFromCommunity => {
- do_websocket_operation::<BanFromCommunity>(context, id, op, data).await
- }
- UserOperation::AddModToCommunity => {
- do_websocket_operation::<AddModToCommunity>(context, id, op, data).await
- }
-
- // Post ops
- UserOperation::LockPost => do_websocket_operation::<LockPost>(context, id, op, data).await,
- UserOperation::StickyPost => do_websocket_operation::<StickyPost>(context, id, op, data).await,
- UserOperation::CreatePostLike => {
- do_websocket_operation::<CreatePostLike>(context, id, op, data).await
- }
- UserOperation::MarkPostAsRead => {
- do_websocket_operation::<MarkPostAsRead>(context, id, op, data).await
- }
- UserOperation::SavePost => do_websocket_operation::<SavePost>(context, id, op, data).await,
- UserOperation::CreatePostReport => {
- do_websocket_operation::<CreatePostReport>(context, id, op, data).await
- }
- UserOperation::ListPostReports => {
- do_websocket_operation::<ListPostReports>(context, id, op, data).await
- }
- UserOperation::ResolvePostReport => {
- do_websocket_operation::<ResolvePostReport>(context, id, op, data).await
- }
- UserOperation::GetSiteMetadata => {
- do_websocket_operation::<GetSiteMetadata>(context, id, op, data).await
- }
-
- // Comment ops
- UserOperation::SaveComment => {
- do_websocket_operation::<SaveComment>(context, id, op, data).await
- }
- UserOperation::CreateCommentLike => {
- do_websocket_operation::<CreateCommentLike>(context, id, op, data).await
- }
- UserOperation::CreateCommentReport => {
- do_websocket_operation::<CreateCommentReport>(context, id, op, data).await
- }
- UserOperation::ListCommentReports => {
- do_websocket_operation::<ListCommentReports>(context, id, op, data).await
- }
- UserOperation::ResolveCommentReport => {
- do_websocket_operation::<ResolveCommentReport>(context, id, op, data).await
- }
- }
-}
-
-async fn do_websocket_operation<'a, 'b, Data>(
- context: LemmyContext,
- id: ConnectionId,
- op: UserOperation,
- data: &str,
-) -> Result<String, LemmyError>
-where
- for<'de> Data: Deserialize<'de> + 'a,
- Data: Perform,
-{
- let parsed_data: Data = serde_json::from_str(data)?;
- let res = parsed_data
- .perform(&web::Data::new(context), Some(id))
- .await?;
- serialize_websocket_message(&op, &res)
-}
-
/// Converts the captcha to a base64 encoded wav audio file
pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> String {
let letters = captcha.as_wav();
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{AddAdmin, AddAdminResponse},
utils::{get_local_user_view_from_jwt, is_admin},
websocket::{messages::SendAllMessage, UserOperation},
- LemmyContext,
};
use lemmy_db_schema::{
source::{
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{BanPerson, BanPersonResponse},
utils::{get_local_user_view_from_jwt, is_admin, remove_user_data},
websocket::{messages::SendAllMessage, UserOperation},
- LemmyContext,
-};
-use lemmy_apub::{
- activities::block::SiteOrCommunity,
- protocol::activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
};
use lemmy_db_schema::{
source::{
},
traits::Crud,
};
-use lemmy_db_views::structs::SiteView;
use lemmy_db_views_actor::structs::PersonViewSafe;
use lemmy_utils::{error::LemmyError, utils::naive_from_unix, ConnectionId};
let person_id = data.person_id;
let person_view = PersonViewSafe::read(context.pool(), person_id).await?;
- let site = SiteOrCommunity::Site(SiteView::read_local(context.pool()).await?.site.into());
- // if the action affects a local user, federate to other instances
- if person.local {
- if ban {
- BlockUser::send(
- &site,
- &person.into(),
- &local_user_view.person.into(),
- remove_data,
- data.reason.clone(),
- expires,
- context,
- )
- .await?;
- } else {
- UndoBlockUser::send(
- &site,
- &person.into(),
- &local_user_view.person.into(),
- data.reason.clone(),
- context,
- )
- .await?;
- }
- }
-
let res = BanPersonResponse {
person_view,
banned: data.ban,
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{BlockPerson, BlockPersonResponse},
utils::get_local_user_view_from_jwt,
- LemmyContext,
};
use lemmy_db_schema::{
source::person_block::{PersonBlock, PersonBlockForm},
use actix_web::web::Data;
use bcrypt::verify;
use lemmy_api_common::{
+ context::LemmyContext,
person::{ChangePassword, LoginResponse},
utils::{get_local_user_view_from_jwt, password_length_check},
- LemmyContext,
};
use lemmy_db_schema::source::local_user::LocalUser;
use lemmy_utils::{claims::Claims, error::LemmyError, ConnectionId};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{LoginResponse, PasswordChangeAfterReset},
utils::password_length_check,
- LemmyContext,
};
use lemmy_db_schema::source::{
local_user::LocalUser,
use captcha::{gen, Difficulty};
use chrono::Duration;
use lemmy_api_common::{
+ context::LemmyContext,
person::{CaptchaResponse, GetCaptcha, GetCaptchaResponse},
websocket::messages::CaptchaItem,
- LemmyContext,
};
use lemmy_db_schema::{source::local_site::LocalSite, utils::naive_now};
use lemmy_utils::{error::LemmyError, ConnectionId};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{BannedPersonsResponse, GetBannedPersons},
utils::{get_local_user_view_from_jwt, is_admin},
- LemmyContext,
};
use lemmy_db_views_actor::structs::PersonViewSafe;
use lemmy_utils::{error::LemmyError, ConnectionId};
use actix_web::web::Data;
use bcrypt::verify;
use lemmy_api_common::{
+ context::LemmyContext,
person::{Login, LoginResponse},
utils::{check_registration_application, check_user_valid},
- LemmyContext,
};
use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_db_views::structs::LocalUserView;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{GetPersonMentions, GetPersonMentionsResponse},
utils::get_local_user_view_from_jwt,
- LemmyContext,
};
use lemmy_db_views_actor::person_mention_view::PersonMentionQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{GetReplies, GetRepliesResponse},
utils::get_local_user_view_from_jwt,
- LemmyContext,
};
use lemmy_db_views_actor::comment_reply_view::CommentReplyQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{GetRepliesResponse, MarkAllAsRead},
utils::get_local_user_view_from_jwt,
- LemmyContext,
};
use lemmy_db_schema::source::{
comment_reply::CommentReply,
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{MarkPersonMentionAsRead, PersonMentionResponse},
utils::get_local_user_view_from_jwt,
- LemmyContext,
};
use lemmy_db_schema::{
source::person_mention::{PersonMention, PersonMentionUpdateForm},
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{CommentReplyResponse, MarkCommentReplyAsRead},
utils::get_local_user_view_from_jwt,
- LemmyContext,
};
use lemmy_db_schema::{
source::comment_reply::{CommentReply, CommentReplyUpdateForm},
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{GetUnreadCount, GetUnreadCountResponse},
utils::get_local_user_view_from_jwt,
- LemmyContext,
};
use lemmy_db_views::structs::PrivateMessageView;
use lemmy_db_views_actor::structs::{CommentReplyView, PersonMentionView};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{GetReportCount, GetReportCountResponse},
utils::get_local_user_view_from_jwt,
- LemmyContext,
};
use lemmy_db_views::structs::{CommentReportView, PostReportView, PrivateMessageReportView};
use lemmy_utils::{error::LemmyError, ConnectionId};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{PasswordReset, PasswordResetResponse},
utils::send_password_reset_email,
- LemmyContext,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{LoginResponse, SaveUserSettings},
utils::{get_local_user_view_from_jwt, send_verification_email},
- LemmyContext,
};
use lemmy_db_schema::{
source::{
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{VerifyEmail, VerifyEmailResponse},
utils::send_email_verification_success,
- LemmyContext,
};
use lemmy_db_schema::{
source::{
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
post::{GetSiteMetadata, GetSiteMetadataResponse},
request::fetch_site_metadata,
- LemmyContext,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
post::{CreatePostLike, PostResponse},
utils::{
check_community_ban,
mark_post_as_read,
},
websocket::{send::send_post_ws_message, UserOperation},
- LemmyContext,
-};
-use lemmy_apub::{
- fetcher::post_or_comment::PostOrComment,
- objects::post::ApubPost,
- protocol::activities::voting::{
- undo_vote::UndoVote,
- vote::{Vote, VoteType},
- },
};
use lemmy_db_schema::{
source::{
// Check for a community ban
let post_id = data.post_id;
- let post: ApubPost = Post::read(context.pool(), post_id).await?.into();
+ let post = Post::read(context.pool(), post_id).await?;
check_community_ban(local_user_view.person.id, post.community_id, context.pool()).await?;
check_community_deleted_or_removed(post.community_id, context.pool()).await?;
PostLike::remove(context.pool(), person_id, post_id).await?;
- let community_id = post.community_id;
- let object = PostOrComment::Post(Box::new(post));
-
// Only add the like if the score isnt 0
let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
if do_add {
PostLike::like(context.pool(), &like_form2)
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_like_post"))?;
-
- Vote::send(
- &object,
- &local_user_view.person.clone().into(),
- community_id,
- like_form.score.try_into()?,
- context,
- )
- .await?;
- } else {
- // API doesn't distinguish between Undo/Like and Undo/Dislike
- UndoVote::send(
- &object,
- &local_user_view.person.clone().into(),
- community_id,
- VoteType::Like,
- context,
- )
- .await?;
}
// Mark the post as read
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
post::{LockPost, PostResponse},
utils::{
check_community_ban,
is_mod_or_admin,
},
websocket::{send::send_post_ws_message, UserOperation},
- LemmyContext,
-};
-use lemmy_apub::{
- objects::post::ApubPost,
- protocol::activities::{create_or_update::page::CreateOrUpdatePage, CreateOrUpdateType},
};
use lemmy_db_schema::{
source::{
// Update the post
let post_id = data.post_id;
let locked = data.locked;
- let updated_post: ApubPost = Post::update(
+ Post::update(
context.pool(),
post_id,
&PostUpdateForm::builder().locked(Some(locked)).build(),
)
- .await?
- .into();
+ .await?;
// Mod tables
let form = ModLockPostForm {
};
ModLockPost::create(context.pool(), &form).await?;
- // apub updates
- CreateOrUpdatePage::send(
- updated_post,
- &local_user_view.person.clone().into(),
- CreateOrUpdateType::Update,
- context,
- )
- .await?;
-
send_post_ws_message(
data.post_id,
UserOperation::LockPost,
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
post::{MarkPostAsRead, PostResponse},
utils::{get_local_user_view_from_jwt, mark_post_as_read, mark_post_as_unread},
- LemmyContext,
};
use lemmy_db_views::structs::PostView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
post::{PostResponse, SavePost},
utils::{get_local_user_view_from_jwt, mark_post_as_read},
- LemmyContext,
};
use lemmy_db_schema::{
source::post::{PostSaved, PostSavedForm},
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
post::{PostResponse, StickyPost},
utils::{
check_community_ban,
is_mod_or_admin,
},
websocket::{send::send_post_ws_message, UserOperation},
- LemmyContext,
-};
-use lemmy_apub::{
- objects::post::ApubPost,
- protocol::activities::{create_or_update::page::CreateOrUpdatePage, CreateOrUpdateType},
};
use lemmy_db_schema::{
source::{
// Update the post
let post_id = data.post_id;
let stickied = data.stickied;
- let updated_post: ApubPost = Post::update(
+ Post::update(
context.pool(),
post_id,
&PostUpdateForm::builder().stickied(Some(stickied)).build(),
)
- .await?
- .into();
+ .await?;
// Mod tables
let form = ModStickyPostForm {
ModStickyPost::create(context.pool(), &form).await?;
- // Apub updates
- // TODO stickied should pry work like locked for ease of use
- CreateOrUpdatePage::send(
- updated_post,
- &local_user_view.person.clone().into(),
- CreateOrUpdateType::Update,
- context,
- )
- .await?;
-
send_post_ws_message(
data.post_id,
UserOperation::StickyPost,
use crate::{check_report_reason, Perform};
-use activitypub_federation::core::object_id::ObjectId;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
post::{CreatePostReport, PostReportResponse},
utils::{check_community_ban, get_local_user_view_from_jwt},
websocket::{messages::SendModRoomMessage, UserOperation},
- LemmyContext,
};
-use lemmy_apub::protocol::activities::community::report::Report;
use lemmy_db_schema::{
source::{
local_site::LocalSite,
websocket_id,
});
- Report::send(
- ObjectId::new(post_view.post.ap_id),
- &local_user_view.person.into(),
- ObjectId::new(post_view.community.actor_id),
- reason.to_string(),
- context,
- )
- .await?;
-
Ok(res)
}
}
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
post::{ListPostReports, ListPostReportsResponse},
utils::get_local_user_view_from_jwt,
- LemmyContext,
};
use lemmy_db_views::post_report_view::PostReportQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
post::{PostReportResponse, ResolvePostReport},
utils::{get_local_user_view_from_jwt, is_mod_or_admin},
websocket::{messages::SendModRoomMessage, UserOperation},
- LemmyContext,
};
use lemmy_db_schema::{source::post_report::PostReport, traits::Reportable};
use lemmy_db_views::structs::PostReportView;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
private_message::{MarkPrivateMessageAsRead, PrivateMessageResponse},
utils::get_local_user_view_from_jwt,
websocket::{send::send_pm_ws_message, UserOperation},
- LemmyContext,
};
use lemmy_db_schema::{
source::private_message::{PrivateMessage, PrivateMessageUpdateForm},
use crate::{check_report_reason, Perform};
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
private_message::{CreatePrivateMessageReport, PrivateMessageReportResponse},
utils::get_local_user_view_from_jwt,
websocket::{messages::SendModRoomMessage, UserOperation},
- LemmyContext,
};
use lemmy_db_schema::{
newtypes::CommunityId,
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
private_message::{ListPrivateMessageReports, ListPrivateMessageReportsResponse},
utils::{get_local_user_view_from_jwt, is_admin},
- LemmyContext,
};
use lemmy_db_views::private_message_report_view::PrivateMessageReportQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
private_message::{PrivateMessageReportResponse, ResolvePrivateMessageReport},
utils::{get_local_user_view_from_jwt, is_admin},
websocket::{messages::SendModRoomMessage, UserOperation},
- LemmyContext,
};
use lemmy_db_schema::{
newtypes::CommunityId,
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
site::{GetSiteResponse, LeaveAdmin},
utils::{get_local_user_view_from_jwt, is_admin},
- LemmyContext,
};
use lemmy_db_schema::{
source::{
mod mod_log;
mod purge;
mod registration_applications;
-mod resolve_object;
-mod search;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
site::{GetModlog, GetModlogResponse},
utils::{check_private_instance, get_local_user_view_from_jwt_opt, is_admin, is_mod_or_admin},
- LemmyContext,
};
use lemmy_db_schema::{
newtypes::{CommunityId, PersonId},
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
site::{PurgeComment, PurgeItemResponse},
utils::{get_local_user_view_from_jwt, is_admin},
- LemmyContext,
};
use lemmy_db_schema::{
source::{
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
request::purge_image_from_pictrs,
site::{PurgeCommunity, PurgeItemResponse},
utils::{get_local_user_view_from_jwt, is_admin, purge_image_posts_for_community},
- LemmyContext,
};
use lemmy_db_schema::{
source::{
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
request::purge_image_from_pictrs,
site::{PurgeItemResponse, PurgePerson},
utils::{get_local_user_view_from_jwt, is_admin, purge_image_posts_for_person},
- LemmyContext,
};
use lemmy_db_schema::{
source::{
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
request::purge_image_from_pictrs,
site::{PurgeItemResponse, PurgePost},
utils::{get_local_user_view_from_jwt, is_admin},
- LemmyContext,
};
use lemmy_db_schema::{
source::{
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
site::{ApproveRegistrationApplication, RegistrationApplicationResponse},
utils::{get_local_user_view_from_jwt, is_admin, send_application_approved_email},
- LemmyContext,
};
use lemmy_db_schema::{
source::{
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
site::{ListRegistrationApplications, ListRegistrationApplicationsResponse},
utils::{get_local_user_view_from_jwt, is_admin},
- LemmyContext,
};
use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_db_views::registration_application_view::RegistrationApplicationQuery;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
site::{GetUnreadRegistrationApplicationCount, GetUnreadRegistrationApplicationCountResponse},
utils::{get_local_user_view_from_jwt, is_admin},
- LemmyContext,
};
use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_db_views::structs::RegistrationApplicationView;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
utils::get_local_user_view_from_jwt,
websocket::{
messages::{JoinCommunityRoom, JoinModRoom, JoinPostRoom, JoinUserRoom},
UserJoinResponse,
},
},
- LemmyContext,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
--- /dev/null
+use crate::websocket::chat_server::ChatServer;
+use actix::Addr;
+use lemmy_db_schema::{source::secret::Secret, utils::DbPool};
+use lemmy_utils::{
+ rate_limit::RateLimitCell,
+ settings::{structs::Settings, SETTINGS},
+};
+use reqwest_middleware::ClientWithMiddleware;
+
+pub struct LemmyContext {
+ pool: DbPool,
+ chat_server: Addr<ChatServer>,
+ client: ClientWithMiddleware,
+ settings: Settings,
+ secret: Secret,
+ rate_limit_cell: RateLimitCell,
+}
+
+impl LemmyContext {
+ pub fn create(
+ pool: DbPool,
+ chat_server: Addr<ChatServer>,
+ client: ClientWithMiddleware,
+ settings: Settings,
+ secret: Secret,
+ rate_limit_cell: RateLimitCell,
+ ) -> LemmyContext {
+ LemmyContext {
+ pool,
+ chat_server,
+ client,
+ settings,
+ secret,
+ rate_limit_cell,
+ }
+ }
+ pub fn pool(&self) -> &DbPool {
+ &self.pool
+ }
+ pub fn chat_server(&self) -> &Addr<ChatServer> {
+ &self.chat_server
+ }
+ pub fn client(&self) -> &ClientWithMiddleware {
+ &self.client
+ }
+ pub fn settings(&self) -> &'static Settings {
+ &SETTINGS
+ }
+ pub fn secret(&self) -> &Secret {
+ &self.secret
+ }
+ pub fn settings_updated_channel(&self) -> &RateLimitCell {
+ &self.rate_limit_cell
+ }
+}
+
+impl Clone for LemmyContext {
+ fn clone(&self) -> Self {
+ LemmyContext {
+ pool: self.pool.clone(),
+ chat_server: self.chat_server.clone(),
+ client: self.client.clone(),
+ settings: self.settings.clone(),
+ secret: self.secret.clone(),
+ rate_limit_cell: self.rate_limit_cell.clone(),
+ }
+ }
+}
pub mod comment;
pub mod community;
+#[cfg(feature = "full")]
+pub mod context;
pub mod person;
pub mod post;
pub mod private_message;
pub mod site;
#[cfg(feature = "full")]
pub mod utils;
+#[cfg(feature = "full")]
pub mod websocket;
#[macro_use]
pub extern crate lemmy_db_views;
pub extern crate lemmy_db_views_actor;
pub extern crate lemmy_db_views_moderator;
-
-use crate::websocket::chat_server::ChatServer;
-use actix::Addr;
-use anyhow::Context;
-use lemmy_db_schema::{newtypes::DbUrl, source::secret::Secret, utils::DbPool};
-use lemmy_utils::{
- error::LemmyError,
- location_info,
- rate_limit::RateLimitCell,
- settings::{structs::Settings, SETTINGS},
-};
-use reqwest_middleware::ClientWithMiddleware;
-use url::{ParseError, Url};
-
-pub struct LemmyContext {
- pool: DbPool,
- chat_server: Addr<ChatServer>,
- client: ClientWithMiddleware,
- settings: Settings,
- secret: Secret,
- rate_limit_cell: RateLimitCell,
-}
-
-impl LemmyContext {
- pub fn create(
- pool: DbPool,
- chat_server: Addr<ChatServer>,
- client: ClientWithMiddleware,
- settings: Settings,
- secret: Secret,
- settings_updated_channel: RateLimitCell,
- ) -> LemmyContext {
- LemmyContext {
- pool,
- chat_server,
- client,
- settings,
- secret,
- rate_limit_cell: settings_updated_channel,
- }
- }
- pub fn pool(&self) -> &DbPool {
- &self.pool
- }
- pub fn chat_server(&self) -> &Addr<ChatServer> {
- &self.chat_server
- }
- pub fn client(&self) -> &ClientWithMiddleware {
- &self.client
- }
- pub fn settings(&self) -> &'static Settings {
- &SETTINGS
- }
- pub fn secret(&self) -> &Secret {
- &self.secret
- }
- pub fn settings_updated_channel(&self) -> &RateLimitCell {
- &self.rate_limit_cell
- }
-}
-
-impl Clone for LemmyContext {
- fn clone(&self) -> Self {
- LemmyContext {
- pool: self.pool.clone(),
- chat_server: self.chat_server.clone(),
- client: self.client.clone(),
- settings: self.settings.clone(),
- secret: self.secret.clone(),
- rate_limit_cell: self.rate_limit_cell.clone(),
- }
- }
-}
-
-pub enum EndpointType {
- Community,
- Person,
- Post,
- Comment,
- PrivateMessage,
-}
-
-/// Generates an apub endpoint for a given domain, IE xyz.tld
-pub fn generate_local_apub_endpoint(
- endpoint_type: EndpointType,
- name: &str,
- domain: &str,
-) -> Result<DbUrl, ParseError> {
- let point = match endpoint_type {
- EndpointType::Community => "c",
- EndpointType::Person => "u",
- EndpointType::Post => "post",
- EndpointType::Comment => "comment",
- EndpointType::PrivateMessage => "private_message",
- };
-
- Ok(Url::parse(&format!("{}/{}/{}", domain, point, name))?.into())
-}
-
-pub fn generate_followers_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
- Ok(Url::parse(&format!("{}/followers", actor_id))?.into())
-}
-
-pub fn generate_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
- Ok(Url::parse(&format!("{}/inbox", actor_id))?.into())
-}
-
-pub fn generate_site_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
- let mut actor_id: Url = actor_id.clone().into();
- actor_id.set_path("site_inbox");
- Ok(actor_id.into())
-}
-
-pub fn generate_shared_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, LemmyError> {
- let actor_id: Url = actor_id.clone().into();
- let url = format!(
- "{}://{}{}/inbox",
- &actor_id.scheme(),
- &actor_id.host_str().context(location_info!())?,
- if let Some(port) = actor_id.port() {
- format!(":{}", port)
- } else {
- String::new()
- },
- );
- Ok(Url::parse(&url)?.into())
-}
-
-pub fn generate_outbox_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
- Ok(Url::parse(&format!("{}/outbox", actor_id))?.into())
-}
-
-pub fn generate_moderators_url(community_id: &DbUrl) -> Result<DbUrl, LemmyError> {
- Ok(Url::parse(&format!("{}/moderators", community_id))?.into())
-}
pub private_messages: i64,
}
-#[derive(Serialize, Deserialize, Clone, Default)]
+#[derive(Serialize, Deserialize, Clone, Default, Debug)]
pub struct VerifyEmail {
pub token: String,
}
use crate::{request::purge_image_from_pictrs, sensitive::Sensitive, site::FederatedInstances};
+use anyhow::Context;
use chrono::NaiveDateTime;
use lemmy_db_schema::{
impls::person::is_banned,
- newtypes::{CommunityId, LocalUserId, PersonId, PostId},
+ newtypes::{CommunityId, DbUrl, LocalUserId, PersonId, PostId},
source::{
comment::{Comment, CommentUpdateForm},
community::{Community, CommunityUpdateForm},
claims::Claims,
email::{send_email, translations::Lang},
error::LemmyError,
+ location_info,
rate_limit::RateLimitConfig,
settings::structs::Settings,
utils::{build_slur_regex, generate_random_string},
use rosetta_i18n::{Language, LanguageId};
use std::str::FromStr;
use tracing::warn;
+use url::{ParseError, Url};
#[tracing::instrument(skip_all)]
pub async fn is_mod_or_admin(
assert!(honeypot_check(&Some("message".to_string())).is_err());
}
}
+
+pub enum EndpointType {
+ Community,
+ Person,
+ Post,
+ Comment,
+ PrivateMessage,
+}
+
+/// Generates an apub endpoint for a given domain, IE xyz.tld
+pub fn generate_local_apub_endpoint(
+ endpoint_type: EndpointType,
+ name: &str,
+ domain: &str,
+) -> Result<DbUrl, ParseError> {
+ let point = match endpoint_type {
+ EndpointType::Community => "c",
+ EndpointType::Person => "u",
+ EndpointType::Post => "post",
+ EndpointType::Comment => "comment",
+ EndpointType::PrivateMessage => "private_message",
+ };
+
+ Ok(Url::parse(&format!("{}/{}/{}", domain, point, name))?.into())
+}
+
+pub fn generate_followers_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
+ Ok(Url::parse(&format!("{}/followers", actor_id))?.into())
+}
+
+pub fn generate_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
+ Ok(Url::parse(&format!("{}/inbox", actor_id))?.into())
+}
+
+pub fn generate_site_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
+ let mut actor_id: Url = actor_id.clone().into();
+ actor_id.set_path("site_inbox");
+ Ok(actor_id.into())
+}
+
+pub fn generate_shared_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, LemmyError> {
+ let actor_id: Url = actor_id.clone().into();
+ let url = format!(
+ "{}://{}{}/inbox",
+ &actor_id.scheme(),
+ &actor_id.host_str().context(location_info!())?,
+ if let Some(port) = actor_id.port() {
+ format!(":{}", port)
+ } else {
+ String::new()
+ },
+ );
+ Ok(Url::parse(&url)?.into())
+}
+
+pub fn generate_outbox_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
+ Ok(Url::parse(&format!("{}/outbox", actor_id))?.into())
+}
+
+pub fn generate_moderators_url(community_id: &DbUrl) -> Result<DbUrl, LemmyError> {
+ Ok(Url::parse(&format!("{}/moderators", community_id))?.into())
+}
use crate::{
comment::CommentResponse,
+ context::LemmyContext,
post::PostResponse,
websocket::{
messages::{CaptchaItem, StandardMessage, WsMessage},
serialize_websocket_message,
OperationType,
UserOperation,
+ UserOperationApub,
UserOperationCrud,
},
- LemmyContext,
};
use actix::prelude::*;
use anyhow::Context as acontext;
data: &str,
) -> Pin<Box<dyn Future<Output = Result<String, LemmyError>> + '_>>;
+type MessageHandlerApubType = fn(
+ context: LemmyContext,
+ id: ConnectionId,
+ op: UserOperationApub,
+ data: &str,
+) -> Pin<Box<dyn Future<Output = Result<String, LemmyError>> + '_>>;
+
/// `ChatServer` manages chat rooms and responsible for coordinating chat
/// session.
pub struct ChatServer {
message_handler: MessageHandlerType,
message_handler_crud: MessageHandlerCrudType,
+ message_handler_apub: MessageHandlerApubType,
/// An HTTP Client
client: ClientWithMiddleware,
pool: DbPool,
message_handler: MessageHandlerType,
message_handler_crud: MessageHandlerCrudType,
+ message_handler_apub: MessageHandlerApubType,
client: ClientWithMiddleware,
settings: Settings,
secret: Secret,
captchas: Vec::new(),
message_handler,
message_handler_crud,
+ message_handler_apub,
client,
settings,
secret,
None => IpAddr("blank_ip".to_string()),
};
- let context = LemmyContext {
- pool: self.pool.clone(),
- chat_server: ctx.address(),
- client: self.client.clone(),
- settings: self.settings.clone(),
- secret: self.secret.clone(),
- rate_limit_cell: self.rate_limit_cell.clone(),
- };
+ let context = LemmyContext::create(
+ self.pool.clone(),
+ ctx.address(),
+ self.client.clone(),
+ self.settings.clone(),
+ self.secret.clone(),
+ self.rate_limit_cell.clone(),
+ );
let message_handler_crud = self.message_handler_crud;
let message_handler = self.message_handler;
+ let message_handler_apub = self.message_handler_apub;
let rate_limiter = self.rate_limit_cell.clone();
async move {
let json: Value = serde_json::from_str(&msg.msg)?;
};
let fut = (message_handler_crud)(context, msg.id, user_operation_crud, data);
(passed, fut)
- } else {
- let user_operation = UserOperation::from_str(op)?;
+ } else if let Ok(user_operation) = UserOperation::from_str(op) {
let passed = match user_operation {
UserOperation::GetCaptcha => rate_limiter.post().check(ip),
- UserOperation::Search => rate_limiter.search().check(ip),
_ => rate_limiter.message().check(ip),
};
let fut = (message_handler)(context, msg.id, user_operation, data);
(passed, fut)
+ } else {
+ let user_operation = UserOperationApub::from_str(op)?;
+ let passed = match user_operation {
+ UserOperationApub::Search => rate_limiter.search().check(ip),
+ _ => rate_limiter.message().check(ip),
+ };
+ let fut = (message_handler_apub)(context, msg.id, user_operation, data);
+ (passed, fut)
};
// if rate limit passed, execute api call future
ApproveRegistrationApplication,
BanPerson,
GetBannedPersons,
- Search,
- ResolveObject,
MarkAllAsRead,
SaveUserSettings,
TransferCommunity,
// Community
CreateCommunity,
ListCommunities,
- GetCommunity,
EditCommunity,
DeleteCommunity,
RemoveCommunity,
// Post
CreatePost,
GetPost,
- GetPosts,
EditPost,
DeletePost,
RemovePost,
// Comment
CreateComment,
GetComment,
- GetComments,
EditComment,
DeleteComment,
RemoveComment,
// User
Register,
- GetPersonDetails,
DeleteAccount,
// Private Message
CreatePrivateMessage,
DeletePrivateMessage,
}
+#[derive(EnumString, Display, Debug, Clone)]
+pub enum UserOperationApub {
+ GetPosts,
+ GetCommunity,
+ GetComments,
+ GetPersonDetails,
+ Search,
+ ResolveObject,
+}
+
pub trait OperationType {}
impl OperationType for UserOperationCrud {}
impl OperationType for UserOperation {}
+
+impl OperationType for UserOperationApub {}
use crate::{
+ context::LemmyContext,
websocket::{
chat_server::ChatServer,
messages::{Connect, Disconnect, StandardMessage, WsMessage},
},
- LemmyContext,
};
use actix::prelude::*;
use actix_web::{web, Error, HttpRequest, HttpResponse};
use crate::{
comment::CommentResponse,
community::CommunityResponse,
+ context::LemmyContext,
post::PostResponse,
private_message::PrivateMessageResponse,
utils::{check_person_block, get_interface_language, send_email_to_user},
messages::{SendComment, SendCommunityRoomMessage, SendPost, SendUserRoomMessage},
OperationType,
},
- LemmyContext,
};
use lemmy_db_schema::{
newtypes::{CommentId, CommunityId, LocalUserId, PersonId, PostId, PrivateMessageId},
repository.workspace = true
[dependencies]
-lemmy_apub = { workspace = true }
lemmy_utils = { workspace = true }
lemmy_db_schema = { workspace = true, features = ["full"] }
lemmy_db_views = { workspace = true, features = ["full"] }
use actix_web::web::Data;
use lemmy_api_common::{
comment::{CommentResponse, CreateComment},
- generate_local_apub_endpoint,
+ context::LemmyContext,
utils::{
check_community_ban,
check_community_deleted_or_removed,
check_post_deleted_or_removed,
+ generate_local_apub_endpoint,
get_local_user_view_from_jwt,
get_post,
local_site_to_slur_regex,
+ EndpointType,
},
websocket::{
send::{send_comment_ws_message, send_local_notifs},
UserOperationCrud,
},
- EndpointType,
- LemmyContext,
-};
-use lemmy_apub::{
- objects::comment::ApubComment,
- protocol::activities::{create_or_update::note::CreateOrUpdateNote, CreateOrUpdateType},
};
use lemmy_db_schema::{
source::{
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_like_comment"))?;
- let apub_comment: ApubComment = updated_comment.into();
- CreateOrUpdateNote::send(
- apub_comment.clone(),
- &local_user_view.person.clone().into(),
- CreateOrUpdateType::Create,
- context,
- &mut 0,
- )
- .await?;
-
// If its a reply, mark the parent as read
if let Some(parent) = parent_opt {
let parent_id = parent.id;
use actix_web::web::Data;
use lemmy_api_common::{
comment::{CommentResponse, DeleteComment},
+ context::LemmyContext,
utils::{check_community_ban, get_local_user_view_from_jwt},
websocket::{
send::{send_comment_ws_message, send_local_notifs},
UserOperationCrud,
},
- LemmyContext,
};
-use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
use lemmy_db_schema::{
source::{
comment::{Comment, CommentUpdateForm},
- community::Community,
post::Post,
},
traits::Crud,
)
.await?;
- // Send the apub message
- let community = Community::read(context.pool(), orig_comment.post.community_id).await?;
- let deletable = DeletableObjects::Comment(Box::new(updated_comment.clone().into()));
- send_apub_delete_in_community(
- local_user_view.person,
- community,
- deletable,
- None,
- deleted,
- context,
- )
- .await?;
-
Ok(res)
}
}
mod create;
mod delete;
-mod list;
mod read;
mod remove;
mod update;
use actix_web::web::Data;
use lemmy_api_common::{
comment::{CommentResponse, GetComment},
+ context::LemmyContext,
utils::{check_private_instance, get_local_user_view_from_jwt_opt},
- LemmyContext,
};
use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_db_views::structs::CommentView;
use actix_web::web::Data;
use lemmy_api_common::{
comment::{CommentResponse, RemoveComment},
+ context::LemmyContext,
utils::{check_community_ban, get_local_user_view_from_jwt, is_mod_or_admin},
websocket::{
send::{send_comment_ws_message, send_local_notifs},
UserOperationCrud,
},
- LemmyContext,
};
-use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
use lemmy_db_schema::{
source::{
comment::{Comment, CommentUpdateForm},
- community::Community,
moderator::{ModRemoveComment, ModRemoveCommentForm},
post::Post,
},
)
.await?;
- // Send the apub message
- let community = Community::read(context.pool(), orig_comment.post.community_id).await?;
- let deletable = DeletableObjects::Comment(Box::new(updated_comment.clone().into()));
- send_apub_delete_in_community(
- local_user_view.person,
- community,
- deletable,
- data.reason.clone().or_else(|| Some(String::new())),
- removed,
- context,
- )
- .await?;
-
Ok(res)
}
}
use actix_web::web::Data;
use lemmy_api_common::{
comment::{CommentResponse, EditComment},
+ context::LemmyContext,
utils::{
check_community_ban,
check_community_deleted_or_removed,
send::{send_comment_ws_message, send_local_notifs},
UserOperationCrud,
},
- LemmyContext,
-};
-use lemmy_apub::protocol::activities::{
- create_or_update::note::CreateOrUpdateNote,
- CreateOrUpdateType,
};
use lemmy_db_schema::{
source::{
)
.await?;
- // Send the apub update
- CreateOrUpdateNote::send(
- updated_comment.into(),
- &local_user_view.person.into(),
- CreateOrUpdateType::Update,
- context,
- &mut 0,
- )
- .await?;
-
send_comment_ws_message(
data.comment_id,
UserOperationCrud::EditComment,
use crate::PerformCrud;
-use activitypub_federation::core::{object_id::ObjectId, signatures::generate_actor_keypair};
+use activitypub_federation::core::signatures::generate_actor_keypair;
use actix_web::web::Data;
use lemmy_api_common::{
community::{CommunityResponse, CreateCommunity},
- generate_followers_url,
- generate_inbox_url,
- generate_local_apub_endpoint,
- generate_shared_inbox_url,
- utils::{get_local_user_view_from_jwt, is_admin, local_site_to_slur_regex},
- EndpointType,
- LemmyContext,
+ context::LemmyContext,
+ utils::{
+ generate_followers_url,
+ generate_inbox_url,
+ generate_local_apub_endpoint,
+ generate_shared_inbox_url,
+ get_local_user_view_from_jwt,
+ is_admin,
+ local_site_to_slur_regex,
+ EndpointType,
+ },
};
-use lemmy_apub::objects::community::ApubCommunity;
use lemmy_db_schema::{
source::community::{
Community,
CommunityModerator,
CommunityModeratorForm,
},
- traits::{Crud, Followable, Joinable},
+ traits::{ApubActor, Crud, Followable, Joinable},
utils::diesel_option_overwrite_to_url_create,
};
use lemmy_db_views::structs::SiteView;
&data.name,
&context.settings().get_protocol_and_hostname(),
)?;
- let community_actor_id_wrapped = ObjectId::<ApubCommunity>::new(community_actor_id.clone());
- let community_dupe = community_actor_id_wrapped.dereference_local(context).await;
- if community_dupe.is_ok() {
+ let community_dupe = Community::read_from_apub_id(context.pool(), &community_actor_id).await?;
+ if community_dupe.is_some() {
return Err(LemmyError::from_message("community_already_exists"));
}
use actix_web::web::Data;
use lemmy_api_common::{
community::{CommunityResponse, DeleteCommunity},
+ context::LemmyContext,
utils::get_local_user_view_from_jwt,
websocket::{send::send_community_ws_message, UserOperationCrud},
- LemmyContext,
};
-use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
use lemmy_db_schema::{
source::community::{Community, CommunityUpdateForm},
traits::Crud,
// Do the delete
let community_id = data.community_id;
let deleted = data.deleted;
- let updated_community = Community::update(
+ Community::update(
context.pool(),
community_id,
&CommunityUpdateForm::builder()
)
.await?;
- // Send apub messages
- let deletable = DeletableObjects::Community(Box::new(updated_community.clone().into()));
- send_apub_delete_in_community(
- local_user_view.person,
- updated_community,
- deletable,
- None,
- deleted,
- context,
- )
- .await?;
-
Ok(res)
}
}
use actix_web::web::Data;
use lemmy_api_common::{
community::{ListCommunities, ListCommunitiesResponse},
+ context::LemmyContext,
utils::{check_private_instance, get_local_user_view_from_jwt_opt},
- LemmyContext,
};
use lemmy_db_schema::{source::local_site::LocalSite, traits::DeleteableOrRemoveable};
use lemmy_db_views_actor::community_view::CommunityQuery;
mod create;
mod delete;
mod list;
-mod read;
mod remove;
mod update;
use actix_web::web::Data;
use lemmy_api_common::{
community::{CommunityResponse, RemoveCommunity},
+ context::LemmyContext,
utils::{get_local_user_view_from_jwt, is_admin},
websocket::{send::send_community_ws_message, UserOperationCrud},
- LemmyContext,
};
-use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
use lemmy_db_schema::{
source::{
community::{Community, CommunityUpdateForm},
// Do the remove
let community_id = data.community_id;
let removed = data.removed;
- let updated_community = Community::update(
+ Community::update(
context.pool(),
community_id,
&CommunityUpdateForm::builder()
)
.await?;
- // Apub messages
- let deletable = DeletableObjects::Community(Box::new(updated_community.clone().into()));
- send_apub_delete_in_community(
- local_user_view.person,
- updated_community,
- deletable,
- data.reason.clone().or_else(|| Some(String::new())),
- removed,
- context,
- )
- .await?;
Ok(res)
}
}
use actix_web::web::Data;
use lemmy_api_common::{
community::{CommunityResponse, EditCommunity},
+ context::LemmyContext,
utils::{get_local_user_view_from_jwt, local_site_to_slur_regex},
websocket::{send::send_community_ws_message, UserOperationCrud},
- LemmyContext,
};
-use lemmy_apub::protocol::activities::community::update::UpdateCommunity;
use lemmy_db_schema::{
newtypes::PersonId,
source::{
.build();
let community_id = data.community_id;
- let updated_community = Community::update(context.pool(), community_id, &community_form)
+ Community::update(context.pool(), community_id, &community_form)
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_community"))?;
- UpdateCommunity::send(
- updated_community.into(),
- &local_user_view.person.into(),
- context,
- )
- .await?;
-
let op = UserOperationCrud::EditCommunity;
send_community_ws_message(data.community_id, op, websocket_id, None, context).await
}
-use actix_web::{web, web::Data};
-use lemmy_api_common::{
- comment::{CreateComment, DeleteComment, EditComment, GetComment, GetComments, RemoveComment},
- community::{
- CreateCommunity,
- DeleteCommunity,
- EditCommunity,
- GetCommunity,
- ListCommunities,
- RemoveCommunity,
- },
- person::{DeleteAccount, GetPersonDetails, Register},
- post::{CreatePost, DeletePost, EditPost, GetPost, GetPosts, RemovePost},
- private_message::{
- CreatePrivateMessage,
- DeletePrivateMessage,
- EditPrivateMessage,
- GetPrivateMessages,
- },
- site::{CreateSite, EditSite, GetSite},
- websocket::{serialize_websocket_message, UserOperationCrud},
- LemmyContext,
-};
+use actix_web::web::Data;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::{error::LemmyError, ConnectionId};
-use serde::Deserialize;
mod comment;
mod community;
websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError>;
}
-
-pub async fn match_websocket_operation_crud(
- context: LemmyContext,
- id: ConnectionId,
- op: UserOperationCrud,
- data: &str,
-) -> Result<String, LemmyError> {
- //TODO: handle commented out actions in crud crate
-
- match op {
- // User ops
- UserOperationCrud::Register => do_websocket_operation::<Register>(context, id, op, data).await,
- UserOperationCrud::GetPersonDetails => {
- do_websocket_operation::<GetPersonDetails>(context, id, op, data).await
- }
- UserOperationCrud::DeleteAccount => {
- do_websocket_operation::<DeleteAccount>(context, id, op, data).await
- }
-
- // Private Message ops
- UserOperationCrud::CreatePrivateMessage => {
- do_websocket_operation::<CreatePrivateMessage>(context, id, op, data).await
- }
- UserOperationCrud::EditPrivateMessage => {
- do_websocket_operation::<EditPrivateMessage>(context, id, op, data).await
- }
- UserOperationCrud::DeletePrivateMessage => {
- do_websocket_operation::<DeletePrivateMessage>(context, id, op, data).await
- }
- UserOperationCrud::GetPrivateMessages => {
- do_websocket_operation::<GetPrivateMessages>(context, id, op, data).await
- }
-
- // Site ops
- UserOperationCrud::CreateSite => {
- do_websocket_operation::<CreateSite>(context, id, op, data).await
- }
- UserOperationCrud::EditSite => do_websocket_operation::<EditSite>(context, id, op, data).await,
- UserOperationCrud::GetSite => do_websocket_operation::<GetSite>(context, id, op, data).await,
-
- // Community ops
- UserOperationCrud::GetCommunity => {
- do_websocket_operation::<GetCommunity>(context, id, op, data).await
- }
- UserOperationCrud::ListCommunities => {
- do_websocket_operation::<ListCommunities>(context, id, op, data).await
- }
- UserOperationCrud::CreateCommunity => {
- do_websocket_operation::<CreateCommunity>(context, id, op, data).await
- }
- UserOperationCrud::EditCommunity => {
- do_websocket_operation::<EditCommunity>(context, id, op, data).await
- }
- UserOperationCrud::DeleteCommunity => {
- do_websocket_operation::<DeleteCommunity>(context, id, op, data).await
- }
- UserOperationCrud::RemoveCommunity => {
- do_websocket_operation::<RemoveCommunity>(context, id, op, data).await
- }
-
- // Post ops
- UserOperationCrud::CreatePost => {
- do_websocket_operation::<CreatePost>(context, id, op, data).await
- }
- UserOperationCrud::GetPost => do_websocket_operation::<GetPost>(context, id, op, data).await,
- UserOperationCrud::GetPosts => do_websocket_operation::<GetPosts>(context, id, op, data).await,
- UserOperationCrud::EditPost => do_websocket_operation::<EditPost>(context, id, op, data).await,
- UserOperationCrud::DeletePost => {
- do_websocket_operation::<DeletePost>(context, id, op, data).await
- }
- UserOperationCrud::RemovePost => {
- do_websocket_operation::<RemovePost>(context, id, op, data).await
- }
-
- // Comment ops
- UserOperationCrud::CreateComment => {
- do_websocket_operation::<CreateComment>(context, id, op, data).await
- }
- UserOperationCrud::EditComment => {
- do_websocket_operation::<EditComment>(context, id, op, data).await
- }
- UserOperationCrud::DeleteComment => {
- do_websocket_operation::<DeleteComment>(context, id, op, data).await
- }
- UserOperationCrud::RemoveComment => {
- do_websocket_operation::<RemoveComment>(context, id, op, data).await
- }
- UserOperationCrud::GetComment => {
- do_websocket_operation::<GetComment>(context, id, op, data).await
- }
- UserOperationCrud::GetComments => {
- do_websocket_operation::<GetComments>(context, id, op, data).await
- }
- }
-}
-
-async fn do_websocket_operation<'a, 'b, Data>(
- context: LemmyContext,
- id: ConnectionId,
- op: UserOperationCrud,
- data: &str,
-) -> Result<String, LemmyError>
-where
- for<'de> Data: Deserialize<'de> + 'a,
- Data: PerformCrud,
-{
- let parsed_data: Data = serde_json::from_str(data)?;
- let res = parsed_data
- .perform(&web::Data::new(context), Some(id))
- .await?;
- serialize_websocket_message(&op, &res)
-}
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- generate_local_apub_endpoint,
+ context::LemmyContext,
post::{CreatePost, PostResponse},
request::fetch_site_data,
utils::{
check_community_ban,
check_community_deleted_or_removed,
+ generate_local_apub_endpoint,
get_local_user_view_from_jwt,
honeypot_check,
local_site_to_slur_regex,
mark_post_as_read,
+ EndpointType,
},
websocket::{send::send_post_ws_message, UserOperationCrud},
- EndpointType,
- LemmyContext,
-};
-use lemmy_apub::{
- objects::post::ApubPost,
- protocol::activities::{create_or_update::page::CreateOrUpdatePage, CreateOrUpdateType},
};
use lemmy_db_schema::{
impls::actor_language::default_post_language,
}
}
- let apub_post: ApubPost = updated_post.into();
- CreateOrUpdatePage::send(
- apub_post.clone(),
- &local_user_view.person.clone().into(),
- CreateOrUpdateType::Create,
- context,
- )
- .await?;
-
send_post_ws_message(
inserted_post.id,
UserOperationCrud::CreatePost,
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
post::{DeletePost, PostResponse},
utils::{check_community_ban, check_community_deleted_or_removed, get_local_user_view_from_jwt},
websocket::{send::send_post_ws_message, UserOperationCrud},
- LemmyContext,
};
-use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
use lemmy_db_schema::{
- source::{
- community::Community,
- post::{Post, PostUpdateForm},
- },
+ source::post::{Post, PostUpdateForm},
traits::Crud,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
// Update the post
let post_id = data.post_id;
let deleted = data.deleted;
- let updated_post = Post::update(
+ Post::update(
context.pool(),
post_id,
&PostUpdateForm::builder().deleted(Some(deleted)).build(),
)
.await?;
- // apub updates
- let community = Community::read(context.pool(), orig_post.community_id).await?;
- let deletable = DeletableObjects::Post(Box::new(updated_post.into()));
- send_apub_delete_in_community(
- local_user_view.person,
- community,
- deletable,
- None,
- deleted,
- context,
- )
- .await?;
Ok(res)
}
}
mod create;
mod delete;
-mod list;
mod read;
mod remove;
mod update;
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
post::{GetPost, GetPostResponse},
utils::{check_private_instance, get_local_user_view_from_jwt_opt, mark_post_as_read},
websocket::messages::GetPostUsersOnline,
- LemmyContext,
};
use lemmy_db_schema::{
aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm},
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
post::{PostResponse, RemovePost},
utils::{check_community_ban, get_local_user_view_from_jwt, is_mod_or_admin},
websocket::{send::send_post_ws_message, UserOperationCrud},
- LemmyContext,
};
-use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
use lemmy_db_schema::{
source::{
- community::Community,
moderator::{ModRemovePost, ModRemovePostForm},
post::{Post, PostUpdateForm},
},
// Update the post
let post_id = data.post_id;
let removed = data.removed;
- let updated_post = Post::update(
+ Post::update(
context.pool(),
post_id,
&PostUpdateForm::builder().removed(Some(removed)).build(),
)
.await?;
- // apub updates
- let community = Community::read(context.pool(), orig_post.community_id).await?;
- let deletable = DeletableObjects::Post(Box::new(updated_post.into()));
- send_apub_delete_in_community(
- local_user_view.person,
- community,
- deletable,
- data.reason.clone().or_else(|| Some(String::new())),
- removed,
- context,
- )
- .await?;
Ok(res)
}
}
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
post::{EditPost, PostResponse},
request::fetch_site_data,
utils::{
local_site_to_slur_regex,
},
websocket::{send::send_post_ws_message, UserOperationCrud},
- LemmyContext,
-};
-use lemmy_apub::protocol::activities::{
- create_or_update::page::CreateOrUpdatePage,
- CreateOrUpdateType,
};
use lemmy_db_schema::{
source::{
let post_id = data.post_id;
let res = Post::update(context.pool(), post_id, &post_form).await;
- let updated_post: Post = match res {
- Ok(post) => post,
- Err(e) => {
- let err_type = if e.to_string() == "value too long for type character varying(200)" {
- "post_title_too_long"
- } else {
- "couldnt_update_post"
- };
-
- return Err(LemmyError::from_error_message(e, err_type));
- }
- };
-
- // Send apub update
- CreateOrUpdatePage::send(
- updated_post.into(),
- &local_user_view.person.clone().into(),
- CreateOrUpdateType::Update,
- context,
- )
- .await?;
+ if let Err(e) = res {
+ let err_type = if e.to_string() == "value too long for type character varying(200)" {
+ "post_title_too_long"
+ } else {
+ "couldnt_update_post"
+ };
+
+ return Err(LemmyError::from_error_message(e, err_type));
+ }
send_post_ws_message(
data.post_id,
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- generate_local_apub_endpoint,
+ context::LemmyContext,
private_message::{CreatePrivateMessage, PrivateMessageResponse},
utils::{
check_person_block,
+ generate_local_apub_endpoint,
get_interface_language,
get_local_user_view_from_jwt,
local_site_to_slur_regex,
send_email_to_user,
+ EndpointType,
},
websocket::{send::send_pm_ws_message, UserOperationCrud},
- EndpointType,
- LemmyContext,
-};
-use lemmy_apub::protocol::activities::{
- create_or_update::chat_message::CreateOrUpdateChatMessage,
- CreateOrUpdateType,
};
use lemmy_db_schema::{
source::{
&inserted_private_message_id.to_string(),
&protocol_and_hostname,
)?;
- let updated_private_message = PrivateMessage::update(
+ PrivateMessage::update(
context.pool(),
inserted_private_message.id,
&PrivateMessageUpdateForm::builder()
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_create_private_message"))?;
- CreateOrUpdateChatMessage::send(
- updated_private_message.into(),
- &local_user_view.person.into(),
- CreateOrUpdateType::Create,
- context,
- )
- .await?;
-
let res = send_pm_ws_message(
inserted_private_message.id,
UserOperationCrud::CreatePrivateMessage,
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
private_message::{DeletePrivateMessage, PrivateMessageResponse},
utils::get_local_user_view_from_jwt,
websocket::{send::send_pm_ws_message, UserOperationCrud},
- LemmyContext,
};
-use lemmy_apub::activities::deletion::send_apub_delete_private_message;
use lemmy_db_schema::{
source::private_message::{PrivateMessage, PrivateMessageUpdateForm},
traits::Crud,
// Doing the update
let private_message_id = data.private_message_id;
let deleted = data.deleted;
- let updated_private_message = PrivateMessage::update(
+ PrivateMessage::update(
context.pool(),
private_message_id,
&PrivateMessageUpdateForm::builder()
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_private_message"))?;
- // Send the apub update
- send_apub_delete_private_message(
- &local_user_view.person.into(),
- updated_private_message,
- data.deleted,
- context,
- )
- .await?;
-
let op = UserOperationCrud::DeletePrivateMessage;
send_pm_ws_message(data.private_message_id, op, websocket_id, context).await
}
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
private_message::{GetPrivateMessages, PrivateMessagesResponse},
utils::get_local_user_view_from_jwt,
- LemmyContext,
};
use lemmy_db_schema::traits::DeleteableOrRemoveable;
use lemmy_db_views::private_message_view::PrivateMessageQuery;
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
private_message::{EditPrivateMessage, PrivateMessageResponse},
utils::{get_local_user_view_from_jwt, local_site_to_slur_regex},
websocket::{send::send_pm_ws_message, UserOperationCrud},
- LemmyContext,
-};
-use lemmy_apub::protocol::activities::{
- create_or_update::chat_message::CreateOrUpdateChatMessage,
- CreateOrUpdateType,
};
use lemmy_db_schema::{
source::{
// Doing the update
let content_slurs_removed = remove_slurs(&data.content, &local_site_to_slur_regex(&local_site));
let private_message_id = data.private_message_id;
- let updated_private_message = PrivateMessage::update(
+ PrivateMessage::update(
context.pool(),
private_message_id,
&PrivateMessageUpdateForm::builder()
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_private_message"))?;
- // Send the apub update
- CreateOrUpdateChatMessage::send(
- updated_private_message.into(),
- &local_user_view.person.into(),
- CreateOrUpdateType::Update,
- context,
- )
- .await?;
-
let op = UserOperationCrud::EditPrivateMessage;
send_pm_ws_message(data.private_message_id, op, websocket_id, context).await
}
use activitypub_federation::core::signatures::generate_actor_keypair;
use actix_web::web::Data;
use lemmy_api_common::{
- generate_site_inbox_url,
+ context::LemmyContext,
site::{CreateSite, SiteResponse},
utils::{
+ generate_site_inbox_url,
get_local_user_view_from_jwt,
is_admin,
local_site_rate_limit_to_rate_limit_config,
local_site_to_slur_regex,
site_description_length_check,
},
- LemmyContext,
};
use lemmy_db_schema::{
newtypes::DbUrl,
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
site::{GetSite, GetSiteResponse, MyUserInfo},
utils::{build_federated_instances, get_local_user_settings_view_from_jwt_opt},
websocket::messages::GetUsersOnline,
- LemmyContext,
};
use lemmy_db_schema::source::{actor_language::SiteLanguage, language::Language, tagline::Tagline};
use lemmy_db_views::structs::{LocalUserDiscussionLanguageView, SiteView};
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
site::{EditSite, SiteResponse},
utils::{
get_local_user_view_from_jwt,
site_description_length_check,
},
websocket::{messages::SendAllMessage, UserOperationCrud},
- LemmyContext,
};
use lemmy_db_schema::{
source::{
use activitypub_federation::core::signatures::generate_actor_keypair;
use actix_web::web::Data;
use lemmy_api_common::{
- generate_inbox_url,
- generate_local_apub_endpoint,
- generate_shared_inbox_url,
+ context::LemmyContext,
person::{LoginResponse, Register},
utils::{
+ generate_inbox_url,
+ generate_local_apub_endpoint,
+ generate_shared_inbox_url,
honeypot_check,
local_site_to_slur_regex,
password_length_check,
send_new_applicant_email_to_admins,
send_verification_email,
+ EndpointType,
},
websocket::messages::CheckCaptcha,
- EndpointType,
- LemmyContext,
};
use lemmy_db_schema::{
aggregates::structs::PersonAggregates,
use actix_web::web::Data;
use bcrypt::verify;
use lemmy_api_common::{
+ context::LemmyContext,
person::{DeleteAccount, DeleteAccountResponse},
- utils::{delete_user_account, get_local_user_view_from_jwt},
- LemmyContext,
+ utils::get_local_user_view_from_jwt,
};
-use lemmy_apub::protocol::activities::deletion::delete_user::DeleteUser;
use lemmy_utils::{error::LemmyError, ConnectionId};
#[async_trait::async_trait(?Send)]
return Err(LemmyError::from_message("password_incorrect"));
}
- delete_user_account(
- local_user_view.person.id,
- context.pool(),
- context.settings(),
- context.client(),
- )
- .await?;
- DeleteUser::send(&local_user_view.person.into(), context).await?;
-
Ok(DeleteAccountResponse {})
}
}
mod create;
mod delete;
-mod read;
use anyhow::anyhow;
use chrono::NaiveDateTime;
use lemmy_api_common::{
+ context::LemmyContext,
utils::{remove_user_data, remove_user_data_in_community},
- LemmyContext,
};
use lemmy_db_schema::{
source::{
use crate::{
- objects::{community::ApubCommunity, instance::ApubSite},
- protocol::objects::{group::Group, instance::Instance},
+ objects::{community::ApubCommunity, instance::ApubSite, person::ApubPerson},
+ protocol::{
+ activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
+ objects::{group::Group, instance::Instance},
+ },
ActorType,
+ SendActivity,
};
use activitypub_federation::{core::object_id::ObjectId, traits::ApubObject};
use chrono::NaiveDateTime;
-use lemmy_api_common::LemmyContext;
-use lemmy_db_schema::{source::site::Site, utils::DbPool};
-use lemmy_utils::error::LemmyError;
+use lemmy_api_common::{
+ community::{BanFromCommunity, BanFromCommunityResponse},
+ context::LemmyContext,
+ person::{BanPerson, BanPersonResponse},
+ utils::get_local_user_view_from_jwt,
+};
+use lemmy_db_schema::{
+ source::{community::Community, person::Person, site::Site},
+ traits::Crud,
+ utils::DbPool,
+};
+use lemmy_db_views::structs::SiteView;
+use lemmy_utils::{error::LemmyError, utils::naive_from_unix};
use serde::Deserialize;
use url::Url;
SiteOrCommunity::Community(c) => vec![c.actor_id()],
})
}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for BanPerson {
+ type Response = BanPersonResponse;
+
+ async fn send_activity(
+ request: &Self,
+ _response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ let person = Person::read(context.pool(), request.person_id).await?;
+ let site = SiteOrCommunity::Site(SiteView::read_local(context.pool()).await?.site.into());
+ let expires = request.expires.map(naive_from_unix);
+
+ // if the action affects a local user, federate to other instances
+ if person.local {
+ if request.ban {
+ BlockUser::send(
+ &site,
+ &person.into(),
+ &local_user_view.person.into(),
+ request.remove_data.unwrap_or(false),
+ request.reason.clone(),
+ expires,
+ context,
+ )
+ .await
+ } else {
+ UndoBlockUser::send(
+ &site,
+ &person.into(),
+ &local_user_view.person.into(),
+ request.reason.clone(),
+ context,
+ )
+ .await
+ }
+ } else {
+ Ok(())
+ }
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for BanFromCommunity {
+ type Response = BanFromCommunityResponse;
+
+ async fn send_activity(
+ request: &Self,
+ _response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ let community: ApubCommunity = Community::read(context.pool(), request.community_id)
+ .await?
+ .into();
+ let banned_person: ApubPerson = Person::read(context.pool(), request.person_id)
+ .await?
+ .into();
+ let expires = request.expires.map(naive_from_unix);
+
+ if request.ban {
+ BlockUser::send(
+ &SiteOrCommunity::Community(community),
+ &banned_person,
+ &local_user_view.person.clone().into(),
+ request.remove_data.unwrap_or(false),
+ request.reason.clone(),
+ expires,
+ context,
+ )
+ .await
+ } else {
+ UndoBlockUser::send(
+ &SiteOrCommunity::Community(community),
+ &banned_person,
+ &local_user_view.person.clone().into(),
+ request.reason.clone(),
+ context,
+ )
+ .await
+ }
+ }
+}
utils::verify_domains_match,
};
use activitystreams_kinds::{activity::UndoType, public};
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::{
source::{
community::{CommunityPersonBan, CommunityPersonBanForm},
activity_lists::AnnouncableActivities,
local_instance,
objects::{community::ApubCommunity, person::ApubPerson},
- protocol::{activities::community::add_mod::AddMod, InCommunity},
+ protocol::{
+ activities::community::{add_mod::AddMod, remove_mod::RemoveMod},
+ InCommunity,
+ },
ActorType,
+ SendActivity,
};
use activitypub_federation::{
core::object_id::ObjectId,
traits::{ActivityHandler, Actor},
};
use activitystreams_kinds::{activity::AddType, public};
-use lemmy_api_common::{generate_moderators_url, LemmyContext};
+use lemmy_api_common::{
+ community::{AddModToCommunity, AddModToCommunityResponse},
+ context::LemmyContext,
+ utils::{generate_moderators_url, get_local_user_view_from_jwt},
+};
use lemmy_db_schema::{
source::{
- community::{CommunityModerator, CommunityModeratorForm},
+ community::{Community, CommunityModerator, CommunityModeratorForm},
moderator::{ModAddCommunity, ModAddCommunityForm},
+ person::Person,
},
traits::{Crud, Joinable},
};
Ok(())
}
}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for AddModToCommunity {
+ type Response = AddModToCommunityResponse;
+
+ async fn send_activity(
+ request: &Self,
+ _response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ let community: ApubCommunity = Community::read(context.pool(), request.community_id)
+ .await?
+ .into();
+ let updated_mod: ApubPerson = Person::read(context.pool(), request.person_id)
+ .await?
+ .into();
+ if request.added {
+ AddMod::send(
+ &community,
+ &updated_mod,
+ &local_user_view.person.into(),
+ context,
+ )
+ .await
+ } else {
+ RemoveMod::send(
+ &community,
+ &updated_mod,
+ &local_user_view.person.into(),
+ context,
+ )
+ .await
+ }
+ }
+}
};
use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
use activitystreams_kinds::{activity::AnnounceType, public};
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use serde_json::Value;
use tracing::debug;
protocol::activities::community::announce::AnnounceActivity,
};
use activitypub_federation::{core::object_id::ObjectId, traits::Actor};
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::source::person::PersonFollower;
use lemmy_utils::error::LemmyError;
use url::Url;
traits::{ActivityHandler, Actor},
};
use activitystreams_kinds::{activity::RemoveType, public};
-use lemmy_api_common::{generate_moderators_url, LemmyContext};
+use lemmy_api_common::{context::LemmyContext, utils::generate_moderators_url};
use lemmy_db_schema::{
source::{
community::{CommunityModerator, CommunityModeratorForm},
protocol::{activities::community::report::Report, InCommunity},
ActorType,
PostOrComment,
+ SendActivity,
};
use activitypub_federation::{
core::object_id::ObjectId,
};
use activitystreams_kinds::activity::FlagType;
use lemmy_api_common::{
- comment::CommentReportResponse,
- post::PostReportResponse,
+ comment::{CommentReportResponse, CreateCommentReport},
+ context::LemmyContext,
+ post::{CreatePostReport, PostReportResponse},
+ utils::get_local_user_view_from_jwt,
websocket::{messages::SendModRoomMessage, UserOperation},
- LemmyContext,
};
use lemmy_db_schema::{
source::{
use lemmy_utils::error::LemmyError;
use url::Url;
+#[async_trait::async_trait(?Send)]
+impl SendActivity for CreatePostReport {
+ type Response = PostReportResponse;
+
+ async fn send_activity(
+ request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ Report::send(
+ ObjectId::new(response.post_report_view.post.ap_id.clone()),
+ &local_user_view.person.into(),
+ ObjectId::new(response.post_report_view.community.actor_id.clone()),
+ request.reason.to_string(),
+ context,
+ )
+ .await
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for CreateCommentReport {
+ type Response = CommentReportResponse;
+
+ async fn send_activity(
+ request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ Report::send(
+ ObjectId::new(response.comment_report_view.comment.ap_id.clone()),
+ &local_user_view.person.into(),
+ ObjectId::new(response.comment_report_view.community.actor_id.clone()),
+ request.reason.to_string(),
+ context,
+ )
+ .await
+ }
+}
+
impl Report {
#[tracing::instrument(skip_all)]
- pub async fn send(
+ async fn send(
object_id: ObjectId<PostOrComment>,
actor: &ApubPerson,
community_id: ObjectId<ApubCommunity>,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::{activities::community::update::UpdateCommunity, InCommunity},
ActorType,
+ SendActivity,
};
use activitypub_federation::{
core::object_id::ObjectId,
};
use activitystreams_kinds::{activity::UpdateType, public};
use lemmy_api_common::{
+ community::{CommunityResponse, EditCommunity, HideCommunity},
+ context::LemmyContext,
+ utils::get_local_user_view_from_jwt,
websocket::{send::send_community_ws_message, UserOperationCrud},
- LemmyContext,
};
use lemmy_db_schema::{source::community::Community, traits::Crud};
use lemmy_utils::error::LemmyError;
use url::Url;
+#[async_trait::async_trait(?Send)]
+impl SendActivity for EditCommunity {
+ type Response = CommunityResponse;
+
+ async fn send_activity(
+ request: &Self,
+ _response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ let community = Community::read(context.pool(), request.community_id).await?;
+ UpdateCommunity::send(community.into(), &local_user_view.person.into(), context).await
+ }
+}
+
impl UpdateCommunity {
#[tracing::instrument(skip_all)]
pub async fn send(
Ok(())
}
}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for HideCommunity {
+ type Response = CommunityResponse;
+
+ async fn send_activity(
+ request: &Self,
+ _response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ let community = Community::read(context.pool(), request.community_id).await?;
+ UpdateCommunity::send(community.into(), &local_user_view.person.into(), context).await
+ }
+}
InCommunity,
},
ActorType,
+ SendActivity,
};
use activitypub_federation::{
core::object_id::ObjectId,
};
use activitystreams_kinds::public;
use lemmy_api_common::{
+ comment::{CommentResponse, CreateComment, EditComment},
+ context::LemmyContext,
utils::check_post_deleted_or_removed,
websocket::{send::send_comment_ws_message, UserOperationCrud},
- LemmyContext,
};
use lemmy_db_schema::{
+ newtypes::PersonId,
source::{
- comment::{CommentLike, CommentLikeForm},
+ comment::{Comment, CommentLike, CommentLikeForm},
community::Community,
+ person::Person,
post::Post,
},
traits::{Crud, Likeable},
use lemmy_utils::error::LemmyError;
use url::Url;
+#[async_trait::async_trait(?Send)]
+impl SendActivity for CreateComment {
+ type Response = CommentResponse;
+
+ async fn send_activity(
+ _request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ CreateOrUpdateNote::send(
+ &response.comment_view.comment,
+ response.comment_view.creator.id,
+ CreateOrUpdateType::Create,
+ context,
+ )
+ .await
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for EditComment {
+ type Response = CommentResponse;
+
+ async fn send_activity(
+ _request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ CreateOrUpdateNote::send(
+ &response.comment_view.comment,
+ response.comment_view.creator.id,
+ CreateOrUpdateType::Update,
+ context,
+ )
+ .await
+ }
+}
+
impl CreateOrUpdateNote {
- #[tracing::instrument(skip(comment, actor, kind, context))]
- pub async fn send(
- comment: ApubComment,
- actor: &ApubPerson,
+ #[tracing::instrument(skip(comment, person_id, kind, context))]
+ async fn send(
+ comment: &Comment,
+ person_id: PersonId,
kind: CreateOrUpdateType,
context: &LemmyContext,
- request_counter: &mut i32,
) -> Result<(), LemmyError> {
// TODO: might be helpful to add a comment method to retrieve community directly
let post_id = comment.post_id;
let post = Post::read(context.pool(), post_id).await?;
let community_id = post.community_id;
+ let person: ApubPerson = Person::read(context.pool(), person_id).await?.into();
let community: ApubCommunity = Community::read(context.pool(), community_id).await?.into();
let id = generate_activity_id(
kind.clone(),
&context.settings().get_protocol_and_hostname(),
)?;
- let note = comment.into_apub(context).await?;
+ let note = ApubComment(comment.clone()).into_apub(context).await?;
let create_or_update = CreateOrUpdateNote {
- actor: ObjectId::new(actor.actor_id()),
+ actor: ObjectId::new(person.actor_id()),
to: vec![public()],
cc: note.cc.clone(),
tag: note.tag.clone(),
let mut inboxes = vec![];
for t in tagged_users {
let person = t
- .dereference(context, local_instance(context).await, request_counter)
+ .dereference(context, local_instance(context).await, &mut 0)
.await?;
inboxes.push(person.shared_inbox_or_inbox());
}
let activity = AnnouncableActivities::CreateOrUpdateComment(create_or_update);
- send_activity_in_community(activity, actor, &community, inboxes, false, context).await
+ send_activity_in_community(activity, &person, &community, inboxes, false, context).await
}
}
use crate::{local_instance, objects::person::ApubPerson};
use activitypub_federation::core::object_id::ObjectId;
-use lemmy_api_common::{websocket::send::send_local_notifs, LemmyContext};
+use lemmy_api_common::{context::LemmyContext, websocket::send::send_local_notifs};
use lemmy_db_schema::{
newtypes::LocalUserId,
source::{comment::Comment, post::Post},
InCommunity,
},
ActorType,
+ SendActivity,
};
use activitypub_federation::{
core::object_id::ObjectId,
};
use activitystreams_kinds::public;
use lemmy_api_common::{
+ context::LemmyContext,
+ post::{CreatePost, EditPost, LockPost, PostResponse, StickyPost},
+ utils::get_local_user_view_from_jwt,
websocket::{send::send_post_ws_message, UserOperationCrud},
- LemmyContext,
};
use lemmy_db_schema::{
+ newtypes::PersonId,
source::{
community::Community,
- post::{PostLike, PostLikeForm},
+ person::Person,
+ post::{Post, PostLike, PostLikeForm},
},
traits::{Crud, Likeable},
};
use lemmy_utils::error::LemmyError;
use url::Url;
+#[async_trait::async_trait(?Send)]
+impl SendActivity for CreatePost {
+ type Response = PostResponse;
+
+ async fn send_activity(
+ _request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ CreateOrUpdatePage::send(
+ &response.post_view.post,
+ response.post_view.creator.id,
+ CreateOrUpdateType::Create,
+ context,
+ )
+ .await
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for EditPost {
+ type Response = PostResponse;
+
+ async fn send_activity(
+ _request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ CreateOrUpdatePage::send(
+ &response.post_view.post,
+ response.post_view.creator.id,
+ CreateOrUpdateType::Update,
+ context,
+ )
+ .await
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for LockPost {
+ type Response = PostResponse;
+
+ async fn send_activity(
+ request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ CreateOrUpdatePage::send(
+ &response.post_view.post,
+ local_user_view.person.id,
+ CreateOrUpdateType::Update,
+ context,
+ )
+ .await
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for StickyPost {
+ type Response = PostResponse;
+
+ async fn send_activity(
+ request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ CreateOrUpdatePage::send(
+ &response.post_view.post,
+ local_user_view.person.id,
+ CreateOrUpdateType::Update,
+ context,
+ )
+ .await
+ }
+}
+
impl CreateOrUpdatePage {
pub(crate) async fn new(
post: ApubPost,
}
#[tracing::instrument(skip_all)]
- pub async fn send(
- post: ApubPost,
- actor: &ApubPerson,
+ async fn send(
+ post: &Post,
+ person_id: PersonId,
kind: CreateOrUpdateType,
context: &LemmyContext,
) -> Result<(), LemmyError> {
+ let post = ApubPost(post.clone());
let community_id = post.community_id;
+ let person: ApubPerson = Person::read(context.pool(), person_id).await?.into();
let community: ApubCommunity = Community::read(context.pool(), community_id).await?.into();
- let create_or_update = CreateOrUpdatePage::new(post, actor, &community, kind, context).await?;
+ let create_or_update =
+ CreateOrUpdatePage::new(post, &person, &community, kind, context).await?;
let is_mod_action = create_or_update.object.is_mod_action(context).await?;
let activity = AnnouncableActivities::CreateOrUpdatePost(create_or_update);
- send_activity_in_community(activity, actor, &community, vec![], is_mod_action, context).await?;
+ send_activity_in_community(
+ activity,
+ &person,
+ &community,
+ vec![],
+ is_mod_action,
+ context,
+ )
+ .await?;
Ok(())
}
}
CreateOrUpdateType,
},
ActorType,
+ SendActivity,
};
use activitypub_federation::{
core::object_id::ObjectId,
utils::verify_domains_match,
};
use lemmy_api_common::{
+ context::LemmyContext,
+ private_message::{CreatePrivateMessage, EditPrivateMessage, PrivateMessageResponse},
websocket::{send::send_pm_ws_message, UserOperationCrud},
- LemmyContext,
};
-use lemmy_db_schema::{source::person::Person, traits::Crud};
+use lemmy_db_schema::{
+ newtypes::PersonId,
+ source::{person::Person, private_message::PrivateMessage},
+ traits::Crud,
+};
use lemmy_utils::error::LemmyError;
use url::Url;
+#[async_trait::async_trait(?Send)]
+impl SendActivity for CreatePrivateMessage {
+ type Response = PrivateMessageResponse;
+
+ async fn send_activity(
+ _request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ CreateOrUpdateChatMessage::send(
+ &response.private_message_view.private_message,
+ response.private_message_view.creator.id,
+ CreateOrUpdateType::Create,
+ context,
+ )
+ .await
+ }
+}
+#[async_trait::async_trait(?Send)]
+impl SendActivity for EditPrivateMessage {
+ type Response = PrivateMessageResponse;
+
+ async fn send_activity(
+ _request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ CreateOrUpdateChatMessage::send(
+ &response.private_message_view.private_message,
+ response.private_message_view.creator.id,
+ CreateOrUpdateType::Update,
+ context,
+ )
+ .await
+ }
+}
+
impl CreateOrUpdateChatMessage {
#[tracing::instrument(skip_all)]
- pub async fn send(
- private_message: ApubPrivateMessage,
- actor: &ApubPerson,
+ async fn send(
+ private_message: &PrivateMessage,
+ sender_id: PersonId,
kind: CreateOrUpdateType,
context: &LemmyContext,
) -> Result<(), LemmyError> {
let recipient_id = private_message.recipient_id;
+ let sender: ApubPerson = Person::read(context.pool(), sender_id).await?.into();
let recipient: ApubPerson = Person::read(context.pool(), recipient_id).await?.into();
let id = generate_activity_id(
)?;
let create_or_update = CreateOrUpdateChatMessage {
id: id.clone(),
- actor: ObjectId::new(actor.actor_id()),
+ actor: ObjectId::new(sender.actor_id()),
to: [ObjectId::new(recipient.actor_id())],
- object: private_message.into_apub(context).await?,
+ object: ApubPrivateMessage(private_message.clone())
+ .into_apub(context)
+ .await?,
kind,
};
let inbox = vec![recipient.shared_inbox_or_inbox()];
- send_lemmy_activity(context, create_or_update, actor, inbox, true).await
+ send_lemmy_activity(context, create_or_update, &sender, inbox, true).await
}
}
use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
use activitystreams_kinds::activity::DeleteType;
use lemmy_api_common::{
+ context::LemmyContext,
websocket::{
send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
UserOperationCrud,
},
- LemmyContext,
};
use lemmy_db_schema::{
source::{
local_instance,
objects::{instance::remote_instance_inboxes, person::ApubPerson},
protocol::activities::deletion::delete_user::DeleteUser,
+ SendActivity,
};
use activitypub_federation::{
core::object_id::ObjectId,
utils::verify_urls_match,
};
use activitystreams_kinds::{activity::DeleteType, public};
-use lemmy_api_common::{utils::delete_user_account, LemmyContext};
+use lemmy_api_common::{
+ context::LemmyContext,
+ person::{DeleteAccount, DeleteAccountResponse},
+ utils::{delete_user_account, get_local_user_view_from_jwt},
+};
use lemmy_utils::error::LemmyError;
use url::Url;
+#[async_trait::async_trait(?Send)]
+impl SendActivity for DeleteAccount {
+ type Response = DeleteAccountResponse;
+
+ async fn send_activity(
+ request: &Self,
+ _response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ let actor: ApubPerson = local_user_view.person.into();
+ delete_user_account(
+ actor.id,
+ context.pool(),
+ context.settings(),
+ context.client(),
+ )
+ .await?;
+
+ let actor_id = ObjectId::new(actor.actor_id.clone());
+ let id = generate_activity_id(
+ DeleteType::Delete,
+ &context.settings().get_protocol_and_hostname(),
+ )?;
+ let delete = DeleteUser {
+ actor: actor_id.clone(),
+ to: vec![public()],
+ object: actor_id,
+ kind: DeleteType::Delete,
+ id: id.clone(),
+ cc: vec![],
+ };
+
+ let inboxes = remote_instance_inboxes(context.pool()).await?;
+ send_lemmy_activity(context, delete, &actor, inboxes, true).await?;
+ Ok(())
+ }
+}
+
/// This can be separate from Delete activity because it doesn't need to be handled in shared inbox
/// (cause instance actor doesn't have shared inbox).
#[async_trait::async_trait(?Send)]
Ok(())
}
}
-
-impl DeleteUser {
- #[tracing::instrument(skip_all)]
- pub async fn send(actor: &ApubPerson, context: &LemmyContext) -> Result<(), LemmyError> {
- let actor_id = ObjectId::new(actor.actor_id.clone());
- let id = generate_activity_id(
- DeleteType::Delete,
- &context.settings().get_protocol_and_hostname(),
- )?;
- let delete = DeleteUser {
- actor: actor_id.clone(),
- to: vec![public()],
- object: actor_id,
- kind: DeleteType::Delete,
- id: id.clone(),
- cc: vec![],
- };
-
- let inboxes = remote_instance_inboxes(context.pool()).await?;
- send_lemmy_activity(context, delete, actor, inboxes, true).await?;
- Ok(())
- }
-}
InCommunity,
},
ActorType,
+ SendActivity,
};
use activitypub_federation::{
core::object_id::ObjectId,
};
use activitystreams_kinds::public;
use lemmy_api_common::{
+ comment::{CommentResponse, DeleteComment, RemoveComment},
+ community::{CommunityResponse, DeleteCommunity, RemoveCommunity},
+ context::LemmyContext,
+ post::{DeletePost, PostResponse, RemovePost},
+ private_message::{DeletePrivateMessage, PrivateMessageResponse},
+ utils::get_local_user_view_from_jwt,
websocket::{
send::{
send_comment_ws_message_simple,
},
UserOperationCrud,
},
- LemmyContext,
};
use lemmy_db_schema::{
source::{
pub mod delete_user;
pub mod undo_delete;
+#[async_trait::async_trait(?Send)]
+impl SendActivity for DeletePost {
+ type Response = PostResponse;
+
+ async fn send_activity(
+ request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ let community = Community::read(context.pool(), response.post_view.community.id).await?;
+ let deletable = DeletableObjects::Post(Box::new(response.post_view.post.clone().into()));
+ send_apub_delete_in_community(
+ local_user_view.person,
+ community,
+ deletable,
+ None,
+ request.deleted,
+ context,
+ )
+ .await
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for RemovePost {
+ type Response = PostResponse;
+
+ async fn send_activity(
+ request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ let community = Community::read(context.pool(), response.post_view.community.id).await?;
+ let deletable = DeletableObjects::Post(Box::new(response.post_view.post.clone().into()));
+ send_apub_delete_in_community(
+ local_user_view.person,
+ community,
+ deletable,
+ request.reason.clone().or_else(|| Some(String::new())),
+ request.removed,
+ context,
+ )
+ .await
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for DeleteComment {
+ type Response = CommentResponse;
+
+ async fn send_activity(
+ request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let community_id = response.comment_view.community.id;
+ let community = Community::read(context.pool(), community_id).await?;
+ let person = Person::read(context.pool(), response.comment_view.creator.id).await?;
+ let deletable =
+ DeletableObjects::Comment(Box::new(response.comment_view.comment.clone().into()));
+ send_apub_delete_in_community(person, community, deletable, None, request.deleted, context)
+ .await
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for RemoveComment {
+ type Response = CommentResponse;
+
+ async fn send_activity(
+ request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ let comment = Comment::read(context.pool(), request.comment_id).await?;
+ let community = Community::read(context.pool(), response.comment_view.community.id).await?;
+ let deletable = DeletableObjects::Comment(Box::new(comment.into()));
+ send_apub_delete_in_community(
+ local_user_view.person,
+ community,
+ deletable,
+ request.reason.clone().or_else(|| Some(String::new())),
+ request.removed,
+ context,
+ )
+ .await
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for DeletePrivateMessage {
+ type Response = PrivateMessageResponse;
+
+ async fn send_activity(
+ request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ send_apub_delete_private_message(
+ &local_user_view.person.into(),
+ response.private_message_view.private_message.clone(),
+ request.deleted,
+ context,
+ )
+ .await
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for DeleteCommunity {
+ type Response = CommunityResponse;
+
+ async fn send_activity(
+ request: &Self,
+ _response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ let community = Community::read(context.pool(), request.community_id).await?;
+ let deletable = DeletableObjects::Community(Box::new(community.clone().into()));
+ send_apub_delete_in_community(
+ local_user_view.person,
+ community,
+ deletable,
+ None,
+ request.deleted,
+ context,
+ )
+ .await
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for RemoveCommunity {
+ type Response = CommunityResponse;
+
+ async fn send_activity(
+ request: &Self,
+ _response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ let community = Community::read(context.pool(), request.community_id).await?;
+ let deletable = DeletableObjects::Community(Box::new(community.clone().into()));
+ send_apub_delete_in_community(
+ local_user_view.person,
+ community,
+ deletable,
+ request.reason.clone().or_else(|| Some(String::new())),
+ request.removed,
+ context,
+ )
+ .await
+ }
+}
+
/// Parameter `reason` being set indicates that this is a removal by a mod. If its unset, this
/// action was done by a normal user.
#[tracing::instrument(skip_all)]
-pub async fn send_apub_delete_in_community(
+async fn send_apub_delete_in_community(
actor: Person,
community: Community,
object: DeletableObjects,
}
#[tracing::instrument(skip_all)]
-pub async fn send_apub_delete_private_message(
+async fn send_apub_delete_private_message(
actor: &ApubPerson,
pm: PrivateMessage,
deleted: bool,
use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
use activitystreams_kinds::activity::UndoType;
use lemmy_api_common::{
+ context::LemmyContext,
websocket::{
send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
UserOperationCrud,
},
- LemmyContext,
};
use lemmy_db_schema::{
source::{
use activitystreams_kinds::activity::AcceptType;
use lemmy_api_common::{
community::CommunityResponse,
+ context::LemmyContext,
websocket::{messages::SendUserRoomMessage, UserOperation},
- LemmyContext,
};
use lemmy_db_schema::{source::community::CommunityFollower, traits::Followable};
use lemmy_db_views::structs::LocalUserView;
fetcher::user_or_community::UserOrCommunity,
local_instance,
objects::{community::ApubCommunity, person::ApubPerson},
- protocol::activities::following::{accept::AcceptFollow, follow::Follow},
+ protocol::activities::following::{
+ accept::AcceptFollow,
+ follow::Follow,
+ undo_follow::UndoFollow,
+ },
ActorType,
+ SendActivity,
};
use activitypub_federation::{
core::object_id::ObjectId,
traits::{ActivityHandler, Actor},
};
use activitystreams_kinds::activity::FollowType;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::{
+ community::{BlockCommunity, BlockCommunityResponse},
+ context::LemmyContext,
+ utils::get_local_user_view_from_jwt,
+};
use lemmy_db_schema::{
source::{
- community::{CommunityFollower, CommunityFollowerForm},
+ community::{Community, CommunityFollower, CommunityFollowerForm},
person::{PersonFollower, PersonFollowerForm},
},
- traits::Followable,
+ traits::{Crud, Followable},
};
use lemmy_utils::error::LemmyError;
use url::Url;
AcceptFollow::send(self, context, request_counter).await
}
}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for BlockCommunity {
+ type Response = BlockCommunityResponse;
+
+ async fn send_activity(
+ request: &Self,
+ _response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ let community = Community::read(context.pool(), request.community_id).await?;
+ UndoFollow::send(&local_user_view.person.into(), &community.into(), context).await
+ }
+}
+use crate::{
+ objects::community::ApubCommunity,
+ protocol::activities::following::{follow::Follow, undo_follow::UndoFollow},
+ SendActivity,
+};
+use lemmy_api_common::{
+ community::{CommunityResponse, FollowCommunity},
+ context::LemmyContext,
+ utils::get_local_user_view_from_jwt,
+};
+use lemmy_db_schema::{source::community::Community, traits::Crud};
+use lemmy_utils::error::LemmyError;
+
pub mod accept;
pub mod follow;
pub mod undo_follow;
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for FollowCommunity {
+ type Response = CommunityResponse;
+
+ async fn send_activity(
+ request: &Self,
+ _response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let local_user_view =
+ get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+ let person = local_user_view.person.clone().into();
+ let community: ApubCommunity = Community::read(context.pool(), request.community_id)
+ .await?
+ .into();
+ if community.local {
+ Ok(())
+ } else if request.follow {
+ Follow::send(&person, &community, context).await
+ } else {
+ UndoFollow::send(&person, &community, context).await
+ }
+ }
+}
utils::verify_urls_match,
};
use activitystreams_kinds::activity::UndoType;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::{
source::{
community::{CommunityFollower, CommunityFollowerForm},
};
use activitystreams_kinds::public;
use anyhow::anyhow;
-use lemmy_api_common::{generate_moderators_url, LemmyContext};
+use lemmy_api_common::{context::LemmyContext, utils::generate_moderators_url};
use lemmy_db_schema::{
newtypes::CommunityId,
source::{community::Community, local_site::LocalSite},
pub mod create_or_update;
pub mod deletion;
pub mod following;
+pub mod unfederated;
pub mod voting;
/// Checks that the specified Url actually identifies a Person (by fetching it), and that the person
--- /dev/null
+use crate::SendActivity;
+use lemmy_api_common::{
+ comment::{
+ CommentReportResponse,
+ CommentResponse,
+ GetComment,
+ GetComments,
+ GetCommentsResponse,
+ ListCommentReports,
+ ListCommentReportsResponse,
+ ResolveCommentReport,
+ SaveComment,
+ },
+ community::{
+ CommunityResponse,
+ CreateCommunity,
+ GetCommunity,
+ GetCommunityResponse,
+ ListCommunities,
+ ListCommunitiesResponse,
+ TransferCommunity,
+ },
+ person::{
+ AddAdmin,
+ AddAdminResponse,
+ BannedPersonsResponse,
+ BlockPerson,
+ BlockPersonResponse,
+ ChangePassword,
+ CommentReplyResponse,
+ GetBannedPersons,
+ GetCaptcha,
+ GetCaptchaResponse,
+ GetPersonDetails,
+ GetPersonDetailsResponse,
+ GetPersonMentions,
+ GetPersonMentionsResponse,
+ GetReplies,
+ GetRepliesResponse,
+ GetReportCount,
+ GetReportCountResponse,
+ GetUnreadCount,
+ GetUnreadCountResponse,
+ Login,
+ LoginResponse,
+ MarkAllAsRead,
+ MarkCommentReplyAsRead,
+ MarkPersonMentionAsRead,
+ PasswordChangeAfterReset,
+ PasswordReset,
+ PasswordResetResponse,
+ PersonMentionResponse,
+ Register,
+ SaveUserSettings,
+ VerifyEmail,
+ VerifyEmailResponse,
+ },
+ post::{
+ GetPost,
+ GetPostResponse,
+ GetPosts,
+ GetPostsResponse,
+ GetSiteMetadata,
+ GetSiteMetadataResponse,
+ ListPostReports,
+ ListPostReportsResponse,
+ MarkPostAsRead,
+ PostReportResponse,
+ PostResponse,
+ ResolvePostReport,
+ SavePost,
+ },
+ private_message::{
+ CreatePrivateMessageReport,
+ GetPrivateMessages,
+ ListPrivateMessageReports,
+ ListPrivateMessageReportsResponse,
+ MarkPrivateMessageAsRead,
+ PrivateMessageReportResponse,
+ PrivateMessageResponse,
+ PrivateMessagesResponse,
+ ResolvePrivateMessageReport,
+ },
+ site::{
+ ApproveRegistrationApplication,
+ CreateSite,
+ EditSite,
+ GetModlog,
+ GetModlogResponse,
+ GetSite,
+ GetSiteResponse,
+ GetUnreadRegistrationApplicationCount,
+ GetUnreadRegistrationApplicationCountResponse,
+ LeaveAdmin,
+ ListRegistrationApplications,
+ ListRegistrationApplicationsResponse,
+ PurgeComment,
+ PurgeCommunity,
+ PurgeItemResponse,
+ PurgePerson,
+ PurgePost,
+ RegistrationApplicationResponse,
+ ResolveObject,
+ ResolveObjectResponse,
+ Search,
+ SearchResponse,
+ SiteResponse,
+ },
+ websocket::structs::{
+ CommunityJoin,
+ CommunityJoinResponse,
+ ModJoin,
+ ModJoinResponse,
+ PostJoin,
+ PostJoinResponse,
+ UserJoin,
+ UserJoinResponse,
+ },
+};
+
+impl SendActivity for Register {
+ type Response = LoginResponse;
+}
+
+impl SendActivity for GetPersonDetails {
+ type Response = GetPersonDetailsResponse;
+}
+
+impl SendActivity for GetPrivateMessages {
+ type Response = PrivateMessagesResponse;
+}
+
+impl SendActivity for CreateSite {
+ type Response = SiteResponse;
+}
+
+impl SendActivity for EditSite {
+ type Response = SiteResponse;
+}
+
+impl SendActivity for GetSite {
+ type Response = GetSiteResponse;
+}
+
+impl SendActivity for GetCommunity {
+ type Response = GetCommunityResponse;
+}
+
+impl SendActivity for ListCommunities {
+ type Response = ListCommunitiesResponse;
+}
+
+impl SendActivity for CreateCommunity {
+ type Response = CommunityResponse;
+}
+
+impl SendActivity for GetPost {
+ type Response = GetPostResponse;
+}
+
+impl SendActivity for GetPosts {
+ type Response = GetPostsResponse;
+}
+
+impl SendActivity for GetComment {
+ type Response = CommentResponse;
+}
+
+impl SendActivity for GetComments {
+ type Response = GetCommentsResponse;
+}
+
+impl SendActivity for Login {
+ type Response = LoginResponse;
+}
+
+impl SendActivity for GetCaptcha {
+ type Response = GetCaptchaResponse;
+}
+
+impl SendActivity for GetReplies {
+ type Response = GetRepliesResponse;
+}
+
+impl SendActivity for AddAdmin {
+ type Response = AddAdminResponse;
+}
+
+impl SendActivity for GetUnreadRegistrationApplicationCount {
+ type Response = GetUnreadRegistrationApplicationCountResponse;
+}
+
+impl SendActivity for ListRegistrationApplications {
+ type Response = ListRegistrationApplicationsResponse;
+}
+
+impl SendActivity for ApproveRegistrationApplication {
+ type Response = RegistrationApplicationResponse;
+}
+
+impl SendActivity for GetBannedPersons {
+ type Response = BannedPersonsResponse;
+}
+
+impl SendActivity for BlockPerson {
+ type Response = BlockPersonResponse;
+}
+
+impl SendActivity for GetPersonMentions {
+ type Response = GetPersonMentionsResponse;
+}
+
+impl SendActivity for MarkPersonMentionAsRead {
+ type Response = PersonMentionResponse;
+}
+
+impl SendActivity for MarkCommentReplyAsRead {
+ type Response = CommentReplyResponse;
+}
+
+impl SendActivity for MarkAllAsRead {
+ type Response = GetRepliesResponse;
+}
+
+impl SendActivity for PasswordReset {
+ type Response = PasswordResetResponse;
+}
+
+impl SendActivity for PasswordChangeAfterReset {
+ type Response = LoginResponse;
+}
+
+impl SendActivity for UserJoin {
+ type Response = UserJoinResponse;
+}
+
+impl SendActivity for PostJoin {
+ type Response = PostJoinResponse;
+}
+
+impl SendActivity for CommunityJoin {
+ type Response = CommunityJoinResponse;
+}
+
+impl SendActivity for ModJoin {
+ type Response = ModJoinResponse;
+}
+
+impl SendActivity for SaveUserSettings {
+ type Response = LoginResponse;
+}
+
+impl SendActivity for ChangePassword {
+ type Response = LoginResponse;
+}
+
+impl SendActivity for GetReportCount {
+ type Response = GetReportCountResponse;
+}
+
+impl SendActivity for GetUnreadCount {
+ type Response = GetUnreadCountResponse;
+}
+
+impl SendActivity for VerifyEmail {
+ type Response = VerifyEmailResponse;
+}
+
+impl SendActivity for MarkPrivateMessageAsRead {
+ type Response = PrivateMessageResponse;
+}
+
+impl SendActivity for CreatePrivateMessageReport {
+ type Response = PrivateMessageReportResponse;
+}
+
+impl SendActivity for ResolvePrivateMessageReport {
+ type Response = PrivateMessageReportResponse;
+}
+
+impl SendActivity for ListPrivateMessageReports {
+ type Response = ListPrivateMessageReportsResponse;
+}
+
+impl SendActivity for GetModlog {
+ type Response = GetModlogResponse;
+}
+
+impl SendActivity for PurgePerson {
+ type Response = PurgeItemResponse;
+}
+
+impl SendActivity for PurgeCommunity {
+ type Response = PurgeItemResponse;
+}
+
+impl SendActivity for PurgePost {
+ type Response = PurgeItemResponse;
+}
+
+impl SendActivity for PurgeComment {
+ type Response = PurgeItemResponse;
+}
+
+impl SendActivity for Search {
+ type Response = SearchResponse;
+}
+
+impl SendActivity for ResolveObject {
+ type Response = ResolveObjectResponse;
+}
+
+impl SendActivity for TransferCommunity {
+ type Response = GetCommunityResponse;
+}
+
+impl SendActivity for LeaveAdmin {
+ type Response = GetSiteResponse;
+}
+
+impl SendActivity for MarkPostAsRead {
+ type Response = PostResponse;
+}
+
+impl SendActivity for SavePost {
+ type Response = PostResponse;
+}
+
+impl SendActivity for ListPostReports {
+ type Response = ListPostReportsResponse;
+}
+
+impl SendActivity for ResolvePostReport {
+ type Response = PostReportResponse;
+}
+
+impl SendActivity for GetSiteMetadata {
+ type Response = GetSiteMetadataResponse;
+}
+
+impl SendActivity for SaveComment {
+ type Response = CommentResponse;
+}
+
+impl SendActivity for ListCommentReports {
+ type Response = ListCommentReportsResponse;
+}
+
+impl SendActivity for ResolveCommentReport {
+ type Response = CommentReportResponse;
+}
use crate::{
+ activities::community::send_activity_in_community,
+ activity_lists::AnnouncableActivities,
+ fetcher::post_or_comment::PostOrComment,
objects::{comment::ApubComment, person::ApubPerson, post::ApubPost},
- protocol::activities::voting::vote::VoteType,
+ protocol::activities::voting::{
+ undo_vote::UndoVote,
+ vote::{Vote, VoteType},
+ },
+ SendActivity,
};
+use activitypub_federation::core::object_id::ObjectId;
use lemmy_api_common::{
+ comment::{CommentResponse, CreateCommentLike},
+ context::LemmyContext,
+ post::{CreatePostLike, PostResponse},
+ sensitive::Sensitive,
+ utils::get_local_user_view_from_jwt,
websocket::{
send::{send_comment_ws_message_simple, send_post_ws_message},
UserOperation,
},
- LemmyContext,
};
use lemmy_db_schema::{
+ newtypes::CommunityId,
source::{
comment::{CommentLike, CommentLikeForm},
+ community::Community,
+ person::Person,
post::{PostLike, PostLikeForm},
},
- traits::Likeable,
+ traits::{Crud, Likeable},
};
use lemmy_utils::error::LemmyError;
pub mod undo_vote;
pub mod vote;
+#[async_trait::async_trait(?Send)]
+impl SendActivity for CreatePostLike {
+ type Response = PostResponse;
+
+ async fn send_activity(
+ request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let object_id = ObjectId::new(response.post_view.post.ap_id.clone());
+ let community_id = response.post_view.community.id;
+ send_activity(
+ object_id,
+ community_id,
+ request.score,
+ &request.auth,
+ context,
+ )
+ .await
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for CreateCommentLike {
+ type Response = CommentResponse;
+
+ async fn send_activity(
+ request: &Self,
+ response: &Self::Response,
+ context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ let object_id = ObjectId::new(response.comment_view.comment.ap_id.clone());
+ let community_id = response.comment_view.community.id;
+ send_activity(
+ object_id,
+ community_id,
+ request.score,
+ &request.auth,
+ context,
+ )
+ .await
+ }
+}
+
+async fn send_activity(
+ object_id: ObjectId<PostOrComment>,
+ community_id: CommunityId,
+ score: i16,
+ jwt: &Sensitive<String>,
+ context: &LemmyContext,
+) -> Result<(), LemmyError> {
+ let community = Community::read(context.pool(), community_id).await?.into();
+ let local_user_view = get_local_user_view_from_jwt(jwt, context.pool(), context.secret()).await?;
+ let actor = Person::read(context.pool(), local_user_view.person.id)
+ .await?
+ .into();
+
+ // score of 1 means upvote, -1 downvote, 0 undo a previous vote
+ if score != 0 {
+ let vote = Vote::new(object_id, &actor, &community, score.try_into()?, context)?;
+ let activity = AnnouncableActivities::Vote(vote);
+ send_activity_in_community(activity, &actor, &community, vec![], false, context).await
+ } else {
+ // Lemmy API doesnt distinguish between Undo/Like and Undo/Dislike, so we hardcode it here.
+ let vote = Vote::new(object_id, &actor, &community, VoteType::Like, context)?;
+ let undo_vote = UndoVote::new(vote, &actor, &community, context)?;
+ let activity = AnnouncableActivities::UndoVote(undo_vote);
+ send_activity_in_community(activity, &actor, &community, vec![], false, context).await
+ }
+}
+
#[tracing::instrument(skip_all)]
async fn vote_comment(
vote_type: &VoteType,
use crate::{
activities::{
- community::send_activity_in_community,
generate_activity_id,
verify_person_in_community,
voting::{undo_vote_comment, undo_vote_post},
},
- activity_lists::AnnouncableActivities,
local_instance,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::{
- activities::voting::{
- undo_vote::UndoVote,
- vote::{Vote, VoteType},
- },
+ activities::voting::{undo_vote::UndoVote, vote::Vote},
InCommunity,
},
ActorType,
utils::verify_urls_match,
};
use activitystreams_kinds::activity::UndoType;
-use lemmy_api_common::LemmyContext;
-use lemmy_db_schema::{newtypes::CommunityId, source::community::Community, traits::Crud};
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use url::Url;
impl UndoVote {
- /// UndoVote has as:Public value in cc field, unlike other activities. This indicates to other
- /// software (like GNU social, or presumably Mastodon), that the like actor should not be
- /// disclosed.
- #[tracing::instrument(skip_all)]
- pub async fn send(
- object: &PostOrComment,
+ pub(in crate::activities::voting) fn new(
+ vote: Vote,
actor: &ApubPerson,
- community_id: CommunityId,
- kind: VoteType,
+ community: &ApubCommunity,
context: &LemmyContext,
- ) -> Result<(), LemmyError> {
- let community: ApubCommunity = Community::read(context.pool(), community_id).await?.into();
-
- let object = Vote::new(object, actor, &community, kind.clone(), context)?;
- let id = generate_activity_id(
- UndoType::Undo,
- &context.settings().get_protocol_and_hostname(),
- )?;
- let undo_vote = UndoVote {
+ ) -> Result<Self, LemmyError> {
+ Ok(UndoVote {
actor: ObjectId::new(actor.actor_id()),
- object,
+ object: vote,
kind: UndoType::Undo,
- id: id.clone(),
+ id: generate_activity_id(
+ UndoType::Undo,
+ &context.settings().get_protocol_and_hostname(),
+ )?,
audience: Some(ObjectId::new(community.actor_id())),
- };
- let activity = AnnouncableActivities::UndoVote(undo_vote);
- send_activity_in_community(activity, actor, &community, vec![], false, context).await
+ })
}
}
use crate::{
activities::{
- community::send_activity_in_community,
generate_activity_id,
verify_person_in_community,
voting::{vote_comment, vote_post},
},
- activity_lists::AnnouncableActivities,
local_instance,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::{
};
use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
use anyhow::anyhow;
-use lemmy_api_common::LemmyContext;
-use lemmy_db_schema::{
- newtypes::CommunityId,
- source::{community::Community, local_site::LocalSite},
- traits::Crud,
-};
+use lemmy_api_common::context::LemmyContext;
+use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_utils::error::LemmyError;
use url::Url;
-/// Vote has as:Public value in cc field, unlike other activities. This indicates to other software
-/// (like GNU social, or presumably Mastodon), that the like actor should not be disclosed.
impl Vote {
pub(in crate::activities::voting) fn new(
- object: &PostOrComment,
+ object_id: ObjectId<PostOrComment>,
actor: &ApubPerson,
community: &ApubCommunity,
kind: VoteType,
) -> Result<Vote, LemmyError> {
Ok(Vote {
actor: ObjectId::new(actor.actor_id()),
- object: ObjectId::new(object.ap_id()),
+ object: object_id,
kind: kind.clone(),
id: generate_activity_id(kind, &context.settings().get_protocol_and_hostname())?,
audience: Some(ObjectId::new(community.actor_id())),
})
}
-
- #[tracing::instrument(skip_all)]
- pub async fn send(
- object: &PostOrComment,
- actor: &ApubPerson,
- community_id: CommunityId,
- kind: VoteType,
- context: &LemmyContext,
- ) -> Result<(), LemmyError> {
- let community = Community::read(context.pool(), community_id).await?.into();
- let vote = Vote::new(object, actor, &community, kind, context)?;
-
- let activity = AnnouncableActivities::Vote(vote);
- send_activity_in_community(activity, actor, &community, vec![], false, context).await
- }
}
#[async_trait::async_trait(?Send)]
},
};
use activitypub_federation::{data::Data, deser::context::WithContext, traits::ActivityHandler};
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use serde::{Deserialize, Serialize};
use url::Url;
-use crate::PerformCrud;
+use crate::{
+ api::PerformApub,
+ fetcher::resolve_actor_identifier,
+ objects::community::ApubCommunity,
+};
use actix_web::web::Data;
use lemmy_api_common::{
comment::{GetComments, GetCommentsResponse},
+ context::LemmyContext,
utils::{
check_private_instance,
get_local_user_view_from_jwt_opt,
listing_type_with_site_default,
},
- LemmyContext,
};
-use lemmy_apub::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity};
use lemmy_db_schema::{
source::{comment::Comment, community::Community, local_site::LocalSite},
traits::{Crud, DeleteableOrRemoveable},
use lemmy_utils::{error::LemmyError, ConnectionId};
#[async_trait::async_trait(?Send)]
-impl PerformCrud for GetComments {
+impl PerformApub for GetComments {
type Response = GetCommentsResponse;
#[tracing::instrument(skip(context, _websocket_id))]
-use crate::PerformCrud;
+use crate::{
+ api::PerformApub,
+ fetcher::resolve_actor_identifier,
+ objects::community::ApubCommunity,
+};
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
post::{GetPosts, GetPostsResponse},
utils::{
check_private_instance,
get_local_user_view_from_jwt_opt,
listing_type_with_site_default,
},
- LemmyContext,
};
-use lemmy_apub::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity};
use lemmy_db_schema::{
source::{community::Community, local_site::LocalSite},
traits::DeleteableOrRemoveable,
use lemmy_utils::{error::LemmyError, ConnectionId};
#[async_trait::async_trait(?Send)]
-impl PerformCrud for GetPosts {
+impl PerformApub for GetPosts {
type Response = GetPostsResponse;
#[tracing::instrument(skip(context, _websocket_id))]
--- /dev/null
+use actix_web::web::Data;
+use lemmy_api_common::context::LemmyContext;
+use lemmy_utils::{error::LemmyError, ConnectionId};
+
+mod list_comments;
+mod list_posts;
+mod read_community;
+mod read_person;
+mod resolve_object;
+mod search;
+
+#[async_trait::async_trait(?Send)]
+pub trait PerformApub {
+ type Response: serde::ser::Serialize + Send;
+
+ async fn perform(
+ &self,
+ context: &Data<LemmyContext>,
+ websocket_id: Option<ConnectionId>,
+ ) -> Result<Self::Response, LemmyError>;
+}
-use crate::PerformCrud;
+use crate::{
+ api::PerformApub,
+ fetcher::resolve_actor_identifier,
+ objects::community::ApubCommunity,
+};
use actix_web::web::Data;
use lemmy_api_common::{
community::{GetCommunity, GetCommunityResponse},
+ context::LemmyContext,
utils::{check_private_instance, get_local_user_view_from_jwt_opt},
websocket::messages::GetCommunityUsersOnline,
- LemmyContext,
-};
-use lemmy_apub::{
- fetcher::resolve_actor_identifier,
- objects::{community::ApubCommunity, instance::instance_actor_id_from_url},
};
use lemmy_db_schema::{
impls::actor_language::default_post_language,
use lemmy_utils::{error::LemmyError, ConnectionId};
#[async_trait::async_trait(?Send)]
-impl PerformCrud for GetCommunity {
+impl PerformApub for GetCommunity {
type Response = GetCommunityResponse;
#[tracing::instrument(skip(context, _websocket_id))]
.await
.unwrap_or(1);
- let site_id = instance_actor_id_from_url(community_view.community.actor_id.clone().into());
+ let site_id =
+ Site::instance_actor_id_from_url(community_view.community.actor_id.clone().into());
let mut site = Site::read_from_apub_id(context.pool(), site_id).await?;
// no need to include metadata for local site (its already available through other endpoints).
// this also prevents us from leaking the federation private key.
-use crate::PerformCrud;
+use crate::{api::PerformApub, fetcher::resolve_actor_identifier, objects::person::ApubPerson};
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
person::{GetPersonDetails, GetPersonDetailsResponse},
utils::{check_private_instance, get_local_user_view_from_jwt_opt},
- LemmyContext,
};
-use lemmy_apub::{fetcher::resolve_actor_identifier, objects::person::ApubPerson};
use lemmy_db_schema::{
source::{local_site::LocalSite, person::Person},
utils::post_to_comment_sort_type,
use lemmy_utils::{error::LemmyError, ConnectionId};
#[async_trait::async_trait(?Send)]
-impl PerformCrud for GetPersonDetails {
+impl PerformApub for GetPersonDetails {
type Response = GetPersonDetailsResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
-use crate::Perform;
+use crate::{
+ api::PerformApub,
+ fetcher::search::{search_query_to_object_id, SearchableObjects},
+};
use actix_web::web::Data;
use diesel::NotFound;
use lemmy_api_common::{
+ context::LemmyContext,
site::{ResolveObject, ResolveObjectResponse},
utils::{check_private_instance, get_local_user_view_from_jwt_opt},
- LemmyContext,
};
-use lemmy_apub::fetcher::search::{search_query_to_object_id, SearchableObjects};
use lemmy_db_schema::{newtypes::PersonId, source::local_site::LocalSite, utils::DbPool};
use lemmy_db_views::structs::{CommentView, PostView};
use lemmy_db_views_actor::structs::{CommunityView, PersonViewSafe};
use lemmy_utils::{error::LemmyError, ConnectionId};
#[async_trait::async_trait(?Send)]
-impl Perform for ResolveObject {
+impl PerformApub for ResolveObject {
type Response = ResolveObjectResponse;
#[tracing::instrument(skip(context, _websocket_id))]
-use crate::Perform;
+use crate::{
+ api::PerformApub,
+ fetcher::resolve_actor_identifier,
+ objects::community::ApubCommunity,
+};
use actix_web::web::Data;
use lemmy_api_common::{
+ context::LemmyContext,
site::{Search, SearchResponse},
utils::{check_private_instance, get_local_user_view_from_jwt_opt},
- LemmyContext,
};
-use lemmy_apub::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity};
use lemmy_db_schema::{
source::{community::Community, local_site::LocalSite},
traits::DeleteableOrRemoveable,
use lemmy_utils::{error::LemmyError, ConnectionId};
#[async_trait::async_trait(?Send)]
-impl Perform for Search {
+impl PerformApub for Search {
type Response = SearchResponse;
#[tracing::instrument(skip(context, _websocket_id))]
};
use activitystreams_kinds::collection::OrderedCollectionType;
use chrono::NaiveDateTime;
-use lemmy_api_common::generate_moderators_url;
+use lemmy_api_common::utils::generate_moderators_url;
use lemmy_db_schema::{
source::community::{CommunityModerator, CommunityModeratorForm},
traits::Joinable,
use activitystreams_kinds::collection::OrderedCollectionType;
use chrono::NaiveDateTime;
use futures::future::join_all;
-use lemmy_api_common::generate_outbox_url;
+use lemmy_api_common::utils::generate_outbox_url;
use lemmy_db_schema::{
source::{person::Person, post::Post},
traits::Crud,
use crate::objects::community::ApubCommunity;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
pub(crate) mod community_moderators;
pub(crate) mod community_outbox;
use crate::{fetcher::webfinger::webfinger_resolve_actor, ActorType};
use activitypub_federation::traits::ApubObject;
use itertools::Itertools;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::traits::ApubActor;
use lemmy_utils::error::LemmyError;
};
use activitypub_federation::traits::ApubObject;
use chrono::NaiveDateTime;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::{
source::{community::Community, post::Post},
traits::Crud,
}
}
-impl PostOrComment {
- pub(crate) fn ap_id(&self) -> Url {
- match self {
- PostOrComment::Post(p) => p.ap_id.clone(),
- PostOrComment::Comment(c) => c.ap_id.clone(),
- }
- .into()
- }
-}
-
#[async_trait::async_trait(?Send)]
impl InCommunity for PostOrComment {
async fn community(
};
use activitypub_federation::{core::object_id::ObjectId, traits::ApubObject};
use chrono::NaiveDateTime;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use serde::Deserialize;
use url::Url;
/// ObjectId directly, or a webfinger identifier (@user@example.com or !community@example.com)
/// which gets resolved to an URL.
#[tracing::instrument(skip_all)]
-pub async fn search_query_to_object_id(
+pub(crate) async fn search_query_to_object_id(
query: &str,
local_only: bool,
context: &LemmyContext,
/// The types of ActivityPub objects that can be fetched directly by searching for their ID.
#[derive(Debug)]
-pub enum SearchableObjects {
+pub(crate) enum SearchableObjects {
Person(ApubPerson),
Community(ApubCommunity),
Post(ApubPost),
#[derive(Deserialize)]
#[serde(untagged)]
-pub enum SearchableApubTypes {
+pub(crate) enum SearchableApubTypes {
Group(Group),
Person(Person),
Page(Page),
};
use activitypub_federation::traits::{Actor, ApubObject};
use chrono::NaiveDateTime;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use serde::{Deserialize, Serialize};
use url::Url;
use activitypub_federation::{core::object_id::ObjectId, traits::ApubObject};
use anyhow::anyhow;
use itertools::Itertools;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::newtypes::DbUrl;
use lemmy_utils::{error::LemmyError, WebfingerResponse};
use tracing::debug;
/// Turns a person id like `@name@example.com` into an apub ID, like `https://example.com/user/name`,
/// using webfinger.
-#[tracing::instrument(skip_all)]
pub(crate) async fn webfinger_resolve_actor<Kind>(
identifier: &str,
local_only: bool,
use activitypub_federation::traits::ApubObject;
use actix_web::{web, web::Path, HttpResponse};
use diesel::result::Error::NotFound;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::{newtypes::CommentId, source::comment::Comment, traits::Crud};
use lemmy_utils::error::LemmyError;
use serde::Deserialize;
traits::ApubObject,
};
use actix_web::{web, HttpRequest, HttpResponse};
-use lemmy_api_common::{generate_outbox_url, LemmyContext};
+use lemmy_api_common::{context::LemmyContext, utils::generate_outbox_url};
use lemmy_db_schema::{source::community::Community, traits::ApubActor};
use lemmy_utils::error::LemmyError;
use serde::Deserialize;
};
use actix_web::{web, HttpRequest, HttpResponse};
use http::StatusCode;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::source::activity::Activity;
use lemmy_utils::error::LemmyError;
use once_cell::sync::OnceCell;
};
use activitypub_federation::{deser::context::WithContext, traits::ApubObject};
use actix_web::{web, HttpRequest, HttpResponse};
-use lemmy_api_common::{generate_outbox_url, LemmyContext};
+use lemmy_api_common::{context::LemmyContext, utils::generate_outbox_url};
use lemmy_db_schema::{source::person::Person, traits::ApubActor};
use lemmy_utils::error::LemmyError;
use serde::Deserialize;
use activitypub_federation::traits::ApubObject;
use actix_web::{web, HttpResponse};
use diesel::result::Error::NotFound;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::{newtypes::PostId, source::post::Post, traits::Crud};
use lemmy_utils::error::LemmyError;
use serde::Deserialize;
};
use activitypub_federation::{deser::context::WithContext, traits::ApubObject};
use actix_web::{web, HttpRequest, HttpResponse};
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_views::structs::SiteView;
use lemmy_utils::error::LemmyError;
use url::Url;
UrlVerifier,
};
use async_trait::async_trait;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::{
source::{activity::Activity, instance::Instance, local_site::LocalSite},
utils::DbPool,
pub mod activities;
pub(crate) mod activity_lists;
+pub mod api;
pub(crate) mod collections;
pub mod fetcher;
pub mod http;
PublicKey::new_main_key(self.actor_id(), self.public_key().to_string())
}
}
+
+#[async_trait::async_trait(?Send)]
+pub trait SendActivity {
+ type Response;
+
+ async fn send_activity(
+ _request: &Self,
+ _response: &Self::Response,
+ _context: &LemmyContext,
+ ) -> Result<(), LemmyError> {
+ Ok(())
+ }
+}
};
use activitypub_federation::core::object_id::ObjectId;
use activitystreams_kinds::link::MentionType;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::{
source::{comment::Comment, person::Person, post::Post},
traits::Crud,
};
use activitystreams_kinds::{object::NoteType, public};
use chrono::NaiveDateTime;
-use lemmy_api_common::{utils::local_site_opt_to_slur_regex, LemmyContext};
+use lemmy_api_common::{context::LemmyContext, utils::local_site_opt_to_slur_regex};
use lemmy_db_schema::{
source::{
comment::{Comment, CommentInsertForm, CommentUpdateForm},
use url::Url;
#[derive(Clone, Debug)]
-pub struct ApubComment(Comment);
+pub struct ApubComment(pub(crate) Comment);
impl Deref for ApubComment {
type Target = Comment;
use activitystreams_kinds::actor::GroupType;
use chrono::NaiveDateTime;
use itertools::Itertools;
-use lemmy_api_common::{generate_moderators_url, generate_outbox_url, LemmyContext};
+use lemmy_api_common::{
+ context::LemmyContext,
+ utils::{generate_moderators_url, generate_outbox_url},
+};
use lemmy_db_schema::{
source::{
actor_language::CommunityLanguage,
utils::verify_domains_match,
};
use chrono::NaiveDateTime;
-use lemmy_api_common::{utils::local_site_opt_to_slur_regex, LemmyContext};
+use lemmy_api_common::{context::LemmyContext, utils::local_site_opt_to_slur_regex};
use lemmy_db_schema::{
source::{
actor_language::SiteLanguage,
}
}
-/// Instance actor is at the root path, so we simply need to clear the path and other unnecessary
-/// parts of the url.
-pub fn instance_actor_id_from_url(mut url: Url) -> Url {
- url.set_fragment(None);
- url.set_path("");
- url.set_query(None);
- url
-}
-
/// try to fetch the instance actor (to make things like instance rules available)
pub(in crate::objects) async fn fetch_instance_actor_for_object(
object_id: Url,
request_counter: &mut i32,
) {
// try to fetch the instance actor (to make things like instance rules available)
- let instance_id = instance_actor_id_from_url(object_id);
+ let instance_id = Site::instance_actor_id_from_url(object_id);
let site = ObjectId::<ApubSite>::new(instance_id.clone())
.dereference(context, local_instance(context).await, request_counter)
.await;
use actix::Actor;
use anyhow::anyhow;
use lemmy_api_common::{
+ context::LemmyContext,
request::build_user_agent,
websocket::chat_server::ChatServer,
- LemmyContext,
};
use lemmy_db_schema::{source::secret::Secret, utils::build_db_pool_for_tests};
use lemmy_utils::{
pool.clone(),
|_, _, _, _| Box::pin(x()),
|_, _, _, _| Box::pin(x()),
+ |_, _, _, _| Box::pin(x()),
client.clone(),
settings.clone(),
secret.clone(),
utils::verify_domains_match,
};
use chrono::NaiveDateTime;
-use lemmy_api_common::{generate_outbox_url, utils::local_site_opt_to_slur_regex, LemmyContext};
+use lemmy_api_common::{
+ context::LemmyContext,
+ utils::{generate_outbox_url, local_site_opt_to_slur_regex},
+};
use lemmy_db_schema::{
source::{
instance::Instance,
use activitystreams_kinds::public;
use chrono::NaiveDateTime;
use lemmy_api_common::{
+ context::LemmyContext,
request::fetch_site_data,
utils::local_site_opt_to_slur_regex,
- LemmyContext,
};
use lemmy_db_schema::{
self,
use url::Url;
#[derive(Clone, Debug)]
-pub struct ApubPost(Post);
+pub struct ApubPost(pub(crate) Post);
impl Deref for ApubPost {
type Target = Post;
utils::verify_domains_match,
};
use chrono::NaiveDateTime;
-use lemmy_api_common::{utils::check_person_block, LemmyContext};
+use lemmy_api_common::{context::LemmyContext, utils::check_person_block};
use lemmy_db_schema::{
source::{
person::Person,
use url::Url;
#[derive(Clone, Debug)]
-pub struct ApubPrivateMessage(PrivateMessage);
+pub struct ApubPrivateMessage(pub(crate) PrivateMessage);
impl Deref for ApubPrivateMessage {
type Target = PrivateMessage;
use activitystreams_kinds::activity::BlockType;
use anyhow::anyhow;
use chrono::{DateTime, FixedOffset};
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
};
use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
use activitystreams_kinds::activity::UndoType;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
};
use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
use activitystreams_kinds::activity::AddType;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use serde::{Deserialize, Serialize};
use url::Url;
};
use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
use activitystreams_kinds::activity::RemoveType;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use serde::{Deserialize, Serialize};
use url::Url;
};
use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one};
use activitystreams_kinds::activity::FlagType;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use serde::{Deserialize, Serialize};
use url::Url;
};
use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
use activitystreams_kinds::activity::UpdateType;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use serde::{Deserialize, Serialize};
use url::Url;
protocol::{activities::CreateOrUpdateType, objects::note::Note, InCommunity},
};
use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::{source::community::Community, traits::Crud};
use lemmy_utils::error::LemmyError;
use serde::{Deserialize, Serialize};
protocol::{activities::CreateOrUpdateType, objects::page::Page, InCommunity},
};
use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use serde::{Deserialize, Serialize};
use url::Url;
use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
use activitystreams_kinds::activity::DeleteType;
use anyhow::anyhow;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::{
source::{community::Community, post::Post},
traits::Crud,
};
use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
use activitystreams_kinds::activity::UndoType;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
};
use activitypub_federation::core::object_id::ObjectId;
use activitystreams_kinds::activity::UndoType;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use serde::{Deserialize, Serialize};
use url::Url;
protocol::InCommunity,
};
use activitypub_federation::core::object_id::ObjectId;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_utils::error::LemmyError;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
use activitystreams_kinds::collection::CollectionType;
-use lemmy_api_common::{generate_followers_url, LemmyContext};
+use lemmy_api_common::{context::LemmyContext, utils::generate_followers_url};
use lemmy_db_schema::source::community::Community;
use lemmy_db_views_actor::structs::CommunityFollowerView;
use lemmy_utils::error::LemmyError;
use crate::{local_instance, objects::community::ApubCommunity};
use activitypub_federation::{deser::values::MediaTypeMarkdown, utils::fetch_object_http};
use activitystreams_kinds::object::ImageType;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::newtypes::DbUrl;
use lemmy_utils::error::LemmyError;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
};
use activitystreams_kinds::actor::GroupType;
use chrono::{DateTime, FixedOffset};
-use lemmy_api_common::{utils::local_site_opt_to_slur_regex, LemmyContext};
+use lemmy_api_common::{context::LemmyContext, utils::local_site_opt_to_slur_regex};
use lemmy_db_schema::{
newtypes::InstanceId,
source::community::{CommunityInsertForm, CommunityUpdateForm},
};
use activitystreams_kinds::object::NoteType;
use chrono::{DateTime, FixedOffset};
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::{
source::{community::Community, post::Post},
traits::Crud,
};
use chrono::{DateTime, FixedOffset};
use itertools::Itertools;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::newtypes::DbUrl;
use lemmy_utils::error::LemmyError;
use serde::{Deserialize, Serialize};
let conn = &mut get_conn(pool).await?;
site.order_by(id).offset(1).get_results::<Self>(conn).await
}
+
+ /// Instance actor is at the root path, so we simply need to clear the path and other unnecessary
+ /// parts of the url.
+ pub fn instance_actor_id_from_url(mut url: Url) -> Url {
+ url.set_fragment(None);
+ url.set_path("");
+ url.set_query(None);
+ url
+ }
}
lemmy_db_views = { workspace = true }
lemmy_db_views_actor = { workspace = true }
lemmy_db_schema = { workspace = true }
-lemmy_api_common = { workspace = true }
+lemmy_api_common = { workspace = true, features = ["full"] }
diesel = { workspace = true }
actix-web = { workspace = true }
anyhow = { workspace = true }
use actix_web::{error::ErrorBadRequest, web, Error, HttpRequest, HttpResponse, Result};
use anyhow::anyhow;
use chrono::{DateTime, NaiveDateTime, Utc};
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::{
newtypes::LocalUserId,
source::{community::Community, local_user::LocalUser, person::Person},
HttpResponse,
};
use futures::stream::{Stream, StreamExt};
-use lemmy_api_common::{utils::get_local_user_view_from_jwt, LemmyContext};
+use lemmy_api_common::{context::LemmyContext, utils::get_local_user_view_from_jwt};
use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_utils::{claims::Claims, rate_limit::RateLimitCell, REQWEST_TIMEOUT};
use reqwest::Body;
use actix_web::{error::ErrorBadRequest, web, Error, HttpResponse, Result};
use anyhow::anyhow;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_views::structs::SiteView;
use lemmy_utils::{error::LemmyError, version};
use serde::{Deserialize, Serialize};
use actix_web::{web, web::Query, HttpResponse};
use anyhow::Context;
-use lemmy_api_common::LemmyContext;
+use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::{
source::{community::Community, person::Person},
traits::ApubActor,
RemoveCommunity,
TransferCommunity,
},
+ context::LemmyContext,
person::{
AddAdmin,
BanPerson,
},
websocket::{
routes::chat_route,
+ serialize_websocket_message,
structs::{CommunityJoin, ModJoin, PostJoin, UserJoin},
+ UserOperation,
+ UserOperationApub,
+ UserOperationCrud,
},
- LemmyContext,
};
use lemmy_api_crud::PerformCrud;
-use lemmy_utils::rate_limit::RateLimitCell;
+use lemmy_apub::{api::PerformApub, SendActivity};
+use lemmy_utils::{error::LemmyError, rate_limit::RateLimitCell, ConnectionId};
use serde::Deserialize;
+use std::result;
pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
cfg.service(
.service(
web::resource("/search")
.wrap(rate_limit.search())
- .route(web::get().to(route_get::<Search>)),
+ .route(web::get().to(route_get_apub::<Search>)),
)
.service(
web::resource("/resolve_object")
.wrap(rate_limit.message())
- .route(web::get().to(route_get::<ResolveObject>)),
+ .route(web::get().to(route_get_apub::<ResolveObject>)),
)
// Community
.service(
.service(
web::scope("/community")
.wrap(rate_limit.message())
- .route("", web::get().to(route_get_crud::<GetCommunity>))
+ .route("", web::get().to(route_get_apub::<GetCommunity>))
.route("", web::put().to(route_post_crud::<EditCommunity>))
.route("/hide", web::put().to(route_post::<HideCommunity>))
.route("/list", web::get().to(route_get_crud::<ListCommunities>))
)
.route("/lock", web::post().to(route_post::<LockPost>))
.route("/sticky", web::post().to(route_post::<StickyPost>))
- .route("/list", web::get().to(route_get_crud::<GetPosts>))
+ .route("/list", web::get().to(route_get_apub::<GetPosts>))
.route("/like", web::post().to(route_post::<CreatePostLike>))
.route("/save", web::put().to(route_post::<SavePost>))
.route("/join", web::post().to(route_post::<PostJoin>))
)
.route("/like", web::post().to(route_post::<CreateCommentLike>))
.route("/save", web::put().to(route_post::<SaveComment>))
- .route("/list", web::get().to(route_get_crud::<GetComments>))
+ .route("/list", web::get().to(route_get_apub::<GetComments>))
.route("/report", web::post().to(route_post::<CreateCommentReport>))
.route(
"/report/resolve",
.service(
web::scope("/user")
.wrap(rate_limit.message())
- .route("", web::get().to(route_get_crud::<GetPersonDetails>))
+ .route("", web::get().to(route_get_apub::<GetPersonDetails>))
.route("/mention", web::get().to(route_get::<GetPersonMentions>))
.route(
"/mention/mark_as_read",
);
}
-async fn perform<Request>(
- data: Request,
+async fn perform<'a, Data>(
+ data: Data,
context: web::Data<LemmyContext>,
) -> Result<HttpResponse, Error>
where
- Request: Perform,
- Request: Send + 'static,
+ Data: Perform
+ + SendActivity<Response = <Data as Perform>::Response>
+ + Clone
+ + Deserialize<'a>
+ + Send
+ + 'static,
{
- let res = data
- .perform(&context, None)
- .await
- .map(|json| HttpResponse::Ok().json(json))?;
- Ok(res)
+ let res = data.perform(&context, None).await?;
+ SendActivity::send_activity(&data, &res, &context).await?;
+ Ok(HttpResponse::Ok().json(res))
}
async fn route_get<'a, Data>(
context: web::Data<LemmyContext>,
) -> Result<HttpResponse, Error>
where
- Data: Deserialize<'a> + Send + 'static + Perform,
+ Data: Perform
+ + SendActivity<Response = <Data as Perform>::Response>
+ + Clone
+ + Deserialize<'a>
+ + Send
+ + 'static,
{
perform::<Data>(data.0, context).await
}
+async fn route_get_apub<'a, Data>(
+ data: web::Query<Data>,
+ context: web::Data<LemmyContext>,
+) -> Result<HttpResponse, Error>
+where
+ Data: PerformApub
+ + SendActivity<Response = <Data as PerformApub>::Response>
+ + Clone
+ + Deserialize<'a>
+ + Send
+ + 'static,
+{
+ let res = data.perform(&context, None).await?;
+ SendActivity::send_activity(&data.0, &res, &context).await?;
+ Ok(HttpResponse::Ok().json(res))
+}
+
async fn route_post<'a, Data>(
data: web::Json<Data>,
context: web::Data<LemmyContext>,
) -> Result<HttpResponse, Error>
where
- Data: Deserialize<'a> + Send + 'static + Perform,
+ Data: Perform
+ + SendActivity<Response = <Data as Perform>::Response>
+ + Clone
+ + Deserialize<'a>
+ + Send
+ + 'static,
{
perform::<Data>(data.0, context).await
}
-async fn perform_crud<Request>(
- data: Request,
+async fn perform_crud<'a, Data>(
+ data: Data,
context: web::Data<LemmyContext>,
) -> Result<HttpResponse, Error>
where
- Request: PerformCrud,
- Request: Send + 'static,
+ Data: PerformCrud
+ + SendActivity<Response = <Data as PerformCrud>::Response>
+ + Clone
+ + Deserialize<'a>
+ + Send
+ + 'static,
{
- let res = data
- .perform(&context, None)
- .await
- .map(|json| HttpResponse::Ok().json(json))?;
- Ok(res)
+ let res = data.perform(&context, None).await?;
+ SendActivity::send_activity(&data, &res, &context).await?;
+ Ok(HttpResponse::Ok().json(res))
}
async fn route_get_crud<'a, Data>(
context: web::Data<LemmyContext>,
) -> Result<HttpResponse, Error>
where
- Data: Deserialize<'a> + Send + 'static + PerformCrud,
+ Data: PerformCrud
+ + SendActivity<Response = <Data as PerformCrud>::Response>
+ + Clone
+ + Deserialize<'a>
+ + Send
+ + 'static,
{
perform_crud::<Data>(data.0, context).await
}
context: web::Data<LemmyContext>,
) -> Result<HttpResponse, Error>
where
- Data: Deserialize<'a> + Send + 'static + PerformCrud,
+ Data: PerformCrud
+ + SendActivity<Response = <Data as PerformCrud>::Response>
+ + Clone
+ + Deserialize<'a>
+ + Send
+ + 'static,
{
perform_crud::<Data>(data.0, context).await
}
+
+pub async fn match_websocket_operation_crud(
+ context: LemmyContext,
+ id: ConnectionId,
+ op: UserOperationCrud,
+ data: &str,
+) -> result::Result<String, LemmyError> {
+ match op {
+ // User ops
+ UserOperationCrud::Register => {
+ do_websocket_operation_crud::<Register>(context, id, op, data).await
+ }
+ UserOperationCrud::DeleteAccount => {
+ do_websocket_operation_crud::<DeleteAccount>(context, id, op, data).await
+ }
+
+ // Private Message ops
+ UserOperationCrud::CreatePrivateMessage => {
+ do_websocket_operation_crud::<CreatePrivateMessage>(context, id, op, data).await
+ }
+ UserOperationCrud::EditPrivateMessage => {
+ do_websocket_operation_crud::<EditPrivateMessage>(context, id, op, data).await
+ }
+ UserOperationCrud::DeletePrivateMessage => {
+ do_websocket_operation_crud::<DeletePrivateMessage>(context, id, op, data).await
+ }
+ UserOperationCrud::GetPrivateMessages => {
+ do_websocket_operation_crud::<GetPrivateMessages>(context, id, op, data).await
+ }
+
+ // Site ops
+ UserOperationCrud::CreateSite => {
+ do_websocket_operation_crud::<CreateSite>(context, id, op, data).await
+ }
+ UserOperationCrud::EditSite => {
+ do_websocket_operation_crud::<EditSite>(context, id, op, data).await
+ }
+ UserOperationCrud::GetSite => {
+ do_websocket_operation_crud::<GetSite>(context, id, op, data).await
+ }
+
+ // Community ops
+ UserOperationCrud::ListCommunities => {
+ do_websocket_operation_crud::<ListCommunities>(context, id, op, data).await
+ }
+ UserOperationCrud::CreateCommunity => {
+ do_websocket_operation_crud::<CreateCommunity>(context, id, op, data).await
+ }
+ UserOperationCrud::EditCommunity => {
+ do_websocket_operation_crud::<EditCommunity>(context, id, op, data).await
+ }
+ UserOperationCrud::DeleteCommunity => {
+ do_websocket_operation_crud::<DeleteCommunity>(context, id, op, data).await
+ }
+ UserOperationCrud::RemoveCommunity => {
+ do_websocket_operation_crud::<RemoveCommunity>(context, id, op, data).await
+ }
+
+ // Post ops
+ UserOperationCrud::CreatePost => {
+ do_websocket_operation_crud::<CreatePost>(context, id, op, data).await
+ }
+ UserOperationCrud::GetPost => {
+ do_websocket_operation_crud::<GetPost>(context, id, op, data).await
+ }
+ UserOperationCrud::EditPost => {
+ do_websocket_operation_crud::<EditPost>(context, id, op, data).await
+ }
+ UserOperationCrud::DeletePost => {
+ do_websocket_operation_crud::<DeletePost>(context, id, op, data).await
+ }
+ UserOperationCrud::RemovePost => {
+ do_websocket_operation_crud::<RemovePost>(context, id, op, data).await
+ }
+
+ // Comment ops
+ UserOperationCrud::CreateComment => {
+ do_websocket_operation_crud::<CreateComment>(context, id, op, data).await
+ }
+ UserOperationCrud::EditComment => {
+ do_websocket_operation_crud::<EditComment>(context, id, op, data).await
+ }
+ UserOperationCrud::DeleteComment => {
+ do_websocket_operation_crud::<DeleteComment>(context, id, op, data).await
+ }
+ UserOperationCrud::RemoveComment => {
+ do_websocket_operation_crud::<RemoveComment>(context, id, op, data).await
+ }
+ UserOperationCrud::GetComment => {
+ do_websocket_operation_crud::<GetComment>(context, id, op, data).await
+ }
+ }
+}
+
+async fn do_websocket_operation_crud<'a, 'b, Data>(
+ context: LemmyContext,
+ id: ConnectionId,
+ op: UserOperationCrud,
+ data: &str,
+) -> result::Result<String, LemmyError>
+where
+ Data: PerformCrud + SendActivity<Response = <Data as PerformCrud>::Response>,
+ for<'de> Data: Deserialize<'de>,
+{
+ let parsed_data: Data = serde_json::from_str(data)?;
+ let res = parsed_data
+ .perform(&web::Data::new(context.clone()), Some(id))
+ .await?;
+ SendActivity::send_activity(&parsed_data, &res, &context).await?;
+ serialize_websocket_message(&op, &res)
+}
+
+pub async fn match_websocket_operation_apub(
+ context: LemmyContext,
+ id: ConnectionId,
+ op: UserOperationApub,
+ data: &str,
+) -> result::Result<String, LemmyError> {
+ match op {
+ UserOperationApub::GetPersonDetails => {
+ do_websocket_operation_apub::<GetPersonDetails>(context, id, op, data).await
+ }
+ UserOperationApub::GetCommunity => {
+ do_websocket_operation_apub::<GetCommunity>(context, id, op, data).await
+ }
+ UserOperationApub::GetComments => {
+ do_websocket_operation_apub::<GetComments>(context, id, op, data).await
+ }
+ UserOperationApub::GetPosts => {
+ do_websocket_operation_apub::<GetPosts>(context, id, op, data).await
+ }
+ UserOperationApub::ResolveObject => {
+ do_websocket_operation_apub::<ResolveObject>(context, id, op, data).await
+ }
+ UserOperationApub::Search => do_websocket_operation_apub::<Search>(context, id, op, data).await,
+ }
+}
+
+async fn do_websocket_operation_apub<'a, 'b, Data>(
+ context: LemmyContext,
+ id: ConnectionId,
+ op: UserOperationApub,
+ data: &str,
+) -> result::Result<String, LemmyError>
+where
+ Data: PerformApub + SendActivity<Response = <Data as PerformApub>::Response>,
+ for<'de> Data: Deserialize<'de>,
+{
+ let parsed_data: Data = serde_json::from_str(data)?;
+ let res = parsed_data
+ .perform(&web::Data::new(context.clone()), Some(id))
+ .await?;
+ SendActivity::send_activity(&parsed_data, &res, &context).await?;
+ serialize_websocket_message(&op, &res)
+}
+
+pub async fn match_websocket_operation(
+ context: LemmyContext,
+ id: ConnectionId,
+ op: UserOperation,
+ data: &str,
+) -> result::Result<String, LemmyError> {
+ match op {
+ // User ops
+ UserOperation::Login => do_websocket_operation::<Login>(context, id, op, data).await,
+ UserOperation::GetCaptcha => do_websocket_operation::<GetCaptcha>(context, id, op, data).await,
+ UserOperation::GetReplies => do_websocket_operation::<GetReplies>(context, id, op, data).await,
+ UserOperation::AddAdmin => do_websocket_operation::<AddAdmin>(context, id, op, data).await,
+ UserOperation::GetUnreadRegistrationApplicationCount => {
+ do_websocket_operation::<GetUnreadRegistrationApplicationCount>(context, id, op, data).await
+ }
+ UserOperation::ListRegistrationApplications => {
+ do_websocket_operation::<ListRegistrationApplications>(context, id, op, data).await
+ }
+ UserOperation::ApproveRegistrationApplication => {
+ do_websocket_operation::<ApproveRegistrationApplication>(context, id, op, data).await
+ }
+ UserOperation::BanPerson => do_websocket_operation::<BanPerson>(context, id, op, data).await,
+ UserOperation::GetBannedPersons => {
+ do_websocket_operation::<GetBannedPersons>(context, id, op, data).await
+ }
+ UserOperation::BlockPerson => {
+ do_websocket_operation::<BlockPerson>(context, id, op, data).await
+ }
+ UserOperation::GetPersonMentions => {
+ do_websocket_operation::<GetPersonMentions>(context, id, op, data).await
+ }
+ UserOperation::MarkPersonMentionAsRead => {
+ do_websocket_operation::<MarkPersonMentionAsRead>(context, id, op, data).await
+ }
+ UserOperation::MarkCommentReplyAsRead => {
+ do_websocket_operation::<MarkCommentReplyAsRead>(context, id, op, data).await
+ }
+ UserOperation::MarkAllAsRead => {
+ do_websocket_operation::<MarkAllAsRead>(context, id, op, data).await
+ }
+ UserOperation::PasswordReset => {
+ do_websocket_operation::<PasswordReset>(context, id, op, data).await
+ }
+ UserOperation::PasswordChange => {
+ do_websocket_operation::<PasswordChangeAfterReset>(context, id, op, data).await
+ }
+ UserOperation::UserJoin => do_websocket_operation::<UserJoin>(context, id, op, data).await,
+ UserOperation::PostJoin => do_websocket_operation::<PostJoin>(context, id, op, data).await,
+ UserOperation::CommunityJoin => {
+ do_websocket_operation::<CommunityJoin>(context, id, op, data).await
+ }
+ UserOperation::ModJoin => do_websocket_operation::<ModJoin>(context, id, op, data).await,
+ UserOperation::SaveUserSettings => {
+ do_websocket_operation::<SaveUserSettings>(context, id, op, data).await
+ }
+ UserOperation::ChangePassword => {
+ do_websocket_operation::<ChangePassword>(context, id, op, data).await
+ }
+ UserOperation::GetReportCount => {
+ do_websocket_operation::<GetReportCount>(context, id, op, data).await
+ }
+ UserOperation::GetUnreadCount => {
+ do_websocket_operation::<GetUnreadCount>(context, id, op, data).await
+ }
+ UserOperation::VerifyEmail => {
+ do_websocket_operation::<VerifyEmail>(context, id, op, data).await
+ }
+
+ // Private Message ops
+ UserOperation::MarkPrivateMessageAsRead => {
+ do_websocket_operation::<MarkPrivateMessageAsRead>(context, id, op, data).await
+ }
+ UserOperation::CreatePrivateMessageReport => {
+ do_websocket_operation::<CreatePrivateMessageReport>(context, id, op, data).await
+ }
+ UserOperation::ResolvePrivateMessageReport => {
+ do_websocket_operation::<ResolvePrivateMessageReport>(context, id, op, data).await
+ }
+ UserOperation::ListPrivateMessageReports => {
+ do_websocket_operation::<ListPrivateMessageReports>(context, id, op, data).await
+ }
+
+ // Site ops
+ UserOperation::GetModlog => do_websocket_operation::<GetModlog>(context, id, op, data).await,
+ UserOperation::PurgePerson => {
+ do_websocket_operation::<PurgePerson>(context, id, op, data).await
+ }
+ UserOperation::PurgeCommunity => {
+ do_websocket_operation::<PurgeCommunity>(context, id, op, data).await
+ }
+ UserOperation::PurgePost => do_websocket_operation::<PurgePost>(context, id, op, data).await,
+ UserOperation::PurgeComment => {
+ do_websocket_operation::<PurgeComment>(context, id, op, data).await
+ }
+ UserOperation::TransferCommunity => {
+ do_websocket_operation::<TransferCommunity>(context, id, op, data).await
+ }
+ UserOperation::LeaveAdmin => do_websocket_operation::<LeaveAdmin>(context, id, op, data).await,
+
+ // Community ops
+ UserOperation::FollowCommunity => {
+ do_websocket_operation::<FollowCommunity>(context, id, op, data).await
+ }
+ UserOperation::BlockCommunity => {
+ do_websocket_operation::<BlockCommunity>(context, id, op, data).await
+ }
+ UserOperation::BanFromCommunity => {
+ do_websocket_operation::<BanFromCommunity>(context, id, op, data).await
+ }
+ UserOperation::AddModToCommunity => {
+ do_websocket_operation::<AddModToCommunity>(context, id, op, data).await
+ }
+
+ // Post ops
+ UserOperation::LockPost => do_websocket_operation::<LockPost>(context, id, op, data).await,
+ UserOperation::StickyPost => do_websocket_operation::<StickyPost>(context, id, op, data).await,
+ UserOperation::CreatePostLike => {
+ do_websocket_operation::<CreatePostLike>(context, id, op, data).await
+ }
+ UserOperation::MarkPostAsRead => {
+ do_websocket_operation::<MarkPostAsRead>(context, id, op, data).await
+ }
+ UserOperation::SavePost => do_websocket_operation::<SavePost>(context, id, op, data).await,
+ UserOperation::CreatePostReport => {
+ do_websocket_operation::<CreatePostReport>(context, id, op, data).await
+ }
+ UserOperation::ListPostReports => {
+ do_websocket_operation::<ListPostReports>(context, id, op, data).await
+ }
+ UserOperation::ResolvePostReport => {
+ do_websocket_operation::<ResolvePostReport>(context, id, op, data).await
+ }
+ UserOperation::GetSiteMetadata => {
+ do_websocket_operation::<GetSiteMetadata>(context, id, op, data).await
+ }
+
+ // Comment ops
+ UserOperation::SaveComment => {
+ do_websocket_operation::<SaveComment>(context, id, op, data).await
+ }
+ UserOperation::CreateCommentLike => {
+ do_websocket_operation::<CreateCommentLike>(context, id, op, data).await
+ }
+ UserOperation::CreateCommentReport => {
+ do_websocket_operation::<CreateCommentReport>(context, id, op, data).await
+ }
+ UserOperation::ListCommentReports => {
+ do_websocket_operation::<ListCommentReports>(context, id, op, data).await
+ }
+ UserOperation::ResolveCommentReport => {
+ do_websocket_operation::<ResolveCommentReport>(context, id, op, data).await
+ }
+ }
+}
+
+async fn do_websocket_operation<'a, 'b, Data>(
+ context: LemmyContext,
+ id: ConnectionId,
+ op: UserOperation,
+ data: &str,
+) -> result::Result<String, LemmyError>
+where
+ Data: Perform + SendActivity<Response = <Data as Perform>::Response>,
+ for<'de> Data: Deserialize<'de>,
+{
+ let parsed_data: Data = serde_json::from_str(data)?;
+ let res = parsed_data
+ .perform(&web::Data::new(context.clone()), Some(id))
+ .await?;
+ SendActivity::send_activity(&parsed_data, &res, &context).await?;
+ serialize_websocket_message(&op, &res)
+}
};
use diesel_async::RunQueryDsl;
use lemmy_api_common::{
- generate_followers_url,
- generate_inbox_url,
- generate_local_apub_endpoint,
- generate_shared_inbox_url,
- generate_site_inbox_url,
lemmy_db_views::structs::SiteView,
- EndpointType,
+ utils::{
+ generate_followers_url,
+ generate_inbox_url,
+ generate_local_apub_endpoint,
+ generate_shared_inbox_url,
+ generate_site_inbox_url,
+ EndpointType,
+ },
};
use lemmy_db_schema::{
source::{
use actix_web::{middleware, web::Data, App, HttpServer, Result};
use diesel_migrations::EmbeddedMigrations;
use doku::json::{AutoComments, CommentsStyle, Formatting, ObjectsStyle};
-use lemmy_api::match_websocket_operation;
use lemmy_api_common::{
+ context::LemmyContext,
lemmy_db_views::structs::SiteView,
request::build_user_agent,
utils::{
local_site_rate_limit_to_rate_limit_config,
},
websocket::chat_server::ChatServer,
- LemmyContext,
};
-use lemmy_api_crud::match_websocket_operation_crud;
use lemmy_db_schema::{
source::secret::Secret,
utils::{build_db_pool, get_database_url, run_migrations},
use lemmy_routes::{feeds, images, nodeinfo, webfinger};
use lemmy_server::{
api_routes,
+ api_routes::{
+ match_websocket_operation,
+ match_websocket_operation_apub,
+ match_websocket_operation_crud,
+ },
code_migrations::run_advanced_migrations,
init_logging,
root_span_builder::QuieterRootSpanBuilder,
pool.clone(),
|c, i, o, d| Box::pin(match_websocket_operation(c, i, o, d)),
|c, i, o, d| Box::pin(match_websocket_operation_crud(c, i, o, d)),
+ |c, i, o, d| Box::pin(match_websocket_operation_apub(c, i, o, d)),
client.clone(),
settings.clone(),
secret.clone(),