Remove chatserver (#2919)

* Remove chatserver

* fix clippy

* Remove captchas (fixes #2922)

* fix prettier

* fix api_common build

* cargo fmt
This commit is contained in:
Nutomic 2023-06-06 18:27:22 +02:00 committed by GitHub
parent ef1aa18fd2
commit 3565ad984a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
129 changed files with 739 additions and 2709 deletions

44
Cargo.lock generated
View File

@ -61,30 +61,6 @@ dependencies = [
"url",
]
[[package]]
name = "actix"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f728064aca1c318585bf4bb04ffcfac9e75e508ab4e8b1bd9ba5dfe04e2cbed5"
dependencies = [
"actix-rt",
"actix_derive",
"bitflags",
"bytes",
"crossbeam-channel",
"futures-core",
"futures-sink",
"futures-task",
"futures-util",
"log",
"once_cell",
"parking_lot 0.12.1",
"pin-project-lite",
"smallvec",
"tokio",
"tokio-util 0.7.4",
]
[[package]]
name = "actix-codec"
version = "0.5.0"
@ -332,17 +308,6 @@ dependencies = [
"syn 1.0.103",
]
[[package]]
name = "actix_derive"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d44b8fee1ced9671ba043476deddef739dd0959bf77030b26b738cc591737a7"
dependencies = [
"proc-macro2 1.0.47",
"quote 1.0.21",
"syn 1.0.103",
]
[[package]]
name = "addr2line"
version = "0.19.0"
@ -2537,7 +2502,6 @@ dependencies = [
"base64",
"bcrypt",
"captcha",
"chrono",
"lemmy_api_common",
"lemmy_db_schema",
"lemmy_db_views",
@ -2555,8 +2519,8 @@ dependencies = [
name = "lemmy_api_common"
version = "0.17.1"
dependencies = [
"actix",
"actix-rt",
"actix-web",
"anyhow",
"chrono",
"encoding",
@ -2567,16 +2531,12 @@ dependencies = [
"lemmy_db_views_moderator",
"lemmy_utils",
"percent-encoding",
"rand 0.8.5",
"regex",
"reqwest",
"reqwest-middleware",
"rosetta-i18n",
"serde",
"serde_json",
"serde_with",
"strum",
"strum_macros",
"tracing",
"ts-rs",
"url",
@ -2608,7 +2568,6 @@ name = "lemmy_apub"
version = "0.17.1"
dependencies = [
"activitypub_federation",
"actix",
"actix-rt",
"actix-web",
"anyhow",
@ -2746,7 +2705,6 @@ name = "lemmy_server"
version = "0.17.1"
dependencies = [
"activitypub_federation",
"actix",
"actix-cors",
"actix-web",
"clokwerk",

View File

@ -106,7 +106,6 @@ rosetta-i18n = "0.1.2"
rand = "0.8.5"
opentelemetry = { version = "0.17.0", features = ["rt-tokio"] }
tracing-opentelemetry = { version = "0.17.2" }
actix = "0.13"
ts-rs = { version = "6.2", features = ["serde-compat", "format", "chrono-impl"] }
[dependencies]
@ -134,7 +133,6 @@ reqwest-tracing = { workspace = true }
clokwerk = { workspace = true }
doku = { workspace = true }
serde_json = { workspace = true }
actix = { workspace = true }
tracing-opentelemetry = { workspace = true, optional = true }
opentelemetry = { workspace = true, optional = true }
console-subscriber = { version = "0.1.8", optional = true }

View File

@ -21,7 +21,6 @@ lemmy_db_views_moderator = { workspace = true, features = ["full"] }
lemmy_db_views_actor = { workspace = true, features = ["full"] }
lemmy_api_common = { workspace = true, features = ["full"] }
bcrypt = { workspace = true }
chrono = { workspace = true }
serde = { workspace = true }
actix-web = { workspace = true }
base64 = { workspace = true }

View File

@ -10,18 +10,14 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views::structs::CommentView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for DistinguishComment {
type Response = CommentResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommentResponse, LemmyError> {
let data: &DistinguishComment = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -1,10 +1,10 @@
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::build_comment_response,
comment::{CommentResponse, CreateCommentLike},
context::LemmyContext,
utils::{check_community_ban, check_downvotes_enabled, local_user_view_from_jwt},
websocket::UserOperation,
};
use lemmy_db_schema::{
newtypes::LocalUserId,
@ -16,18 +16,14 @@ use lemmy_db_schema::{
traits::Likeable,
};
use lemmy_db_views::structs::{CommentView, LocalUserView};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for CreateCommentLike {
type Response = CommentResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommentResponse, LemmyError> {
let data: &CreateCommentLike = self;
let local_site = LocalSite::read(context.pool()).await?;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -76,13 +72,11 @@ impl Perform for CreateCommentLike {
.map_err(|e| LemmyError::from_error_message(e, "couldnt_like_comment"))?;
}
context
.send_comment_ws_message(
&UserOperation::CreateCommentLike,
data.comment_id,
websocket_id,
build_comment_response(
context,
comment_id,
Some(local_user_view),
None,
Some(local_user_view.person.id),
recipient_ids,
)
.await

View File

@ -10,18 +10,14 @@ use lemmy_db_schema::{
traits::Saveable,
};
use lemmy_db_views::structs::CommentView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for SaveComment {
type Response = CommentResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommentResponse, LemmyError> {
let data: &SaveComment = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -4,7 +4,6 @@ use lemmy_api_common::{
comment::{CommentReportResponse, CreateCommentReport},
context::LemmyContext,
utils::{check_community_ban, local_user_view_from_jwt, send_new_report_email_to_admins},
websocket::UserOperation,
};
use lemmy_db_schema::{
source::{
@ -14,18 +13,17 @@ use lemmy_db_schema::{
traits::Reportable,
};
use lemmy_db_views::structs::{CommentReportView, CommentView};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
/// Creates a comment report and notifies the moderators of the community
#[async_trait::async_trait(?Send)]
impl Perform for CreateCommentReport {
type Response = CommentReportResponse;
#[tracing::instrument(skip(context, websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<CommentReportResponse, LemmyError> {
let data: &CreateCommentReport = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -64,17 +62,8 @@ impl Perform for CreateCommentReport {
.await?;
}
let res = CommentReportResponse {
Ok(CommentReportResponse {
comment_report_view,
};
context.send_mod_ws_message(
&UserOperation::CreateCommentReport,
&res,
comment_view.community.id,
websocket_id,
)?;
Ok(res)
})
}
}

View File

@ -6,7 +6,7 @@ use lemmy_api_common::{
utils::local_user_view_from_jwt,
};
use lemmy_db_views::comment_report_view::CommentReportQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
/// Lists comment reports for a community if an id is supplied
/// or returns all comment reports for communities a user moderates
@ -14,11 +14,10 @@ use lemmy_utils::{error::LemmyError, ConnectionId};
impl Perform for ListCommentReports {
type Response = ListCommentReportsResponse;
#[tracing::instrument(skip(context, _websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<ListCommentReportsResponse, LemmyError> {
let data: &ListCommentReports = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -42,8 +41,6 @@ impl Perform for ListCommentReports {
.list()
.await?;
let res = ListCommentReportsResponse { comment_reports };
Ok(res)
Ok(ListCommentReportsResponse { comment_reports })
}
}

View File

@ -4,22 +4,20 @@ use lemmy_api_common::{
comment::{CommentReportResponse, ResolveCommentReport},
context::LemmyContext,
utils::{is_mod_or_admin, local_user_view_from_jwt},
websocket::UserOperation,
};
use lemmy_db_schema::{source::comment_report::CommentReport, traits::Reportable};
use lemmy_db_views::structs::CommentReportView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
/// Resolves or unresolves a comment report and notifies the moderators of the community
#[async_trait::async_trait(?Send)]
impl Perform for ResolveCommentReport {
type Response = CommentReportResponse;
#[tracing::instrument(skip(context, websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<CommentReportResponse, LemmyError> {
let data: &ResolveCommentReport = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -44,17 +42,8 @@ impl Perform for ResolveCommentReport {
let report_id = data.report_id;
let comment_report_view = CommentReportView::read(context.pool(), report_id, person_id).await?;
let res = CommentReportResponse {
Ok(CommentReportResponse {
comment_report_view,
};
context.send_mod_ws_message(
&UserOperation::ResolveCommentReport,
&res,
report.community.id,
websocket_id,
)?;
Ok(res)
})
}
}

View File

@ -4,7 +4,6 @@ use lemmy_api_common::{
community::{AddModToCommunity, AddModToCommunityResponse},
context::LemmyContext,
utils::{is_mod_or_admin, local_user_view_from_jwt},
websocket::UserOperation,
};
use lemmy_db_schema::{
source::{
@ -14,17 +13,16 @@ use lemmy_db_schema::{
traits::{Crud, Joinable},
};
use lemmy_db_views_actor::structs::CommunityModeratorView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for AddModToCommunity {
type Response = AddModToCommunityResponse;
#[tracing::instrument(skip(context, websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<AddModToCommunityResponse, LemmyError> {
let data: &AddModToCommunity = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -68,14 +66,6 @@ impl Perform for AddModToCommunity {
let community_id = data.community_id;
let moderators = CommunityModeratorView::for_community(context.pool(), community_id).await?;
let res = AddModToCommunityResponse { moderators };
context.send_mod_ws_message(
&UserOperation::AddModToCommunity,
&res,
community_id,
websocket_id,
)?;
Ok(res)
Ok(AddModToCommunityResponse { moderators })
}
}

View File

@ -4,11 +4,6 @@ use lemmy_api_common::{
community::{BanFromCommunity, BanFromCommunityResponse},
context::LemmyContext,
utils::{is_mod_or_admin, local_user_view_from_jwt, remove_user_data_in_community},
websocket::{
handlers::messages::SendCommunityRoomMessage,
serialize_websocket_message,
UserOperation,
},
};
use lemmy_db_schema::{
source::{
@ -26,18 +21,16 @@ use lemmy_db_views_actor::structs::PersonView;
use lemmy_utils::{
error::LemmyError,
utils::{time::naive_from_unix, validation::is_valid_body_field},
ConnectionId,
};
#[async_trait::async_trait(?Send)]
impl Perform for BanFromCommunity {
type Response = BanFromCommunityResponse;
#[tracing::instrument(skip(context, websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<BanFromCommunityResponse, LemmyError> {
let data: &BanFromCommunity = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -98,19 +91,9 @@ impl Perform for BanFromCommunity {
let person_id = data.person_id;
let person_view = PersonView::read(context.pool(), person_id).await?;
let res = BanFromCommunityResponse {
Ok(BanFromCommunityResponse {
person_view,
banned: data.ban,
};
// A custom ban message
let message = serialize_websocket_message(&UserOperation::BanFromCommunity, &res)?;
context.chat_server().do_send(SendCommunityRoomMessage {
community_id,
message,
websocket_id,
});
Ok(res)
})
}
}

View File

@ -13,17 +13,16 @@ use lemmy_db_schema::{
traits::{Blockable, Followable},
};
use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for BlockCommunity {
type Response = BlockCommunityResponse;
#[tracing::instrument(skip(context, _websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<BlockCommunityResponse, LemmyError> {
let data: &BlockCommunity = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -13,18 +13,14 @@ use lemmy_db_schema::{
traits::{Crud, Followable},
};
use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for FollowCommunity {
type Response = CommunityResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<CommunityResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommunityResponse, LemmyError> {
let data: &FollowCommunity = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -1,10 +1,10 @@
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::build_community_response,
community::{CommunityResponse, HideCommunity},
context::LemmyContext,
utils::{is_admin, local_user_view_from_jwt},
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
source::{
@ -13,18 +13,14 @@ use lemmy_db_schema::{
},
traits::Crud,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for HideCommunity {
type Response = CommunityResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<CommunityResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommunityResponse, LemmyError> {
let data: &HideCommunity = self;
// Verify its a admin (only admin can hide or unhide it)
@ -49,13 +45,6 @@ impl Perform for HideCommunity {
ModHideCommunity::create(context.pool(), &mod_hide_community_form).await?;
context
.send_community_ws_message(
&UserOperationCrud::EditCommunity,
data.community_id,
websocket_id,
None,
)
.await
build_community_response(context, local_user_view, community_id).await
}
}

View File

@ -14,7 +14,7 @@ use lemmy_db_schema::{
traits::{Crud, Joinable},
};
use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
use lemmy_utils::{error::LemmyError, location_info, ConnectionId};
use lemmy_utils::{error::LemmyError, location_info};
// TODO: we dont do anything for federation here, it should be updated the next time the community
// gets fetched. i hope we can get rid of the community creator role soon.
@ -22,11 +22,10 @@ use lemmy_utils::{error::LemmyError, location_info, ConnectionId};
impl Perform for TransferCommunity {
type Response = GetCommunityResponse;
#[tracing::instrument(skip(context, _websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<GetCommunityResponse, LemmyError> {
let data: &TransferCommunity = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -95,7 +94,6 @@ impl Perform for TransferCommunity {
community_view,
site: None,
moderators,
online: 0,
discussion_languages: vec![],
})
}

View File

@ -1,8 +1,7 @@
use actix_web::web::Data;
use captcha::Captcha;
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::slurs::check_slurs, ConnectionId};
use lemmy_utils::{error::LemmyError, utils::slurs::check_slurs};
mod comment;
mod comment_report;
@ -13,32 +12,12 @@ mod post_report;
mod private_message;
mod private_message_report;
mod site;
mod websocket;
#[async_trait::async_trait(?Send)]
pub trait Perform {
type Response: serde::ser::Serialize + Send;
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError>;
}
/// 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();
let mut concat_letters: Vec<u8> = Vec::new();
for letter in letters {
let bytes = letter.unwrap_or_default();
concat_letters.extend(bytes);
}
// Convert to base64
base64::encode(concat_letters)
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError>;
}
/// Check size of report and remove whitespace

View File

@ -4,7 +4,6 @@ use lemmy_api_common::{
context::LemmyContext,
person::{AddAdmin, AddAdminResponse},
utils::{is_admin, local_user_view_from_jwt},
websocket::UserOperation,
};
use lemmy_db_schema::{
source::{
@ -14,18 +13,14 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views_actor::structs::PersonView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for AddAdmin {
type Response = AddAdminResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<AddAdminResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<AddAdminResponse, LemmyError> {
let data: &AddAdmin = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -53,10 +48,6 @@ impl Perform for AddAdmin {
let admins = PersonView::admins(context.pool()).await?;
let res = AddAdminResponse { admins };
context.send_all_ws_message(&UserOperation::AddAdmin, &res, websocket_id)?;
Ok(res)
Ok(AddAdminResponse { admins })
}
}

View File

@ -4,7 +4,6 @@ use lemmy_api_common::{
context::LemmyContext,
person::{BanPerson, BanPersonResponse},
utils::{is_admin, local_user_view_from_jwt, remove_user_data},
websocket::UserOperation,
};
use lemmy_db_schema::{
source::{
@ -17,19 +16,14 @@ use lemmy_db_views_actor::structs::PersonView;
use lemmy_utils::{
error::LemmyError,
utils::{time::naive_from_unix, validation::is_valid_body_field},
ConnectionId,
};
#[async_trait::async_trait(?Send)]
impl Perform for BanPerson {
type Response = BanPersonResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<BanPersonResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<BanPersonResponse, LemmyError> {
let data: &BanPerson = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -79,13 +73,9 @@ impl Perform for BanPerson {
let person_id = data.person_id;
let person_view = PersonView::read(context.pool(), person_id).await?;
let res = BanPersonResponse {
Ok(BanPersonResponse {
person_view,
banned: data.ban,
};
context.send_all_ws_message(&UserOperation::BanPerson, &res, websocket_id)?;
Ok(res)
})
}
}

View File

@ -10,18 +10,14 @@ use lemmy_db_schema::{
traits::Blockable,
};
use lemmy_db_views_actor::structs::PersonView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for BlockPerson {
type Response = BlockPersonResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<BlockPersonResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<BlockPersonResponse, LemmyError> {
let data: &BlockPerson = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -54,11 +50,9 @@ impl Perform for BlockPerson {
.map_err(|e| LemmyError::from_error_message(e, "person_block_already_exists"))?;
}
let res = BlockPersonResponse {
Ok(BlockPersonResponse {
person_view: target_person_view,
blocked: data.block,
};
Ok(res)
})
}
}

View File

@ -7,18 +7,14 @@ use lemmy_api_common::{
utils::{local_user_view_from_jwt, password_length_check},
};
use lemmy_db_schema::source::local_user::LocalUser;
use lemmy_utils::{claims::Claims, error::LemmyError, ConnectionId};
use lemmy_utils::{claims::Claims, error::LemmyError};
#[async_trait::async_trait(?Send)]
impl Perform for ChangePassword {
type Response = LoginResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<LoginResponse, LemmyError> {
#[tracing::instrument(skip(self, context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<LoginResponse, LemmyError> {
let data: &ChangePassword = self;
let local_user_view = local_user_view_from_jwt(data.auth.as_ref(), context).await?;

View File

@ -10,18 +10,14 @@ use lemmy_db_schema::{
RegistrationMode,
};
use lemmy_db_views::structs::SiteView;
use lemmy_utils::{claims::Claims, error::LemmyError, ConnectionId};
use lemmy_utils::{claims::Claims, error::LemmyError};
#[async_trait::async_trait(?Send)]
impl Perform for PasswordChangeAfterReset {
type Response = LoginResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<LoginResponse, LemmyError> {
#[tracing::instrument(skip(self, context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<LoginResponse, LemmyError> {
let data: &PasswordChangeAfterReset = self;
// Fetch the user_id from the token

View File

@ -1,58 +0,0 @@
use crate::{captcha_as_wav_base64, Perform};
use actix_web::web::Data;
use captcha::{gen, Difficulty};
use chrono::Duration;
use lemmy_api_common::{
context::LemmyContext,
person::{CaptchaResponse, GetCaptcha, GetCaptchaResponse},
websocket::{handlers::captcha::AddCaptcha, structs::CaptchaItem},
};
use lemmy_db_schema::{source::local_site::LocalSite, utils::naive_now};
use lemmy_utils::{error::LemmyError, ConnectionId};
#[async_trait::async_trait(?Send)]
impl Perform for GetCaptcha {
type Response = GetCaptchaResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
let local_site = LocalSite::read(context.pool()).await?;
if !local_site.captcha_enabled {
return Ok(GetCaptchaResponse { ok: None });
}
let captcha = gen(match local_site.captcha_difficulty.as_str() {
"easy" => Difficulty::Easy,
"hard" => Difficulty::Hard,
_ => Difficulty::Medium,
});
let answer = captcha.chars_as_string();
let png = captcha.as_base64().expect("failed to generate captcha");
let uuid = uuid::Uuid::new_v4().to_string();
let wav = captcha_as_wav_base64(&captcha);
let captcha_item = CaptchaItem {
answer,
uuid: uuid.clone(),
expires: naive_now() + Duration::minutes(10), // expires in 10 minutes
};
// Stores the captcha item on the queue
context.chat_server().do_send(AddCaptcha {
captcha: captcha_item,
});
Ok(GetCaptchaResponse {
ok: Some(CaptchaResponse { png, wav, uuid }),
})
}
}

View File

@ -6,17 +6,13 @@ use lemmy_api_common::{
utils::{is_admin, local_user_view_from_jwt},
};
use lemmy_db_views_actor::structs::PersonView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for GetBannedPersons {
type Response = BannedPersonsResponse;
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let data: &GetBannedPersons = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -25,8 +21,6 @@ impl Perform for GetBannedPersons {
let banned = PersonView::banned(context.pool()).await?;
let res = Self::Response { banned };
Ok(res)
Ok(Self::Response { banned })
}
}

View File

@ -7,23 +7,14 @@ use lemmy_api_common::{
utils::{check_registration_application, check_user_valid},
};
use lemmy_db_views::structs::{LocalUserView, SiteView};
use lemmy_utils::{
claims::Claims,
error::LemmyError,
utils::validation::check_totp_2fa_valid,
ConnectionId,
};
use lemmy_utils::{claims::Claims, error::LemmyError, utils::validation::check_totp_2fa_valid};
#[async_trait::async_trait(?Send)]
impl Perform for Login {
type Response = LoginResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<LoginResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<LoginResponse, LemmyError> {
let data: &Login = self;
let site_view = SiteView::read_local(context.pool()).await?;

View File

@ -3,7 +3,6 @@ mod ban_person;
mod block;
mod change_password;
mod change_password_after_reset;
mod get_captcha;
mod list_banned;
mod login;
mod notifications;

View File

@ -6,17 +6,16 @@ use lemmy_api_common::{
utils::local_user_view_from_jwt,
};
use lemmy_db_views_actor::person_mention_view::PersonMentionQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for GetPersonMentions {
type Response = GetPersonMentionsResponse;
#[tracing::instrument(skip(context, _websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<GetPersonMentionsResponse, LemmyError> {
let data: &GetPersonMentions = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -6,18 +6,14 @@ use lemmy_api_common::{
utils::local_user_view_from_jwt,
};
use lemmy_db_views_actor::comment_reply_view::CommentReplyQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for GetReplies {
type Response = GetRepliesResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<GetRepliesResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<GetRepliesResponse, LemmyError> {
let data: &GetReplies = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -10,18 +10,14 @@ use lemmy_db_schema::source::{
person_mention::PersonMention,
private_message::PrivateMessage,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for MarkAllAsRead {
type Response = GetRepliesResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<GetRepliesResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<GetRepliesResponse, LemmyError> {
let data: &MarkAllAsRead = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
let person_id = local_user_view.person.id;

View File

@ -10,17 +10,16 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views_actor::structs::PersonMentionView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for MarkPersonMentionAsRead {
type Response = PersonMentionResponse;
#[tracing::instrument(skip(context, _websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<PersonMentionResponse, LemmyError> {
let data: &MarkPersonMentionAsRead = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -10,17 +10,16 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views_actor::structs::CommentReplyView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for MarkCommentReplyAsRead {
type Response = CommentReplyResponse;
#[tracing::instrument(skip(context, _websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<CommentReplyResponse, LemmyError> {
let data = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -7,18 +7,14 @@ use lemmy_api_common::{
};
use lemmy_db_views::structs::PrivateMessageView;
use lemmy_db_views_actor::structs::{CommentReplyView, PersonMentionView};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for GetUnreadCount {
type Response = GetUnreadCountResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let data = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -31,12 +27,10 @@ impl Perform for GetUnreadCount {
let private_messages =
PrivateMessageView::get_unread_messages(context.pool(), person_id).await?;
let res = Self::Response {
Ok(Self::Response {
replies,
mentions,
private_messages,
};
Ok(res)
})
}
}

View File

@ -6,17 +6,16 @@ use lemmy_api_common::{
utils::local_user_view_from_jwt,
};
use lemmy_db_views::structs::{CommentReportView, PostReportView, PrivateMessageReportView};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for GetReportCount {
type Response = GetReportCountResponse;
#[tracing::instrument(skip(context, _websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<GetReportCountResponse, LemmyError> {
let data: &GetReportCount = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -37,13 +36,11 @@ impl Perform for GetReportCount {
None
};
let res = GetReportCountResponse {
Ok(GetReportCountResponse {
community_id,
comment_reports,
post_reports,
private_message_reports,
};
Ok(res)
})
}
}

View File

@ -6,17 +6,16 @@ use lemmy_api_common::{
utils::send_password_reset_email,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for PasswordReset {
type Response = PasswordResetResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
#[tracing::instrument(skip(self, context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<PasswordResetResponse, LemmyError> {
let data: &PasswordReset = self;

View File

@ -25,19 +25,14 @@ use lemmy_utils::{
is_valid_display_name,
is_valid_matrix_id,
},
ConnectionId,
};
#[async_trait::async_trait(?Send)]
impl Perform for SaveUserSettings {
type Response = LoginResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<LoginResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<LoginResponse, LemmyError> {
let data: &SaveUserSettings = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
let site_view = SiteView::read_local(context.pool()).await?;

View File

@ -19,11 +19,7 @@ use lemmy_utils::error::LemmyError;
impl Perform for VerifyEmail {
type Response = VerifyEmailResponse;
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<usize>,
) -> Result<Self::Response, LemmyError> {
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let token = self.token.clone();
let verification = EmailVerification::read_for_token(context.pool(), &token)
.await

View File

@ -1,6 +1,7 @@
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::build_post_response,
context::LemmyContext,
post::{FeaturePost, PostResponse},
utils::{
@ -10,7 +11,6 @@ use lemmy_api_common::{
is_mod_or_admin,
local_user_view_from_jwt,
},
websocket::UserOperation,
};
use lemmy_db_schema::{
source::{
@ -20,18 +20,14 @@ use lemmy_db_schema::{
traits::Crud,
PostFeatureType,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for FeaturePost {
type Response = PostResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<PostResponse, LemmyError> {
let data: &FeaturePost = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -81,12 +77,11 @@ impl Perform for FeaturePost {
ModFeaturePost::create(context.pool(), &form).await?;
context
.send_post_ws_message(
&UserOperation::FeaturePost,
data.post_id,
websocket_id,
Some(local_user_view.person.id),
build_post_response(
context,
orig_post.community_id,
local_user_view.person.id,
post_id,
)
.await
}

View File

@ -5,17 +5,16 @@ use lemmy_api_common::{
post::{GetSiteMetadata, GetSiteMetadataResponse},
request::fetch_site_metadata,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for GetSiteMetadata {
type Response = GetSiteMetadataResponse;
#[tracing::instrument(skip(context, _websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<GetSiteMetadataResponse, LemmyError> {
let data: &Self = self;

View File

@ -1,6 +1,7 @@
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::build_post_response,
context::LemmyContext,
post::{CreatePostLike, PostResponse},
utils::{
@ -10,7 +11,6 @@ use lemmy_api_common::{
local_user_view_from_jwt,
mark_post_as_read,
},
websocket::UserOperation,
};
use lemmy_db_schema::{
source::{
@ -19,18 +19,14 @@ use lemmy_db_schema::{
},
traits::{Crud, Likeable},
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for CreatePostLike {
type Response = PostResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<PostResponse, LemmyError> {
let data: &CreatePostLike = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
let local_site = LocalSite::read(context.pool()).await?;
@ -67,12 +63,11 @@ impl Perform for CreatePostLike {
// Mark the post as read
mark_post_as_read(person_id, post_id, context.pool()).await?;
context
.send_post_ws_message(
&UserOperation::CreatePostLike,
data.post_id,
websocket_id,
Some(local_user_view.person.id),
build_post_response(
context,
post.community_id,
local_user_view.person.id,
post_id,
)
.await
}

View File

@ -1,6 +1,7 @@
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::build_post_response,
context::LemmyContext,
post::{LockPost, PostResponse},
utils::{
@ -9,7 +10,6 @@ use lemmy_api_common::{
is_mod_or_admin,
local_user_view_from_jwt,
},
websocket::UserOperation,
};
use lemmy_db_schema::{
source::{
@ -18,18 +18,14 @@ use lemmy_db_schema::{
},
traits::Crud,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for LockPost {
type Response = PostResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<PostResponse, LemmyError> {
let data: &LockPost = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -70,12 +66,11 @@ impl Perform for LockPost {
};
ModLockPost::create(context.pool(), &form).await?;
context
.send_post_ws_message(
&UserOperation::LockPost,
data.post_id,
websocket_id,
Some(local_user_view.person.id),
build_post_response(
context,
orig_post.community_id,
local_user_view.person.id,
post_id,
)
.await
}

View File

@ -6,18 +6,14 @@ use lemmy_api_common::{
utils::{local_user_view_from_jwt, mark_post_as_read, mark_post_as_unread},
};
use lemmy_db_views::structs::PostView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for MarkPostAsRead {
type Response = PostResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let data = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -34,8 +30,6 @@ impl Perform for MarkPostAsRead {
// Fetch it
let post_view = PostView::read(context.pool(), post_id, Some(person_id), None).await?;
let res = Self::Response { post_view };
Ok(res)
Ok(Self::Response { post_view })
}
}

View File

@ -10,18 +10,14 @@ use lemmy_db_schema::{
traits::Saveable,
};
use lemmy_db_views::structs::PostView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for SavePost {
type Response = PostResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<PostResponse, LemmyError> {
let data: &SavePost = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -4,7 +4,6 @@ use lemmy_api_common::{
context::LemmyContext,
post::{CreatePostReport, PostReportResponse},
utils::{check_community_ban, local_user_view_from_jwt, send_new_report_email_to_admins},
websocket::UserOperation,
};
use lemmy_db_schema::{
source::{
@ -14,19 +13,15 @@ use lemmy_db_schema::{
traits::Reportable,
};
use lemmy_db_views::structs::{PostReportView, PostView};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
/// Creates a post report and notifies the moderators of the community
#[async_trait::async_trait(?Send)]
impl Perform for CreatePostReport {
type Response = PostReportResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<PostReportResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<PostReportResponse, LemmyError> {
let data: &CreatePostReport = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
let local_site = LocalSite::read(context.pool()).await?;
@ -66,15 +61,6 @@ impl Perform for CreatePostReport {
.await?;
}
let res = PostReportResponse { post_report_view };
context.send_mod_ws_message(
&UserOperation::CreatePostReport,
&res,
post_view.community.id,
websocket_id,
)?;
Ok(res)
Ok(PostReportResponse { post_report_view })
}
}

View File

@ -6,7 +6,7 @@ use lemmy_api_common::{
utils::local_user_view_from_jwt,
};
use lemmy_db_views::post_report_view::PostReportQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
/// Lists post reports for a community if an id is supplied
/// or returns all post reports for communities a user moderates
@ -14,11 +14,10 @@ use lemmy_utils::{error::LemmyError, ConnectionId};
impl Perform for ListPostReports {
type Response = ListPostReportsResponse;
#[tracing::instrument(skip(context, _websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<ListPostReportsResponse, LemmyError> {
let data: &ListPostReports = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -42,8 +41,6 @@ impl Perform for ListPostReports {
.list()
.await?;
let res = ListPostReportsResponse { post_reports };
Ok(res)
Ok(ListPostReportsResponse { post_reports })
}
}

View File

@ -4,23 +4,18 @@ use lemmy_api_common::{
context::LemmyContext,
post::{PostReportResponse, ResolvePostReport},
utils::{is_mod_or_admin, local_user_view_from_jwt},
websocket::UserOperation,
};
use lemmy_db_schema::{source::post_report::PostReport, traits::Reportable};
use lemmy_db_views::structs::PostReportView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
/// Resolves or unresolves a post report and notifies the moderators of the community
#[async_trait::async_trait(?Send)]
impl Perform for ResolvePostReport {
type Response = PostReportResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<PostReportResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<PostReportResponse, LemmyError> {
let data: &ResolvePostReport = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -43,15 +38,6 @@ impl Perform for ResolvePostReport {
let post_report_view = PostReportView::read(context.pool(), report_id, person_id).await?;
let res = PostReportResponse { post_report_view };
context.send_mod_ws_message(
&UserOperation::ResolvePostReport,
&res,
report.community.id,
websocket_id,
)?;
Ok(res)
Ok(PostReportResponse { post_report_view })
}
}

View File

@ -4,23 +4,22 @@ use lemmy_api_common::{
context::LemmyContext,
private_message::{MarkPrivateMessageAsRead, PrivateMessageResponse},
utils::local_user_view_from_jwt,
websocket::UserOperation,
};
use lemmy_db_schema::{
source::private_message::{PrivateMessage, PrivateMessageUpdateForm},
traits::Crud,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_db_views::structs::PrivateMessageView;
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for MarkPrivateMessageAsRead {
type Response = PrivateMessageResponse;
#[tracing::instrument(skip(context, websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<PrivateMessageResponse, LemmyError> {
let data: &MarkPrivateMessageAsRead = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -43,13 +42,9 @@ impl Perform for MarkPrivateMessageAsRead {
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_private_message"))?;
// No need to send an apub update
context
.send_pm_ws_message(
&UserOperation::MarkPrivateMessageAsRead,
data.private_message_id,
websocket_id,
)
.await
let view = PrivateMessageView::read(context.pool(), private_message_id).await?;
Ok(PrivateMessageResponse {
private_message_view: view,
})
}
}

View File

@ -4,10 +4,8 @@ use lemmy_api_common::{
context::LemmyContext,
private_message::{CreatePrivateMessageReport, PrivateMessageReportResponse},
utils::{local_user_view_from_jwt, send_new_report_email_to_admins},
websocket::UserOperation,
};
use lemmy_db_schema::{
newtypes::CommunityId,
source::{
local_site::LocalSite,
private_message::PrivateMessage,
@ -16,18 +14,14 @@ use lemmy_db_schema::{
traits::{Crud, Reportable},
};
use lemmy_db_views::structs::PrivateMessageReportView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for CreatePrivateMessageReport {
type Response = PrivateMessageReportResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let local_user_view = local_user_view_from_jwt(&self.auth, context).await?;
let local_site = LocalSite::read(context.pool()).await?;
@ -63,19 +57,10 @@ impl Perform for CreatePrivateMessageReport {
.await?;
}
let res = PrivateMessageReportResponse {
private_message_report_view,
};
context.send_mod_ws_message(
&UserOperation::CreatePrivateMessageReport,
&res,
CommunityId(0),
websocket_id,
)?;
// TODO: consider federating this
Ok(res)
Ok(PrivateMessageReportResponse {
private_message_report_view,
})
}
}

View File

@ -6,18 +6,14 @@ use lemmy_api_common::{
utils::{is_admin, local_user_view_from_jwt},
};
use lemmy_db_views::private_message_report_view::PrivateMessageReportQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for ListPrivateMessageReports {
type Response = ListPrivateMessageReportsResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let local_user_view = local_user_view_from_jwt(&self.auth, context).await?;
is_admin(&local_user_view)?;
@ -34,10 +30,8 @@ impl Perform for ListPrivateMessageReports {
.list()
.await?;
let res = ListPrivateMessageReportsResponse {
Ok(ListPrivateMessageReportsResponse {
private_message_reports,
};
Ok(res)
})
}
}

View File

@ -4,26 +4,17 @@ use lemmy_api_common::{
context::LemmyContext,
private_message::{PrivateMessageReportResponse, ResolvePrivateMessageReport},
utils::{is_admin, local_user_view_from_jwt},
websocket::UserOperation,
};
use lemmy_db_schema::{
newtypes::CommunityId,
source::private_message_report::PrivateMessageReport,
traits::Reportable,
};
use lemmy_db_schema::{source::private_message_report::PrivateMessageReport, traits::Reportable};
use lemmy_db_views::structs::PrivateMessageReportView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for ResolvePrivateMessageReport {
type Response = PrivateMessageReportResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let local_user_view = local_user_view_from_jwt(&self.auth, context).await?;
is_admin(&local_user_view)?;
@ -43,17 +34,8 @@ impl Perform for ResolvePrivateMessageReport {
let private_message_report_view =
PrivateMessageReportView::read(context.pool(), report_id).await?;
let res = PrivateMessageReportResponse {
Ok(PrivateMessageReportResponse {
private_message_report_view,
};
context.send_mod_ws_message(
&UserOperation::ResolvePrivateMessageReport,
&res,
CommunityId(0),
websocket_id,
)?;
Ok(res)
})
}
}

View File

@ -6,18 +6,14 @@ use lemmy_api_common::{
utils::build_federated_instances,
};
use lemmy_db_views::structs::SiteView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for GetFederatedInstances {
type Response = GetFederatedInstancesResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let site_view = SiteView::read_local(context.pool()).await?;
let federated_instances =
build_federated_instances(&site_view.local_site, context.pool()).await?;

View File

@ -17,18 +17,14 @@ use lemmy_db_schema::{
};
use lemmy_db_views::structs::{CustomEmojiView, SiteView};
use lemmy_db_views_actor::structs::PersonView;
use lemmy_utils::{error::LemmyError, version, ConnectionId};
use lemmy_utils::{error::LemmyError, version};
#[async_trait::async_trait(?Send)]
impl Perform for LeaveAdmin {
type Response = GetSiteResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<GetSiteResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<GetSiteResponse, LemmyError> {
let data: &LeaveAdmin = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -69,7 +65,6 @@ impl Perform for LeaveAdmin {
Ok(GetSiteResponse {
site_view,
admins,
online: 0,
version: version::VERSION.to_string(),
my_user: None,
all_languages,

View File

@ -28,19 +28,15 @@ use lemmy_db_views_moderator::structs::{
ModTransferCommunityView,
ModlogListParams,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
use ModlogActionType::*;
#[async_trait::async_trait(?Send)]
impl Perform for GetModlog {
type Response = GetModlogResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<GetModlogResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<GetModlogResponse, LemmyError> {
let data: &GetModlog = self;
let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), context).await;

View File

@ -12,18 +12,14 @@ use lemmy_db_schema::{
},
traits::Crud,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for PurgeComment {
type Response = PurgeItemResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let data: &Self = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -13,18 +13,14 @@ use lemmy_db_schema::{
},
traits::Crud,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for PurgeCommunity {
type Response = PurgeItemResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let data: &Self = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -13,18 +13,14 @@ use lemmy_db_schema::{
},
traits::Crud,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for PurgePerson {
type Response = PurgeItemResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let data: &Self = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -13,18 +13,14 @@ use lemmy_db_schema::{
},
traits::Crud,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for PurgePost {
type Response = PurgeItemResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let data: &Self = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -14,17 +14,13 @@ use lemmy_db_schema::{
utils::diesel_option_overwrite,
};
use lemmy_db_views::structs::{LocalUserView, RegistrationApplicationView};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for ApproveRegistrationApplication {
type Response = RegistrationApplicationResponse;
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let data = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -7,18 +7,14 @@ use lemmy_api_common::{
};
use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_db_views::registration_application_view::RegistrationApplicationQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
/// Lists registration applications, filterable by undenied only.
#[async_trait::async_trait(?Send)]
impl Perform for ListRegistrationApplications {
type Response = ListRegistrationApplicationsResponse;
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let data = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
let local_site = LocalSite::read(context.pool()).await?;
@ -41,10 +37,8 @@ impl Perform for ListRegistrationApplications {
.list()
.await?;
let res = Self::Response {
Ok(Self::Response {
registration_applications,
};
Ok(res)
})
}
}

View File

@ -7,17 +7,13 @@ use lemmy_api_common::{
};
use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_db_views::structs::RegistrationApplicationView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl Perform for GetUnreadRegistrationApplicationCount {
type Response = GetUnreadRegistrationApplicationCountResponse;
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let data = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
let local_site = LocalSite::read(context.pool()).await?;

View File

@ -1,113 +0,0 @@
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
context::LemmyContext,
utils::local_user_view_from_jwt,
websocket::{
handlers::join_rooms::{JoinCommunityRoom, JoinModRoom, JoinPostRoom, JoinUserRoom},
structs::{
CommunityJoin,
CommunityJoinResponse,
ModJoin,
ModJoinResponse,
PostJoin,
PostJoinResponse,
UserJoin,
UserJoinResponse,
},
},
};
use lemmy_utils::{error::LemmyError, ConnectionId};
#[async_trait::async_trait(?Send)]
impl Perform for UserJoin {
type Response = UserJoinResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<UserJoinResponse, LemmyError> {
let data: &UserJoin = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
if let Some(id) = websocket_id {
context.chat_server().do_send(JoinUserRoom {
user_id: local_user_view.local_user.id,
id,
});
}
Ok(UserJoinResponse { joined: true })
}
}
#[async_trait::async_trait(?Send)]
impl Perform for CommunityJoin {
type Response = CommunityJoinResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<CommunityJoinResponse, LemmyError> {
let data: &CommunityJoin = self;
if let Some(id) = websocket_id {
context.chat_server().do_send(JoinCommunityRoom {
community_id: data.community_id,
id,
});
}
Ok(CommunityJoinResponse { joined: true })
}
}
#[async_trait::async_trait(?Send)]
impl Perform for ModJoin {
type Response = ModJoinResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<ModJoinResponse, LemmyError> {
let data: &ModJoin = self;
if let Some(id) = websocket_id {
context.chat_server().do_send(JoinModRoom {
community_id: data.community_id,
id,
});
}
Ok(ModJoinResponse { joined: true })
}
}
#[async_trait::async_trait(?Send)]
impl Perform for PostJoin {
type Response = PostJoinResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<PostJoinResponse, LemmyError> {
let data: &PostJoin = self;
if let Some(id) = websocket_id {
context.chat_server().do_send(JoinPostRoom {
post_id: data.post_id,
id,
});
}
Ok(PostJoinResponse { joined: true })
}
}

View File

@ -35,14 +35,10 @@ rosetta-i18n = { workspace = true, optional = true }
percent-encoding = { workspace = true, optional = true }
webpage = { version = "1.4.0", default-features = false, features = ["serde"], optional = true }
encoding = { version = "0.2.33", optional = true }
rand = { workspace = true }
serde_json = { workspace = true }
anyhow = { workspace = true }
strum = { workspace = true }
strum_macros = { workspace = true }
actix = { workspace = true }
futures = { workspace = true }
uuid = { workspace = true }
actix-rt = { workspace = true }
reqwest = { workspace = true }
ts-rs = { workspace = true, optional = true }
actix-web = { workspace = true }

View File

@ -0,0 +1,216 @@
use crate::{
comment::CommentResponse,
community::CommunityResponse,
context::LemmyContext,
post::PostResponse,
utils::{check_person_block, get_interface_language, is_mod_or_admin, send_email_to_user},
};
use actix_web::web::Data;
use lemmy_db_schema::{
newtypes::{CommentId, CommunityId, LocalUserId, PersonId, PostId},
source::{
actor_language::CommunityLanguage,
comment::Comment,
comment_reply::{CommentReply, CommentReplyInsertForm},
person::Person,
person_mention::{PersonMention, PersonMentionInsertForm},
post::Post,
},
traits::Crud,
};
use lemmy_db_views::structs::{CommentView, LocalUserView, PostView};
use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{error::LemmyError, utils::mention::MentionData};
pub async fn build_comment_response(
context: &Data<LemmyContext>,
comment_id: CommentId,
local_user_view: Option<LocalUserView>,
form_id: Option<String>,
recipient_ids: Vec<LocalUserId>,
) -> Result<CommentResponse, LemmyError> {
let person_id = local_user_view.map(|l| l.person.id);
let comment_view = CommentView::read(context.pool(), comment_id, person_id).await?;
Ok(CommentResponse {
comment_view,
recipient_ids,
form_id,
})
}
pub async fn build_community_response(
context: &Data<LemmyContext>,
local_user_view: LocalUserView,
community_id: CommunityId,
) -> Result<CommunityResponse, LemmyError> {
let is_mod_or_admin = is_mod_or_admin(context.pool(), local_user_view.person.id, community_id)
.await
.is_ok();
let person_id = local_user_view.person.id;
let community_view = CommunityView::read(
context.pool(),
community_id,
Some(person_id),
Some(is_mod_or_admin),
)
.await?;
let discussion_languages = CommunityLanguage::read(context.pool(), community_id).await?;
Ok(CommunityResponse {
community_view,
discussion_languages,
})
}
pub async fn build_post_response(
context: &Data<LemmyContext>,
community_id: CommunityId,
person_id: PersonId,
post_id: PostId,
) -> Result<PostResponse, LemmyError> {
let is_mod_or_admin = is_mod_or_admin(context.pool(), person_id, community_id)
.await
.is_ok();
let post_view = PostView::read(
context.pool(),
post_id,
Some(person_id),
Some(is_mod_or_admin),
)
.await?;
Ok(PostResponse { post_view })
}
// TODO: this function is a mess and should be split up to handle email seperately
#[tracing::instrument(skip_all)]
pub async fn send_local_notifs(
mentions: Vec<MentionData>,
comment: &Comment,
person: &Person,
post: &Post,
do_send_email: bool,
context: &LemmyContext,
) -> Result<Vec<LocalUserId>, LemmyError> {
let mut recipient_ids = Vec::new();
let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname());
// Send the local mentions
for mention in mentions
.iter()
.filter(|m| m.is_local(&context.settings().hostname) && m.name.ne(&person.name))
.collect::<Vec<&MentionData>>()
{
let mention_name = mention.name.clone();
let user_view = LocalUserView::read_from_name(context.pool(), &mention_name).await;
if let Ok(mention_user_view) = user_view {
// TODO
// At some point, make it so you can't tag the parent creator either
// This can cause two notifications, one for reply and the other for mention
recipient_ids.push(mention_user_view.local_user.id);
let user_mention_form = PersonMentionInsertForm {
recipient_id: mention_user_view.person.id,
comment_id: comment.id,
read: None,
};
// Allow this to fail softly, since comment edits might re-update or replace it
// Let the uniqueness handle this fail
PersonMention::create(context.pool(), &user_mention_form)
.await
.ok();
// Send an email to those local users that have notifications on
if do_send_email {
let lang = get_interface_language(&mention_user_view);
send_email_to_user(
&mention_user_view,
&lang.notification_mentioned_by_subject(&person.name),
&lang.notification_mentioned_by_body(&comment.content, &inbox_link, &person.name),
context.settings(),
)
}
}
}
// Send comment_reply to the parent commenter / poster
if let Some(parent_comment_id) = comment.parent_comment_id() {
let parent_comment = Comment::read(context.pool(), parent_comment_id).await?;
// Get the parent commenter local_user
let parent_creator_id = parent_comment.creator_id;
// Only add to recipients if that person isn't blocked
let creator_blocked = check_person_block(person.id, parent_creator_id, context.pool())
.await
.is_err();
// Don't send a notif to yourself
if parent_comment.creator_id != person.id && !creator_blocked {
let user_view = LocalUserView::read_person(context.pool(), parent_creator_id).await;
if let Ok(parent_user_view) = user_view {
recipient_ids.push(parent_user_view.local_user.id);
let comment_reply_form = CommentReplyInsertForm {
recipient_id: parent_user_view.person.id,
comment_id: comment.id,
read: None,
};
// Allow this to fail softly, since comment edits might re-update or replace it
// Let the uniqueness handle this fail
CommentReply::create(context.pool(), &comment_reply_form)
.await
.ok();
if do_send_email {
let lang = get_interface_language(&parent_user_view);
send_email_to_user(
&parent_user_view,
&lang.notification_comment_reply_subject(&person.name),
&lang.notification_comment_reply_body(&comment.content, &inbox_link, &person.name),
context.settings(),
)
}
}
}
} else {
// If there's no parent, its the post creator
// Only add to recipients if that person isn't blocked
let creator_blocked = check_person_block(person.id, post.creator_id, context.pool())
.await
.is_err();
if post.creator_id != person.id && !creator_blocked {
let creator_id = post.creator_id;
let parent_user = LocalUserView::read_person(context.pool(), creator_id).await;
if let Ok(parent_user_view) = parent_user {
recipient_ids.push(parent_user_view.local_user.id);
let comment_reply_form = CommentReplyInsertForm {
recipient_id: parent_user_view.person.id,
comment_id: comment.id,
read: None,
};
// Allow this to fail softly, since comment edits might re-update or replace it
// Let the uniqueness handle this fail
CommentReply::create(context.pool(), &comment_reply_form)
.await
.ok();
if do_send_email {
let lang = get_interface_language(&parent_user_view);
send_email_to_user(
&parent_user_view,
&lang.notification_post_reply_subject(&person.name),
&lang.notification_post_reply_body(&comment.content, &inbox_link, &person.name),
context.settings(),
)
}
}
}
}
Ok(recipient_ids)
}

View File

@ -32,7 +32,6 @@ pub struct GetCommunityResponse {
pub community_view: CommunityView,
pub site: Option<Site>,
pub moderators: Vec<CommunityModeratorView>,
pub online: usize,
pub discussion_languages: Vec<LanguageId>,
}

View File

@ -1,5 +1,3 @@
use crate::websocket::chat_server::ChatServer;
use actix::Addr;
use lemmy_db_schema::{source::secret::Secret, utils::DbPool};
use lemmy_utils::{
rate_limit::RateLimitCell,
@ -11,7 +9,6 @@ use std::sync::Arc;
#[derive(Clone)]
pub struct LemmyContext {
pool: DbPool,
chat_server: Addr<ChatServer>,
client: Arc<ClientWithMiddleware>,
secret: Arc<Secret>,
rate_limit_cell: RateLimitCell,
@ -20,14 +17,12 @@ pub struct LemmyContext {
impl LemmyContext {
pub fn create(
pool: DbPool,
chat_server: Addr<ChatServer>,
client: ClientWithMiddleware,
secret: Secret,
rate_limit_cell: RateLimitCell,
) -> LemmyContext {
LemmyContext {
pool,
chat_server,
client: Arc::new(client),
secret: Arc::new(secret),
rate_limit_cell,
@ -36,9 +31,6 @@ impl LemmyContext {
pub fn pool(&self) -> &DbPool {
&self.pool
}
pub fn chat_server(&self) -> &Addr<ChatServer> {
&self.chat_server
}
pub fn client(&self) -> &ClientWithMiddleware {
&self.client
}

View File

@ -1,3 +1,5 @@
#[cfg(feature = "full")]
pub mod build_response;
pub mod comment;
pub mod community;
#[cfg(feature = "full")]
@ -12,11 +14,7 @@ pub mod sensitive;
pub mod site;
#[cfg(feature = "full")]
pub mod utils;
#[cfg(feature = "full")]
pub mod websocket;
#[macro_use]
extern crate strum_macros;
pub extern crate lemmy_db_schema;
pub extern crate lemmy_db_views;
pub extern crate lemmy_db_views_actor;

View File

@ -60,7 +60,6 @@ pub struct GetPostResponse {
pub moderators: Vec<CommunityModeratorView>,
/// A list of cross-posts, or other times / communities this link has been posted to.
pub cross_posts: Vec<PostView>,
pub online: usize,
}
#[skip_serializing_none]

View File

@ -294,7 +294,6 @@ pub struct SiteResponse {
pub struct GetSiteResponse {
pub site_view: SiteView,
pub admins: Vec<PersonView>,
pub online: usize,
pub version: String,
pub my_user: Option<MyUserInfo>,
pub all_languages: Vec<Language>,

View File

@ -1,77 +0,0 @@
use crate::websocket::{
handlers::{SessionInfo, WsMessage},
structs::CaptchaItem,
};
use actix::{Actor, Context};
use lemmy_db_schema::newtypes::{CommunityId, LocalUserId, PostId};
use lemmy_utils::ConnectionId;
use rand::{rngs::StdRng, SeedableRng};
use std::collections::{HashMap, HashSet};
pub struct ChatServer {
/// A map from generated random ID to session addr
pub sessions: HashMap<ConnectionId, SessionInfo>,
/// A map from post_id to set of connectionIDs
pub post_rooms: HashMap<PostId, HashSet<ConnectionId>>,
/// A map from community to set of connectionIDs
pub community_rooms: HashMap<CommunityId, HashSet<ConnectionId>>,
pub mod_rooms: HashMap<CommunityId, HashSet<ConnectionId>>,
/// A map from user id to its connection ID for joined users. Remember a user can have multiple
/// sessions (IE clients)
pub(super) user_rooms: HashMap<LocalUserId, HashSet<ConnectionId>>,
pub(super) rng: StdRng,
/// A list of the current captchas
pub(super) captchas: Vec<CaptchaItem>,
}
/// `ChatServer` is an actor. It maintains list of connection client session.
/// And manages available rooms. Peers send messages to other peers in same
/// room through `ChatServer`.
impl ChatServer {
pub fn new() -> ChatServer {
ChatServer {
sessions: Default::default(),
post_rooms: Default::default(),
community_rooms: Default::default(),
mod_rooms: Default::default(),
user_rooms: Default::default(),
rng: StdRng::from_entropy(),
captchas: vec![],
}
}
pub fn send_message(
&self,
connections: &HashSet<ConnectionId>,
message: &str,
exclude_connection: Option<ConnectionId>,
) {
for id in connections
.iter()
.filter(|c| Some(*c) != exclude_connection.as_ref())
{
if let Some(session) = self.sessions.get(id) {
session.addr.do_send(WsMessage(message.to_owned()));
}
}
}
}
impl Default for ChatServer {
fn default() -> Self {
Self::new()
}
}
/// Make actor from `ChatServer`
impl Actor for ChatServer {
/// We are going to use simple Context, we just need ability to communicate
/// with other actors.
type Context = Context<Self>;
}

View File

@ -1,45 +0,0 @@
use crate::websocket::{chat_server::ChatServer, structs::CaptchaItem};
use actix::{Context, Handler, Message};
use lemmy_db_schema::utils::naive_now;
/// Adding a Captcha
#[derive(Message)]
#[rtype(result = "()")]
pub struct AddCaptcha {
pub captcha: CaptchaItem,
}
impl Handler<AddCaptcha> for ChatServer {
type Result = ();
fn handle(&mut self, msg: AddCaptcha, _: &mut Context<Self>) -> Self::Result {
self.captchas.push(msg.captcha);
}
}
/// Checking a Captcha
#[derive(Message)]
#[rtype(bool)]
pub struct CheckCaptcha {
pub uuid: String,
pub answer: String,
}
impl Handler<CheckCaptcha> for ChatServer {
type Result = bool;
fn handle(&mut self, msg: CheckCaptcha, _: &mut Context<Self>) -> Self::Result {
// Remove all the ones that are past the expire time
self.captchas.retain(|x| x.expires.gt(&naive_now()));
let check = self
.captchas
.iter()
.any(|r| r.uuid == msg.uuid && r.answer.to_lowercase() == msg.answer.to_lowercase());
// Remove this uuid so it can't be re-checked (Checks only work once)
self.captchas.retain(|x| x.uuid != msg.uuid);
check
}
}

View File

@ -1,62 +0,0 @@
use crate::websocket::{
chat_server::ChatServer,
handlers::{SessionInfo, WsMessage},
};
use actix::{Context, Handler, Message, Recipient};
use lemmy_utils::ConnectionId;
use rand::Rng;
/// New chat session is created
#[derive(Message)]
#[rtype(ConnectionId)]
pub struct Connect {
pub addr: Recipient<WsMessage>,
}
/// Handler for Connect message.
///
/// Register new session and assign unique id to this session
impl Handler<Connect> for ChatServer {
type Result = ConnectionId;
fn handle(&mut self, msg: Connect, _: &mut Context<Self>) -> Self::Result {
// register session with random id
let id = self.rng.gen::<usize>();
let session = SessionInfo { addr: msg.addr };
self.sessions.insert(id, session);
// send id back
id
}
}
/// Session is disconnected
#[derive(Message)]
#[rtype(result = "()")]
pub struct Disconnect {
pub id: ConnectionId,
}
/// Handler for Disconnect message.
impl Handler<Disconnect> for ChatServer {
type Result = ();
fn handle(&mut self, msg: Disconnect, _: &mut Context<Self>) -> Self::Result {
// remove address
if self.sessions.remove(&msg.id).is_some() {
// remove session from all rooms
for sessions in self.user_rooms.values_mut() {
sessions.remove(&msg.id);
}
for sessions in self.post_rooms.values_mut() {
sessions.remove(&msg.id);
}
for sessions in self.community_rooms.values_mut() {
sessions.remove(&msg.id);
}
for sessions in self.mod_rooms.values_mut() {
sessions.remove(&msg.id);
}
}
}
}

View File

@ -1,120 +0,0 @@
use crate::websocket::chat_server::ChatServer;
use actix::{Context, Handler, Message};
use lemmy_db_schema::newtypes::{CommunityId, LocalUserId, PostId};
use lemmy_utils::ConnectionId;
use std::collections::HashSet;
/// Joining a Post room
#[derive(Message)]
#[rtype(result = "()")]
pub struct JoinPostRoom {
pub post_id: PostId,
pub id: ConnectionId,
}
impl Handler<JoinPostRoom> for ChatServer {
type Result = ();
fn handle(&mut self, msg: JoinPostRoom, _: &mut Context<Self>) -> Self::Result {
// remove session from all rooms
for sessions in self.post_rooms.values_mut() {
sessions.remove(&msg.id);
}
// Also leave all communities
// This avoids double messages
// TODO found a bug, whereby community messages like
// delete and remove aren't sent, because
// you left the community room
for sessions in self.community_rooms.values_mut() {
sessions.remove(&msg.id);
}
self
.post_rooms
.entry(msg.post_id)
.or_insert_with(HashSet::new)
.insert(msg.id);
}
}
/// Joining a Community Room
#[derive(Message)]
#[rtype(result = "()")]
pub struct JoinCommunityRoom {
pub community_id: CommunityId,
pub id: ConnectionId,
}
impl Handler<JoinCommunityRoom> for ChatServer {
type Result = ();
fn handle(&mut self, msg: JoinCommunityRoom, _: &mut Context<Self>) -> Self::Result {
// remove session from all rooms
for sessions in self.community_rooms.values_mut() {
sessions.remove(&msg.id);
}
// Also leave all post rooms
// This avoids double messages
for sessions in self.post_rooms.values_mut() {
sessions.remove(&msg.id);
}
self
.community_rooms
.entry(msg.community_id)
.or_insert_with(HashSet::new)
.insert(msg.id);
}
}
/// Joining a Mod room
#[derive(Message)]
#[rtype(result = "()")]
pub struct JoinModRoom {
pub community_id: CommunityId,
pub id: ConnectionId,
}
impl Handler<JoinModRoom> for ChatServer {
type Result = ();
fn handle(&mut self, msg: JoinModRoom, _: &mut Context<Self>) -> Self::Result {
// remove session from all rooms
for sessions in self.mod_rooms.values_mut() {
sessions.remove(&msg.id);
}
self
.mod_rooms
.entry(msg.community_id)
.or_insert_with(HashSet::new)
.insert(msg.id);
}
}
/// Joining a User room
#[derive(Message)]
#[rtype(result = "()")]
pub struct JoinUserRoom {
pub user_id: LocalUserId,
pub id: ConnectionId,
}
impl Handler<JoinUserRoom> for ChatServer {
type Result = ();
fn handle(&mut self, msg: JoinUserRoom, _: &mut Context<Self>) -> Self::Result {
// remove session from all rooms
for sessions in self.user_rooms.values_mut() {
sessions.remove(&msg.id);
}
self
.user_rooms
.entry(msg.user_id)
.or_insert_with(HashSet::new)
.insert(msg.id);
}
}

View File

@ -1,130 +0,0 @@
use crate::websocket::chat_server::ChatServer;
use actix::{Context, Handler, Message};
use lemmy_db_schema::newtypes::{CommunityId, LocalUserId, PostId};
use lemmy_utils::ConnectionId;
use std::collections::HashSet;
/// Sending a post room message
#[derive(Message)]
#[rtype(result = "()")]
pub struct SendPostRoomMessage {
pub post_id: PostId,
pub message: String,
pub websocket_id: Option<ConnectionId>,
}
impl Handler<SendPostRoomMessage> for ChatServer {
type Result = ();
fn handle(&mut self, msg: SendPostRoomMessage, _: &mut Context<Self>) -> Self::Result {
let room_connections = self.post_rooms.get(&msg.post_id);
if let Some(connections) = room_connections {
self.send_message(connections, &msg.message, msg.websocket_id);
}
}
}
/// Sending a community room message
#[derive(Message)]
#[rtype(result = "()")]
pub struct SendCommunityRoomMessage {
pub community_id: CommunityId,
pub message: String,
pub websocket_id: Option<ConnectionId>,
}
impl Handler<SendCommunityRoomMessage> for ChatServer {
type Result = ();
fn handle(&mut self, msg: SendCommunityRoomMessage, _: &mut Context<Self>) -> Self::Result {
let room_connections = self.community_rooms.get(&msg.community_id);
if let Some(connections) = room_connections {
self.send_message(connections, &msg.message, msg.websocket_id);
}
}
}
/// Sending a mod room message
#[derive(Message)]
#[rtype(result = "()")]
pub struct SendModRoomMessage {
pub community_id: CommunityId,
pub message: String,
pub websocket_id: Option<ConnectionId>,
}
impl Handler<SendModRoomMessage> for ChatServer {
type Result = ();
fn handle(&mut self, msg: SendModRoomMessage, _: &mut Context<Self>) -> Self::Result {
let room_connections = self.community_rooms.get(&msg.community_id);
if let Some(connections) = room_connections {
self.send_message(connections, &msg.message, msg.websocket_id);
}
}
}
/// Sending a user room message
#[derive(Message)]
#[rtype(result = "()")]
pub struct SendUserRoomMessage {
pub recipient_id: LocalUserId,
pub message: String,
pub websocket_id: Option<ConnectionId>,
}
impl Handler<SendUserRoomMessage> for ChatServer {
type Result = ();
fn handle(&mut self, msg: SendUserRoomMessage, _: &mut Context<Self>) -> Self::Result {
let room_connections = self.user_rooms.get(&msg.recipient_id);
if let Some(connections) = room_connections {
self.send_message(connections, &msg.message, msg.websocket_id);
}
}
}
/// Sending a message to every session
#[derive(Message)]
#[rtype(result = "()")]
pub struct SendAllMessage {
pub message: String,
pub websocket_id: Option<ConnectionId>,
}
impl Handler<SendAllMessage> for ChatServer {
type Result = ();
fn handle(&mut self, msg: SendAllMessage, _: &mut Context<Self>) -> Self::Result {
let connections: HashSet<ConnectionId> = self.sessions.keys().cloned().collect();
self.send_message(&connections, &msg.message, msg.websocket_id);
}
}
///// Send websocket message in all sessions which joined a specific room.
/////
///// `message` - The json message body to send
///// `room` - Connection IDs which should receive the message
///// `exclude_connection` - Dont send to user who initiated the api call, as that
///// would result in duplicate notification
//async fn send_message_in_room(
// &self,
// message: &str,
// room: Option<HashSet<ConnectionId>>,
// exclude_connection: Option<ConnectionId>,
//) -> Result<(), LemmyError> {
// let mut session = self.inner()?.sessions.clone();
// if let Some(room) = room {
// // Note, this will ignore any errors, such as closed connections
// join_all(
// room
// .into_iter()
// .filter(|c| Some(c) != exclude_connection.as_ref())
// .filter_map(|c| session.remove(&c))
// .map(|mut s: Session| async move { s.text(message).await }),
// )
// .await;
// }
// Ok(())
//}
//}

View File

@ -1,18 +0,0 @@
use actix::{Message, Recipient};
pub mod captcha;
pub mod connect;
pub mod join_rooms;
pub mod messages;
pub mod online_users;
/// A string message sent to a websocket session
#[derive(Message)]
#[rtype(result = "()")]
pub struct WsMessage(pub String);
// TODO move this?
pub struct SessionInfo {
pub addr: Recipient<WsMessage>,
// pub ip: IpAddr
}

View File

@ -1,55 +0,0 @@
use crate::websocket::chat_server::ChatServer;
use actix::{Context, Handler, Message};
use lemmy_db_schema::newtypes::{CommunityId, PostId};
/// Getting the number of online connections
#[derive(Message)]
#[rtype(usize)]
pub struct GetUsersOnline;
/// Handler for Disconnect message.
impl Handler<GetUsersOnline> for ChatServer {
type Result = usize;
fn handle(&mut self, _msg: GetUsersOnline, _: &mut Context<Self>) -> Self::Result {
self.sessions.len()
}
}
/// Getting the number of post users online
#[derive(Message)]
#[rtype(usize)]
pub struct GetPostUsersOnline {
pub post_id: PostId,
}
/// Handler for Disconnect message.
impl Handler<GetPostUsersOnline> for ChatServer {
type Result = usize;
fn handle(&mut self, msg: GetPostUsersOnline, _: &mut Context<Self>) -> Self::Result {
self
.post_rooms
.get(&msg.post_id)
.map_or(1, std::collections::HashSet::len)
}
}
/// Getting the number of post users online
#[derive(Message)]
#[rtype(usize)]
pub struct GetCommunityUsersOnline {
pub community_id: CommunityId,
}
/// Handler for Disconnect message.
impl Handler<GetCommunityUsersOnline> for ChatServer {
type Result = usize;
fn handle(&mut self, msg: GetCommunityUsersOnline, _: &mut Context<Self>) -> Self::Result {
self
.community_rooms
.get(&msg.community_id)
.map_or(1, std::collections::HashSet::len)
}
}

View File

@ -1,146 +0,0 @@
use actix::{Message, Recipient};
use lemmy_utils::error::LemmyError;
use serde::Serialize;
pub mod chat_server;
pub mod handlers;
pub mod send;
pub mod structs;
/// A string message sent to a websocket session
#[derive(Message)]
#[rtype(result = "()")]
pub struct WsMessage(pub String);
pub struct SessionInfo {
pub addr: Recipient<WsMessage>,
}
#[derive(Serialize)]
struct WebsocketResponse<T> {
op: String,
data: T,
}
pub fn serialize_websocket_message<Response, OP>(
op: &OP,
data: &Response,
) -> Result<String, LemmyError>
where
Response: Serialize,
OP: ToString,
{
let response = WebsocketResponse {
op: op.to_string(),
data,
};
Ok(serde_json::to_string(&response)?)
}
#[derive(EnumString, Display, Debug, Clone)]
pub enum UserOperation {
Login,
GetCaptcha,
SaveComment,
CreateCommentLike,
DistinguishComment,
CreateCommentReport,
ResolveCommentReport,
ListCommentReports,
CreatePostLike,
LockPost,
FeaturePost,
MarkPostAsRead,
SavePost,
CreatePostReport,
ResolvePostReport,
ListPostReports,
GetReportCount,
GetUnreadCount,
VerifyEmail,
FollowCommunity,
GetReplies,
GetPersonMentions,
MarkPersonMentionAsRead,
MarkCommentReplyAsRead,
GetModlog,
BanFromCommunity,
AddModToCommunity,
AddAdmin,
GetUnreadRegistrationApplicationCount,
ListRegistrationApplications,
ApproveRegistrationApplication,
BanPerson,
GetBannedPersons,
MarkAllAsRead,
SaveUserSettings,
TransferCommunity,
LeaveAdmin,
PasswordReset,
PasswordChange,
MarkPrivateMessageAsRead,
CreatePrivateMessageReport,
ResolvePrivateMessageReport,
ListPrivateMessageReports,
UserJoin,
PostJoin,
CommunityJoin,
ModJoin,
ChangePassword,
GetSiteMetadata,
BlockCommunity,
BlockPerson,
PurgePerson,
PurgeCommunity,
PurgePost,
PurgeComment,
GetFederatedInstances,
}
#[derive(EnumString, Display, Debug, Clone)]
pub enum UserOperationCrud {
// Site
CreateSite,
GetSite,
EditSite,
// Community
CreateCommunity,
ListCommunities,
EditCommunity,
DeleteCommunity,
RemoveCommunity,
// Post
CreatePost,
GetPost,
EditPost,
DeletePost,
RemovePost,
// Comment
CreateComment,
GetComment,
EditComment,
DeleteComment,
RemoveComment,
// User
Register,
DeleteAccount,
// Private Message
CreatePrivateMessage,
GetPrivateMessages,
EditPrivateMessage,
DeletePrivateMessage,
//Emojis
CreateCustomEmoji,
EditCustomEmoji,
DeleteCustomEmoji,
}
#[derive(EnumString, Display, Debug, Clone)]
pub enum UserOperationApub {
GetPosts,
GetCommunity,
GetComments,
GetPersonDetails,
Search,
ResolveObject,
}

View File

@ -1,405 +0,0 @@
use super::{
handlers::messages::{
SendAllMessage,
SendCommunityRoomMessage,
SendModRoomMessage,
SendPostRoomMessage,
SendUserRoomMessage,
},
serialize_websocket_message,
};
use crate::{
comment::CommentResponse,
community::CommunityResponse,
context::LemmyContext,
post::PostResponse,
private_message::PrivateMessageResponse,
utils::{check_person_block, get_interface_language, send_email_to_user},
};
use lemmy_db_schema::{
newtypes::{CommentId, CommunityId, LocalUserId, PersonId, PostId, PrivateMessageId},
source::{
actor_language::CommunityLanguage,
comment::Comment,
comment_reply::{CommentReply, CommentReplyInsertForm},
person::Person,
person_mention::{PersonMention, PersonMentionInsertForm},
post::Post,
},
traits::Crud,
SubscribedType,
};
use lemmy_db_views::structs::{CommentView, LocalUserView, PostView, PrivateMessageView};
use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{error::LemmyError, utils::mention::MentionData, ConnectionId};
use serde::Serialize;
impl LemmyContext {
#[tracing::instrument(skip_all)]
pub async fn send_post_ws_message<OP>(
&self,
op: &OP,
post_id: PostId,
websocket_id: Option<ConnectionId>,
person_id: Option<PersonId>,
) -> Result<PostResponse, LemmyError>
where
OP: ToString,
{
let post_view = PostView::read(self.pool(), post_id, person_id, Some(true)).await?;
let res = PostResponse { post_view };
// Send it to the post room
// Don't send my data with it
let mut post_sent = res.clone();
post_sent.post_view.my_vote = None;
let message = serialize_websocket_message(op, &post_sent)?;
self.chat_server().do_send(SendPostRoomMessage {
post_id,
message: message.clone(),
websocket_id,
});
// Send it to /c/all and that community
self.chat_server().do_send(SendCommunityRoomMessage {
community_id: CommunityId(0),
message: message.clone(),
websocket_id,
});
self.chat_server().do_send(SendCommunityRoomMessage {
community_id: post_sent.post_view.community.id,
message,
websocket_id,
});
Ok(res)
}
// TODO: in many call sites in apub crate, we are setting an empty vec for recipient_ids,
// we should get the actual recipient actors from somewhere
#[tracing::instrument(skip_all)]
pub async fn send_comment_ws_message_simple<OP>(
&self,
op: &OP,
comment_id: CommentId,
) -> Result<CommentResponse, LemmyError>
where
OP: ToString,
{
self
.send_comment_ws_message(op, comment_id, None, None, None, vec![])
.await
}
#[tracing::instrument(skip_all)]
pub async fn send_comment_ws_message<OP>(
&self,
op: &OP,
comment_id: CommentId,
websocket_id: Option<ConnectionId>,
form_id: Option<String>,
person_id: Option<PersonId>,
recipient_ids: Vec<LocalUserId>,
) -> Result<CommentResponse, LemmyError>
where
OP: ToString,
{
let view = CommentView::read(self.pool(), comment_id, person_id).await?;
let mut res = CommentResponse {
comment_view: view,
recipient_ids,
form_id,
};
// Strip out my specific user info
let mut sent_recipient_comment = res.clone();
sent_recipient_comment.form_id = None;
sent_recipient_comment.comment_view.my_vote = None;
let recipient_message = serialize_websocket_message(op, &sent_recipient_comment)?;
// Send it to the recipient(s) including the mentioned users
for recipient_id in &sent_recipient_comment.recipient_ids {
self.chat_server().do_send(SendUserRoomMessage {
recipient_id: *recipient_id,
message: recipient_message.clone(),
websocket_id,
});
}
// Remove the recipients here to separate mentions / user messages from post or community comments
let mut sent_post_comment = sent_recipient_comment;
sent_post_comment.recipient_ids = Vec::new();
let post_message = serialize_websocket_message(op, &sent_post_comment)?;
// Send it to the post room
self.chat_server().do_send(SendPostRoomMessage {
post_id: sent_post_comment.comment_view.post.id,
message: post_message.clone(),
websocket_id,
});
// Send it to the community too
self.chat_server().do_send(SendCommunityRoomMessage {
community_id: sent_post_comment.comment_view.community.id,
message: post_message,
websocket_id,
});
// TODO should I send it to all? Seems excessive
// self
// .send_community_room_message(
// user_operation,
// &comment_post_sent,
// CommunityId(0),
// websocket_id,
// )
// .await?;
// No need to return recipients
res.recipient_ids = Vec::new();
Ok(res)
}
#[tracing::instrument(skip_all)]
pub async fn send_community_ws_message<OP>(
&self,
op: &OP,
community_id: CommunityId,
websocket_id: Option<ConnectionId>,
person_id: Option<PersonId>,
) -> Result<CommunityResponse, LemmyError>
where
OP: ToString,
{
let community_view =
CommunityView::read(self.pool(), community_id, person_id, Some(true)).await?;
let discussion_languages = CommunityLanguage::read(self.pool(), community_id).await?;
let mut res = CommunityResponse {
community_view,
discussion_languages,
};
// Strip out the person id and subscribed when sending to others
res.community_view.subscribed = SubscribedType::NotSubscribed;
let message = serialize_websocket_message(op, &res)?;
self.chat_server().do_send(SendCommunityRoomMessage {
community_id: res.community_view.community.id,
message,
websocket_id,
});
Ok(res)
}
#[tracing::instrument(skip_all)]
pub async fn send_pm_ws_message<OP>(
&self,
op: &OP,
private_message_id: PrivateMessageId,
websocket_id: Option<ConnectionId>,
) -> Result<PrivateMessageResponse, LemmyError>
where
OP: ToString,
{
let view = PrivateMessageView::read(self.pool(), private_message_id).await?;
let res = PrivateMessageResponse {
private_message_view: view,
};
// Send notifications to the local recipient, if one exists
if res.private_message_view.recipient.local {
let recipient_id = res.private_message_view.recipient.id;
let local_recipient = LocalUserView::read_person(self.pool(), recipient_id).await?;
let message = serialize_websocket_message(op, &res)?;
self.chat_server().do_send(SendUserRoomMessage {
recipient_id: local_recipient.local_user.id,
message,
websocket_id,
});
}
Ok(res)
}
#[tracing::instrument(skip_all)]
pub async fn send_local_notifs(
&self,
mentions: Vec<MentionData>,
comment: &Comment,
person: &Person,
post: &Post,
do_send_email: bool,
) -> Result<Vec<LocalUserId>, LemmyError> {
let mut recipient_ids = Vec::new();
let inbox_link = format!("{}/inbox", self.settings().get_protocol_and_hostname());
// Send the local mentions
for mention in mentions
.iter()
.filter(|m| m.is_local(&self.settings().hostname) && m.name.ne(&person.name))
.collect::<Vec<&MentionData>>()
{
let mention_name = mention.name.clone();
let user_view = LocalUserView::read_from_name(self.pool(), &mention_name).await;
if let Ok(mention_user_view) = user_view {
// TODO
// At some point, make it so you can't tag the parent creator either
// This can cause two notifications, one for reply and the other for mention
recipient_ids.push(mention_user_view.local_user.id);
let user_mention_form = PersonMentionInsertForm {
recipient_id: mention_user_view.person.id,
comment_id: comment.id,
read: None,
};
// Allow this to fail softly, since comment edits might re-update or replace it
// Let the uniqueness handle this fail
PersonMention::create(self.pool(), &user_mention_form)
.await
.ok();
// Send an email to those local users that have notifications on
if do_send_email {
let lang = get_interface_language(&mention_user_view);
send_email_to_user(
&mention_user_view,
&lang.notification_mentioned_by_subject(&person.name),
&lang.notification_mentioned_by_body(&comment.content, &inbox_link, &person.name),
self.settings(),
)
}
}
}
// Send comment_reply to the parent commenter / poster
if let Some(parent_comment_id) = comment.parent_comment_id() {
let parent_comment = Comment::read(self.pool(), parent_comment_id).await?;
// Get the parent commenter local_user
let parent_creator_id = parent_comment.creator_id;
// Only add to recipients if that person isn't blocked
let creator_blocked = check_person_block(person.id, parent_creator_id, self.pool())
.await
.is_err();
// Don't send a notif to yourself
if parent_comment.creator_id != person.id && !creator_blocked {
let user_view = LocalUserView::read_person(self.pool(), parent_creator_id).await;
if let Ok(parent_user_view) = user_view {
recipient_ids.push(parent_user_view.local_user.id);
let comment_reply_form = CommentReplyInsertForm {
recipient_id: parent_user_view.person.id,
comment_id: comment.id,
read: None,
};
// Allow this to fail softly, since comment edits might re-update or replace it
// Let the uniqueness handle this fail
CommentReply::create(self.pool(), &comment_reply_form)
.await
.ok();
if do_send_email {
let lang = get_interface_language(&parent_user_view);
send_email_to_user(
&parent_user_view,
&lang.notification_comment_reply_subject(&person.name),
&lang.notification_comment_reply_body(&comment.content, &inbox_link, &person.name),
self.settings(),
)
}
}
}
} else {
// If there's no parent, its the post creator
// Only add to recipients if that person isn't blocked
let creator_blocked = check_person_block(person.id, post.creator_id, self.pool())
.await
.is_err();
if post.creator_id != person.id && !creator_blocked {
let creator_id = post.creator_id;
let parent_user = LocalUserView::read_person(self.pool(), creator_id).await;
if let Ok(parent_user_view) = parent_user {
recipient_ids.push(parent_user_view.local_user.id);
let comment_reply_form = CommentReplyInsertForm {
recipient_id: parent_user_view.person.id,
comment_id: comment.id,
read: None,
};
// Allow this to fail softly, since comment edits might re-update or replace it
// Let the uniqueness handle this fail
CommentReply::create(self.pool(), &comment_reply_form)
.await
.ok();
if do_send_email {
let lang = get_interface_language(&parent_user_view);
send_email_to_user(
&parent_user_view,
&lang.notification_post_reply_subject(&person.name),
&lang.notification_post_reply_body(&comment.content, &inbox_link, &person.name),
self.settings(),
)
}
}
}
}
Ok(recipient_ids)
}
#[tracing::instrument(skip_all)]
pub fn send_all_ws_message<Data, OP>(
&self,
op: &OP,
data: Data,
websocket_id: Option<ConnectionId>,
) -> Result<(), LemmyError>
where
Data: Serialize,
OP: ToString,
{
let message = serialize_websocket_message(op, &data)?;
self.chat_server().do_send(SendAllMessage {
message,
websocket_id,
});
Ok(())
}
#[tracing::instrument(skip_all)]
pub fn send_mod_ws_message<Data, OP>(
&self,
op: &OP,
data: Data,
community_id: CommunityId,
websocket_id: Option<ConnectionId>,
) -> Result<(), LemmyError>
where
Data: Serialize,
OP: ToString,
{
let message = serialize_websocket_message(op, &data)?;
self.chat_server().do_send(SendModRoomMessage {
community_id,
message,
websocket_id,
});
Ok(())
}
}

View File

@ -1,76 +0,0 @@
use crate::sensitive::Sensitive;
use lemmy_db_schema::newtypes::{CommunityId, PostId};
use serde::{Deserialize, Serialize};
#[cfg(feature = "full")]
use ts_rs::TS;
#[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Join a user room.
pub struct UserJoin {
pub auth: Sensitive<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// The join response.
pub struct UserJoinResponse {
pub joined: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Join a community room.
pub struct CommunityJoin {
pub community_id: CommunityId,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// The join response.
pub struct CommunityJoinResponse {
pub joined: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Join a mod room.
pub struct ModJoin {
pub community_id: CommunityId,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// The join response.
pub struct ModJoinResponse {
pub joined: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Join a post room.
pub struct PostJoin {
pub post_id: PostId,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// The join response.
pub struct PostJoinResponse {
pub joined: bool,
}
#[derive(Debug)]
pub struct CaptchaItem {
pub uuid: String,
pub answer: String,
pub expires: chrono::NaiveDateTime,
}

View File

@ -1,6 +1,7 @@
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::{build_comment_response, send_local_notifs},
comment::{CommentResponse, CreateComment},
context::LemmyContext,
utils::{
@ -13,7 +14,6 @@ use lemmy_api_common::{
local_user_view_from_jwt,
EndpointType,
},
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
source::{
@ -32,19 +32,14 @@ use lemmy_utils::{
slurs::remove_slurs,
validation::is_valid_body_field,
},
ConnectionId,
};
#[async_trait::async_trait(?Send)]
impl PerformCrud for CreateComment {
type Response = CommentResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommentResponse, LemmyError> {
let data: &CreateComment = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
let local_site = LocalSite::read(context.pool()).await?;
@ -129,22 +124,21 @@ impl PerformCrud for CreateComment {
.map_err(|e| LemmyError::from_error_message(e, "couldnt_create_comment"))?;
// Scan the comment for user mentions, add those rows
let post_id = post.id;
let mentions = scrape_text_for_mentions(&content_slurs_removed);
let recipient_ids = context
.send_local_notifs(
let recipient_ids = send_local_notifs(
mentions,
&updated_comment,
&local_user_view.person,
&post,
true,
context,
)
.await?;
// You like your own comment by default
let like_form = CommentLikeForm {
comment_id: inserted_comment.id,
post_id,
post_id: post.id,
person_id: local_user_view.person.id,
score: 1,
};
@ -182,13 +176,11 @@ impl PerformCrud for CreateComment {
}
}
context
.send_comment_ws_message(
&UserOperationCrud::CreateComment,
build_comment_response(
context,
inserted_comment.id,
websocket_id,
data.form_id.clone(),
Some(local_user_view.person.id),
Some(local_user_view),
self.form_id.clone(),
recipient_ids,
)
.await

View File

@ -1,10 +1,10 @@
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::{build_comment_response, send_local_notifs},
comment::{CommentResponse, DeleteComment},
context::LemmyContext,
utils::{check_community_ban, local_user_view_from_jwt},
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
source::{
@ -14,18 +14,14 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views::structs::CommentView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl PerformCrud for DeleteComment {
type Response = CommentResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommentResponse, LemmyError> {
let data: &DeleteComment = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -61,27 +57,23 @@ impl PerformCrud for DeleteComment {
let post_id = updated_comment.post_id;
let post = Post::read(context.pool(), post_id).await?;
let recipient_ids = context
.send_local_notifs(
let recipient_ids = send_local_notifs(
vec![],
&updated_comment,
&local_user_view.person,
&post,
false,
context,
)
.await?;
let res = context
.send_comment_ws_message(
&UserOperationCrud::DeleteComment,
data.comment_id,
websocket_id,
build_comment_response(
context,
updated_comment.id,
Some(local_user_view),
None,
Some(local_user_view.person.id),
recipient_ids,
)
.await?;
Ok(res)
.await
}
}

View File

@ -1,40 +1,26 @@
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::build_comment_response,
comment::{CommentResponse, GetComment},
context::LemmyContext,
utils::{check_private_instance, local_user_view_from_jwt_opt},
};
use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_db_views::structs::CommentView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl PerformCrud for GetComment {
type Response = CommentResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError> {
let data = self;
let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), context).await;
let local_site = LocalSite::read(context.pool()).await?;
check_private_instance(&local_user_view, &local_site)?;
let person_id = local_user_view.map(|u| u.person.id);
let id = data.id;
let comment_view = CommentView::read(context.pool(), id, person_id)
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_find_comment"))?;
Ok(Self::Response {
comment_view,
form_id: None,
recipient_ids: Vec::new(),
})
build_comment_response(context, data.id, local_user_view, None, vec![]).await
}
}

View File

@ -1,10 +1,10 @@
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::{build_comment_response, send_local_notifs},
comment::{CommentResponse, RemoveComment},
context::LemmyContext,
utils::{check_community_ban, is_mod_or_admin, local_user_view_from_jwt},
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
source::{
@ -15,18 +15,14 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views::structs::CommentView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl PerformCrud for RemoveComment {
type Response = CommentResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommentResponse, LemmyError> {
let data: &RemoveComment = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -69,27 +65,23 @@ impl PerformCrud for RemoveComment {
let post_id = updated_comment.post_id;
let post = Post::read(context.pool(), post_id).await?;
let recipient_ids = context
.send_local_notifs(
let recipient_ids = send_local_notifs(
vec![],
&updated_comment,
&local_user_view.person.clone(),
&post,
false,
context,
)
.await?;
let res = context
.send_comment_ws_message(
&UserOperationCrud::RemoveComment,
data.comment_id,
websocket_id,
None, // TODO maybe this might clear other forms
Some(local_user_view.person.id),
build_comment_response(
context,
updated_comment.id,
Some(local_user_view),
None,
recipient_ids,
)
.await?;
Ok(res)
.await
}
}

View File

@ -1,10 +1,10 @@
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::{build_comment_response, send_local_notifs},
comment::{CommentResponse, EditComment},
context::LemmyContext,
utils::{check_community_ban, local_site_to_slur_regex, local_user_view_from_jwt},
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
source::{
@ -23,19 +23,14 @@ use lemmy_utils::{
slurs::remove_slurs,
validation::is_valid_body_field,
},
ConnectionId,
};
#[async_trait::async_trait(?Send)]
impl PerformCrud for EditComment {
type Response = CommentResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommentResponse, LemmyError> {
let data: &EditComment = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
let local_site = LocalSite::read(context.pool()).await?;
@ -84,23 +79,21 @@ impl PerformCrud for EditComment {
// Do the mentions / recipients
let updated_comment_content = updated_comment.content.clone();
let mentions = scrape_text_for_mentions(&updated_comment_content);
let recipient_ids = context
.send_local_notifs(
let recipient_ids = send_local_notifs(
mentions,
&updated_comment,
&local_user_view.person,
&orig_comment.post,
false,
context,
)
.await?;
context
.send_comment_ws_message(
&UserOperationCrud::EditComment,
data.comment_id,
websocket_id,
data.form_id.clone(),
None,
build_comment_response(
context,
updated_comment.id,
Some(local_user_view),
self.form_id.clone(),
recipient_ids,
)
.await

View File

@ -2,6 +2,7 @@ use crate::PerformCrud;
use activitypub_federation::http_signatures::generate_actor_keypair;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::build_community_response,
community::{CommunityResponse, CreateCommunity},
context::LemmyContext,
utils::{
@ -31,26 +32,20 @@ use lemmy_db_schema::{
utils::diesel_option_overwrite_to_url_create,
};
use lemmy_db_views::structs::SiteView;
use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{
error::LemmyError,
utils::{
slurs::{check_slurs, check_slurs_opt},
validation::{is_valid_actor_name, is_valid_body_field},
},
ConnectionId,
};
#[async_trait::async_trait(?Send)]
impl PerformCrud for CreateCommunity {
type Response = CommunityResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<CommunityResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommunityResponse, LemmyError> {
let data: &CreateCommunity = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
let site_view = SiteView::read_local(context.pool()).await?;
@ -143,15 +138,6 @@ impl PerformCrud for CreateCommunity {
CommunityLanguage::update(context.pool(), languages, community_id).await?;
}
let person_id = local_user_view.person.id;
let community_view =
CommunityView::read(context.pool(), inserted_community.id, Some(person_id), None).await?;
let discussion_languages =
CommunityLanguage::read(context.pool(), inserted_community.id).await?;
Ok(CommunityResponse {
community_view,
discussion_languages,
})
build_community_response(context, local_user_view, community_id).await
}
}

View File

@ -1,28 +1,24 @@
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::build_community_response,
community::{CommunityResponse, DeleteCommunity},
context::LemmyContext,
utils::{is_top_mod, local_user_view_from_jwt},
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
source::community::{Community, CommunityUpdateForm},
traits::Crud,
};
use lemmy_db_views_actor::structs::CommunityModeratorView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl PerformCrud for DeleteCommunity {
type Response = CommunityResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<CommunityResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommunityResponse, LemmyError> {
let data: &DeleteCommunity = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -47,15 +43,6 @@ impl PerformCrud for DeleteCommunity {
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_community"))?;
let res = context
.send_community_ws_message(
&UserOperationCrud::DeleteCommunity,
data.community_id,
websocket_id,
Some(local_user_view.person.id),
)
.await?;
Ok(res)
build_community_response(context, local_user_view, community_id).await
}
}

View File

@ -7,17 +7,16 @@ use lemmy_api_common::{
};
use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_db_views_actor::community_view::CommunityQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl PerformCrud for ListCommunities {
type Response = ListCommunitiesResponse;
#[tracing::instrument(skip(context, _websocket_id))]
#[tracing::instrument(skip(context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<ListCommunitiesResponse, LemmyError> {
let data: &ListCommunities = self;
let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), context).await;

View File

@ -1,10 +1,10 @@
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::build_community_response,
community::{CommunityResponse, RemoveCommunity},
context::LemmyContext,
utils::{is_admin, local_user_view_from_jwt},
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
source::{
@ -13,18 +13,14 @@ use lemmy_db_schema::{
},
traits::Crud,
};
use lemmy_utils::{error::LemmyError, utils::time::naive_from_unix, ConnectionId};
use lemmy_utils::{error::LemmyError, utils::time::naive_from_unix};
#[async_trait::async_trait(?Send)]
impl PerformCrud for RemoveCommunity {
type Response = CommunityResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<CommunityResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommunityResponse, LemmyError> {
let data: &RemoveCommunity = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -55,15 +51,6 @@ impl PerformCrud for RemoveCommunity {
};
ModRemoveCommunity::create(context.pool(), &form).await?;
let res = context
.send_community_ws_message(
&UserOperationCrud::RemoveCommunity,
data.community_id,
websocket_id,
Some(local_user_view.person.id),
)
.await?;
Ok(res)
build_community_response(context, local_user_view, community_id).await
}
}

View File

@ -1,10 +1,10 @@
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::build_community_response,
community::{CommunityResponse, EditCommunity},
context::LemmyContext,
utils::{local_site_to_slur_regex, local_user_view_from_jwt},
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
newtypes::PersonId,
@ -20,19 +20,14 @@ use lemmy_db_views_actor::structs::CommunityModeratorView;
use lemmy_utils::{
error::LemmyError,
utils::{slurs::check_slurs_opt, validation::is_valid_body_field},
ConnectionId,
};
#[async_trait::async_trait(?Send)]
impl PerformCrud for EditCommunity {
type Response = CommunityResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<CommunityResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CommunityResponse, LemmyError> {
let data: &EditCommunity = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
let local_site = LocalSite::read(context.pool()).await?;
@ -82,13 +77,6 @@ impl PerformCrud for EditCommunity {
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_community"))?;
context
.send_community_ws_message(
&UserOperationCrud::EditCommunity,
data.community_id,
websocket_id,
None,
)
.await
build_community_response(context, local_user_view, community_id).await
}
}

View File

@ -11,18 +11,14 @@ use lemmy_db_schema::source::{
local_site::LocalSite,
};
use lemmy_db_views::structs::CustomEmojiView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl PerformCrud for CreateCustomEmoji {
type Response = CustomEmojiResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<CustomEmojiResponse, LemmyError> {
#[tracing::instrument(skip(self, context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CustomEmojiResponse, LemmyError> {
let data: &CreateCustomEmoji = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -6,17 +6,16 @@ use lemmy_api_common::{
utils::{is_admin, local_user_view_from_jwt},
};
use lemmy_db_schema::source::custom_emoji::CustomEmoji;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl PerformCrud for DeleteCustomEmoji {
type Response = DeleteCustomEmojiResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
#[tracing::instrument(skip(self, context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<DeleteCustomEmojiResponse, LemmyError> {
let data: &DeleteCustomEmoji = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -11,18 +11,14 @@ use lemmy_db_schema::source::{
local_site::LocalSite,
};
use lemmy_db_views::structs::CustomEmojiView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl PerformCrud for EditCustomEmoji {
type Response = CustomEmojiResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<CustomEmojiResponse, LemmyError> {
#[tracing::instrument(skip(self, context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<CustomEmojiResponse, LemmyError> {
let data: &EditCustomEmoji = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;

View File

@ -1,6 +1,6 @@
use actix_web::web::Data;
use lemmy_api_common::context::LemmyContext;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
mod comment;
mod community;
@ -14,9 +14,5 @@ mod user;
pub trait PerformCrud {
type Response: serde::ser::Serialize + Send;
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError>;
async fn perform(&self, context: &Data<LemmyContext>) -> Result<Self::Response, LemmyError>;
}

View File

@ -1,6 +1,7 @@
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::build_post_response,
context::LemmyContext,
post::{CreatePost, PostResponse},
request::fetch_site_data,
@ -14,7 +15,6 @@ use lemmy_api_common::{
mark_post_as_read,
EndpointType,
},
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
impls::actor_language::default_post_language,
@ -33,7 +33,6 @@ use lemmy_utils::{
slurs::{check_slurs, check_slurs_opt},
validation::{clean_url_params, is_valid_body_field, is_valid_post_title},
},
ConnectionId,
};
use tracing::{warn, Instrument};
use url::Url;
@ -43,12 +42,8 @@ use webmention::{Webmention, WebmentionError};
impl PerformCrud for CreatePost {
type Response = PostResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<PostResponse, LemmyError> {
let data: &CreatePost = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
let local_site = LocalSite::read(context.pool()).await?;
@ -171,13 +166,6 @@ impl PerformCrud for CreatePost {
}
}
context
.send_post_ws_message(
&UserOperationCrud::CreatePost,
inserted_post.id,
websocket_id,
Some(local_user_view.person.id),
)
.await
build_post_response(context, community_id, person_id, post_id).await
}
}

View File

@ -1,27 +1,23 @@
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::build_post_response,
context::LemmyContext,
post::{DeletePost, PostResponse},
utils::{check_community_ban, check_community_deleted_or_removed, local_user_view_from_jwt},
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
source::post::{Post, PostUpdateForm},
traits::Crud,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl PerformCrud for DeletePost {
type Response = PostResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<PostResponse, LemmyError> {
let data: &DeletePost = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -56,15 +52,12 @@ impl PerformCrud for DeletePost {
)
.await?;
let res = context
.send_post_ws_message(
&UserOperationCrud::DeletePost,
data.post_id,
websocket_id,
Some(local_user_view.person.id),
build_post_response(
context,
orig_post.community_id,
local_user_view.person.id,
post_id,
)
.await?;
Ok(res)
.await
}
}

View File

@ -9,7 +9,6 @@ use lemmy_api_common::{
local_user_view_from_jwt_opt,
mark_post_as_read,
},
websocket::handlers::online_users::GetPostUsersOnline,
};
use lemmy_db_schema::{
aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm},
@ -18,18 +17,14 @@ use lemmy_db_schema::{
};
use lemmy_db_views::{post_view::PostQuery, structs::PostView};
use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl PerformCrud for GetPost {
type Response = GetPostResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<GetPostResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<GetPostResponse, LemmyError> {
let data: &GetPost = self;
let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), context).await;
let local_site = LocalSite::read(context.pool()).await?;
@ -106,17 +101,11 @@ impl PerformCrud for GetPost {
Vec::new()
};
let online = context
.chat_server()
.send(GetPostUsersOnline { post_id })
.await?;
// Return the jwt
Ok(GetPostResponse {
post_view,
community_view,
moderators,
online,
cross_posts,
})
}

View File

@ -1,10 +1,10 @@
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::build_post_response,
context::LemmyContext,
post::{PostResponse, RemovePost},
utils::{check_community_ban, is_mod_or_admin, local_user_view_from_jwt},
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
source::{
@ -13,18 +13,14 @@ use lemmy_db_schema::{
},
traits::Crud,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl PerformCrud for RemovePost {
type Response = PostResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<PostResponse, LemmyError> {
let data: &RemovePost = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -65,15 +61,12 @@ impl PerformCrud for RemovePost {
};
ModRemovePost::create(context.pool(), &form).await?;
let res = context
.send_post_ws_message(
&UserOperationCrud::RemovePost,
data.post_id,
websocket_id,
Some(local_user_view.person.id),
build_post_response(
context,
orig_post.community_id,
local_user_view.person.id,
post_id,
)
.await?;
Ok(res)
.await
}
}

View File

@ -1,11 +1,11 @@
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
build_response::build_post_response,
context::LemmyContext,
post::{EditPost, PostResponse},
request::fetch_site_data,
utils::{check_community_ban, local_site_to_slur_regex, local_user_view_from_jwt},
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
source::{
@ -22,19 +22,14 @@ use lemmy_utils::{
slurs::check_slurs_opt,
validation::{clean_url_params, is_valid_body_field, is_valid_post_title},
},
ConnectionId,
};
#[async_trait::async_trait(?Send)]
impl PerformCrud for EditPost {
type Response = PostResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<PostResponse, LemmyError> {
let data: &EditPost = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
let local_site = LocalSite::read(context.pool()).await?;
@ -112,12 +107,11 @@ impl PerformCrud for EditPost {
return Err(LemmyError::from_error_message(e, err_type));
}
context
.send_post_ws_message(
&UserOperationCrud::EditPost,
data.post_id,
websocket_id,
Some(local_user_view.person.id),
build_post_response(
context,
orig_post.community_id,
local_user_view.person.id,
post_id,
)
.await
}

View File

@ -12,7 +12,6 @@ use lemmy_api_common::{
send_email_to_user,
EndpointType,
},
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
source::{
@ -21,22 +20,20 @@ use lemmy_db_schema::{
},
traits::Crud,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_db_views::structs::{LocalUserView, PrivateMessageView};
use lemmy_utils::{
error::LemmyError,
utils::{slurs::remove_slurs, validation::is_valid_body_field},
ConnectionId,
};
#[async_trait::async_trait(?Send)]
impl PerformCrud for CreatePrivateMessage {
type Response = PrivateMessageResponse;
#[tracing::instrument(skip(self, context, websocket_id))]
#[tracing::instrument(skip(self, context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<PrivateMessageResponse, LemmyError> {
let data: &CreatePrivateMessage = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -84,16 +81,10 @@ impl PerformCrud for CreatePrivateMessage {
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_create_private_message"))?;
let res = context
.send_pm_ws_message(
&UserOperationCrud::CreatePrivateMessage,
inserted_private_message.id,
websocket_id,
)
.await?;
let view = PrivateMessageView::read(context.pool(), inserted_private_message.id).await?;
// Send email to the local recipient, if one exists
if res.private_message_view.recipient.local {
if view.recipient.local {
let recipient_id = data.recipient_id;
let local_recipient = LocalUserView::read_person(context.pool(), recipient_id).await?;
let lang = get_interface_language(&local_recipient);
@ -110,6 +101,8 @@ impl PerformCrud for CreatePrivateMessage {
);
}
Ok(res)
Ok(PrivateMessageResponse {
private_message_view: view,
})
}
}

View File

@ -4,23 +4,22 @@ use lemmy_api_common::{
context::LemmyContext,
private_message::{DeletePrivateMessage, PrivateMessageResponse},
utils::local_user_view_from_jwt,
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
source::private_message::{PrivateMessage, PrivateMessageUpdateForm},
traits::Crud,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_db_views::structs::PrivateMessageView;
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl PerformCrud for DeletePrivateMessage {
type Response = PrivateMessageResponse;
#[tracing::instrument(skip(self, context, websocket_id))]
#[tracing::instrument(skip(self, context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<PrivateMessageResponse, LemmyError> {
let data: &DeletePrivateMessage = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -45,12 +44,9 @@ impl PerformCrud for DeletePrivateMessage {
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_private_message"))?;
context
.send_pm_ws_message(
&UserOperationCrud::DeletePrivateMessage,
data.private_message_id,
websocket_id,
)
.await
let view = PrivateMessageView::read(context.pool(), private_message_id).await?;
Ok(PrivateMessageResponse {
private_message_view: view,
})
}
}

View File

@ -6,17 +6,16 @@ use lemmy_api_common::{
utils::local_user_view_from_jwt,
};
use lemmy_db_views::private_message_view::PrivateMessageQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_utils::error::LemmyError;
#[async_trait::async_trait(?Send)]
impl PerformCrud for GetPrivateMessages {
type Response = PrivateMessagesResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
#[tracing::instrument(skip(self, context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<PrivateMessagesResponse, LemmyError> {
let data: &GetPrivateMessages = self;
let local_user_view = local_user_view_from_jwt(data.auth.as_ref(), context).await?;

View File

@ -4,7 +4,6 @@ use lemmy_api_common::{
context::LemmyContext,
private_message::{EditPrivateMessage, PrivateMessageResponse},
utils::{local_site_to_slur_regex, local_user_view_from_jwt},
websocket::UserOperationCrud,
};
use lemmy_db_schema::{
source::{
@ -14,21 +13,20 @@ use lemmy_db_schema::{
traits::Crud,
utils::naive_now,
};
use lemmy_db_views::structs::PrivateMessageView;
use lemmy_utils::{
error::LemmyError,
utils::{slurs::remove_slurs, validation::is_valid_body_field},
ConnectionId,
};
#[async_trait::async_trait(?Send)]
impl PerformCrud for EditPrivateMessage {
type Response = PrivateMessageResponse;
#[tracing::instrument(skip(self, context, websocket_id))]
#[tracing::instrument(skip(self, context))]
async fn perform(
&self,
context: &Data<LemmyContext>,
websocket_id: Option<ConnectionId>,
) -> Result<PrivateMessageResponse, LemmyError> {
let data: &EditPrivateMessage = self;
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
@ -57,12 +55,10 @@ impl PerformCrud for EditPrivateMessage {
.await
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_private_message"))?;
context
.send_pm_ws_message(
&UserOperationCrud::EditPrivateMessage,
data.private_message_id,
websocket_id,
)
.await
let view = PrivateMessageView::read(context.pool(), private_message_id).await?;
Ok(PrivateMessageResponse {
private_message_view: view,
})
}
}

View File

@ -31,7 +31,6 @@ use lemmy_utils::{
slurs::{check_slurs, check_slurs_opt},
validation::is_valid_body_field,
},
ConnectionId,
};
use url::Url;
@ -39,12 +38,8 @@ use url::Url;
impl PerformCrud for CreateSite {
type Response = SiteResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<SiteResponse, LemmyError> {
#[tracing::instrument(skip(context))]
async fn perform(&self, context: &Data<LemmyContext>) -> Result<SiteResponse, LemmyError> {
let data: &CreateSite = self;
let local_site = LocalSite::read(context.pool()).await?;

Some files were not shown because too many files have changed in this diff Show More