mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-12-22 19:01:32 +00:00
Most of the bulk work done, need to add tests yet.
This commit is contained in:
parent
f133079f0b
commit
05f218d53c
44 changed files with 1528 additions and 741 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -2699,8 +2699,10 @@ name = "lemmy_db_views_actor"
|
|||
version = "0.19.6-beta.7"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"derive-new",
|
||||
"diesel",
|
||||
"diesel-async",
|
||||
"i-love-jesus",
|
||||
"lemmy_db_schema",
|
||||
"lemmy_db_views",
|
||||
"lemmy_utils",
|
||||
|
@ -2710,6 +2712,7 @@ dependencies = [
|
|||
"serial_test",
|
||||
"strum",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"ts-rs",
|
||||
"url",
|
||||
]
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
use actix_web::web::{Data, Json, Query};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
person::{GetPersonCommentMentions, GetPersonCommentMentionsResponse},
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_db_views_actor::person_comment_mention_view::PersonCommentMentionQuery;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn list_comment_mentions(
|
||||
data: Query<GetPersonCommentMentions>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<GetPersonCommentMentionsResponse>> {
|
||||
let sort = data.sort;
|
||||
let page = data.page;
|
||||
let limit = data.limit;
|
||||
let unread_only = data.unread_only.unwrap_or_default();
|
||||
let person_id = Some(local_user_view.person.id);
|
||||
let show_bot_accounts = local_user_view.local_user.show_bot_accounts;
|
||||
|
||||
let comment_mentions = PersonCommentMentionQuery {
|
||||
recipient_id: person_id,
|
||||
my_person_id: person_id,
|
||||
sort,
|
||||
unread_only,
|
||||
show_bot_accounts,
|
||||
page,
|
||||
limit,
|
||||
}
|
||||
.list(&mut context.pool())
|
||||
.await?;
|
||||
|
||||
Ok(Json(GetPersonCommentMentionsResponse { comment_mentions }))
|
||||
}
|
39
crates/api/src/local_user/notifications/list_inbox.rs
Normal file
39
crates/api/src/local_user/notifications/list_inbox.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use actix_web::web::{Data, Json, Query};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
person::{ListInbox, ListInboxResponse},
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_db_views_actor::inbox_combined_view::InboxCombinedQuery;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn list_inbox(
|
||||
data: Query<ListInbox>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<ListInboxResponse>> {
|
||||
let unread_only = data.unread_only;
|
||||
let person_id = local_user_view.person.id;
|
||||
let show_bot_accounts = Some(local_user_view.local_user.show_bot_accounts);
|
||||
|
||||
// parse pagination token
|
||||
let page_after = if let Some(pa) = &data.page_cursor {
|
||||
Some(pa.read(&mut context.pool()).await?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let page_back = data.page_back;
|
||||
|
||||
let inbox = InboxCombinedQuery {
|
||||
my_person_id: person_id,
|
||||
unread_only,
|
||||
show_bot_accounts,
|
||||
page_after,
|
||||
page_back,
|
||||
}
|
||||
.list(&mut context.pool())
|
||||
.await?;
|
||||
|
||||
Ok(Json(ListInboxResponse { inbox }))
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
use actix_web::web::{Data, Json, Query};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
person::{GetPersonPostMentions, GetPersonPostMentionsResponse},
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_db_views_actor::person_post_mention_view::PersonPostMentionQuery;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn list_post_mentions(
|
||||
data: Query<GetPersonPostMentions>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<GetPersonPostMentionsResponse>> {
|
||||
let sort = data.sort;
|
||||
let page = data.page;
|
||||
let limit = data.limit;
|
||||
let unread_only = data.unread_only.unwrap_or_default();
|
||||
let person_id = Some(local_user_view.person.id);
|
||||
let show_bot_accounts = local_user_view.local_user.show_bot_accounts;
|
||||
|
||||
let post_mentions = PersonPostMentionQuery {
|
||||
recipient_id: person_id,
|
||||
my_person_id: person_id,
|
||||
sort,
|
||||
unread_only,
|
||||
show_bot_accounts,
|
||||
page,
|
||||
limit,
|
||||
}
|
||||
.list(&mut context.pool())
|
||||
.await?;
|
||||
|
||||
Ok(Json(GetPersonPostMentionsResponse { post_mentions }))
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
use actix_web::web::{Data, Json, Query};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
person::{GetReplies, GetRepliesResponse},
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_db_views_actor::comment_reply_view::CommentReplyQuery;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn list_replies(
|
||||
data: Query<GetReplies>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<GetRepliesResponse>> {
|
||||
let sort = data.sort;
|
||||
let page = data.page;
|
||||
let limit = data.limit;
|
||||
let unread_only = data.unread_only.unwrap_or_default();
|
||||
let person_id = Some(local_user_view.person.id);
|
||||
let show_bot_accounts = local_user_view.local_user.show_bot_accounts;
|
||||
|
||||
let replies = CommentReplyQuery {
|
||||
recipient_id: person_id,
|
||||
my_person_id: person_id,
|
||||
sort,
|
||||
unread_only,
|
||||
show_bot_accounts,
|
||||
page,
|
||||
limit,
|
||||
}
|
||||
.list(&mut context.pool())
|
||||
.await?;
|
||||
|
||||
Ok(Json(GetRepliesResponse { replies }))
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
use actix_web::web::{Data, Json};
|
||||
use lemmy_api_common::{context::LemmyContext, person::GetRepliesResponse};
|
||||
use lemmy_api_common::{context::LemmyContext, SuccessResponse};
|
||||
use lemmy_db_schema::source::{
|
||||
comment_reply::CommentReply,
|
||||
person_comment_mention::PersonCommentMention,
|
||||
person_post_mention::PersonPostMention,
|
||||
private_message::PrivateMessage,
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
|
@ -12,7 +13,7 @@ use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
|||
pub async fn mark_all_notifications_read(
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<GetRepliesResponse>> {
|
||||
) -> LemmyResult<Json<SuccessResponse>> {
|
||||
let person_id = local_user_view.person.id;
|
||||
|
||||
// Mark all comment_replies as read
|
||||
|
@ -25,10 +26,15 @@ pub async fn mark_all_notifications_read(
|
|||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||
|
||||
// Mark all post mentions as read
|
||||
PersonPostMention::mark_all_as_read(&mut context.pool(), person_id)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntUpdatePost)?;
|
||||
|
||||
// Mark all private_messages as read
|
||||
PrivateMessage::mark_all_as_read(&mut context.pool(), person_id)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?;
|
||||
|
||||
Ok(Json(GetRepliesResponse { replies: vec![] }))
|
||||
Ok(Json(SuccessResponse::default()))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
pub mod list_comment_mentions;
|
||||
pub mod list_post_mentions;
|
||||
pub mod list_replies;
|
||||
pub mod list_inbox;
|
||||
pub mod mark_all_read;
|
||||
pub mod mark_comment_mention_read;
|
||||
pub mod mark_post_mention_read;
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
use actix_web::web::{Data, Json};
|
||||
use lemmy_api_common::{context::LemmyContext, person::GetUnreadCountResponse};
|
||||
use lemmy_db_views::structs::{LocalUserView, PrivateMessageView};
|
||||
use lemmy_db_views_actor::structs::{
|
||||
CommentReplyView,
|
||||
PersonCommentMentionView,
|
||||
PersonPostMentionView,
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_db_views_actor::structs::InboxCombinedViewInternal;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
|
@ -14,25 +10,10 @@ pub async fn unread_count(
|
|||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<GetUnreadCountResponse>> {
|
||||
let person_id = local_user_view.person.id;
|
||||
|
||||
let replies =
|
||||
CommentReplyView::get_unread_count(&mut context.pool(), &local_user_view.local_user).await?;
|
||||
|
||||
let comment_mentions =
|
||||
PersonCommentMentionView::get_unread_count(&mut context.pool(), &local_user_view.local_user)
|
||||
let show_bot_accounts = local_user_view.local_user.show_bot_accounts;
|
||||
let count =
|
||||
InboxCombinedViewInternal::get_unread_count(&mut context.pool(), person_id, show_bot_accounts)
|
||||
.await?;
|
||||
|
||||
let post_mentions =
|
||||
PersonPostMentionView::get_unread_count(&mut context.pool(), &local_user_view.local_user)
|
||||
.await?;
|
||||
|
||||
let private_messages =
|
||||
PrivateMessageView::get_unread_count(&mut context.pool(), person_id).await?;
|
||||
|
||||
Ok(Json(GetUnreadCountResponse {
|
||||
replies,
|
||||
comment_mentions,
|
||||
post_mentions,
|
||||
private_messages,
|
||||
}))
|
||||
Ok(Json(GetUnreadCountResponse { count }))
|
||||
}
|
||||
|
|
|
@ -5,12 +5,7 @@ use lemmy_api_common::{
|
|||
context::LemmyContext,
|
||||
post::{CreatePostLike, PostResponse},
|
||||
send_activity::{ActivityChannel, SendActivityData},
|
||||
utils::{
|
||||
check_bot_account,
|
||||
check_community_user_action,
|
||||
check_local_vote_mode,
|
||||
mark_post_as_read,
|
||||
},
|
||||
utils::{check_bot_account, check_community_user_action, check_local_vote_mode},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
newtypes::PostOrCommentId,
|
||||
|
|
|
@ -7,7 +7,8 @@ use lemmy_db_schema::{
|
|||
source::private_message::{PrivateMessage, PrivateMessageUpdateForm},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_db_views::structs::{LocalUserView, PrivateMessageView};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_db_views_actor::structs::PrivateMessageView;
|
||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
|
|
|
@ -21,6 +21,7 @@ use lemmy_db_schema::{
|
|||
person::Person,
|
||||
person_comment_mention::{PersonCommentMention, PersonCommentMentionInsertForm},
|
||||
person_post_mention::{PersonPostMention, PersonPostMentionInsertForm},
|
||||
post::Post,
|
||||
},
|
||||
traits::Crud,
|
||||
};
|
||||
|
@ -103,31 +104,6 @@ pub async fn send_local_notifs(
|
|||
let mut recipient_ids = Vec::new();
|
||||
let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname());
|
||||
|
||||
// When called from api code, we have local user view and can read with CommentView
|
||||
// to reduce db queries. But when receiving a federated comment the user view is None,
|
||||
// which means that comments inside private communities cant be read. As a workaround
|
||||
// we need to read the items manually to bypass this check.
|
||||
let (comment, post, community) = if let Some(local_user_view) = local_user_view {
|
||||
let comment_view = CommentView::read(
|
||||
&mut context.pool(),
|
||||
comment_id,
|
||||
Some(&local_user_view.local_user),
|
||||
)
|
||||
.await?;
|
||||
(
|
||||
comment_view.comment,
|
||||
comment_view.post,
|
||||
comment_view.community,
|
||||
)
|
||||
} else {
|
||||
let comment = Comment::read(&mut context.pool(), comment_id).await?;
|
||||
let post = Post::read(&mut context.pool(), comment.post_id).await?;
|
||||
let community = Community::read(&mut context.pool(), post.community_id).await?;
|
||||
(comment, post, community)
|
||||
};
|
||||
// let person = my_local_user.person;
|
||||
// Read the comment view to get extra info
|
||||
|
||||
let (comment_opt, post, community) = match post_or_comment_id {
|
||||
PostOrCommentId::Post(post_id) => {
|
||||
let post_view = PostView::read(
|
||||
|
@ -140,10 +116,16 @@ pub async fn send_local_notifs(
|
|||
(None, post_view.post, post_view.community)
|
||||
}
|
||||
PostOrCommentId::Comment(comment_id) => {
|
||||
// When called from api code, we have local user view and can read with CommentView
|
||||
// to reduce db queries. But when receiving a federated comment the user view is None,
|
||||
// which means that comments inside private communities cant be read. As a workaround
|
||||
// we need to read the items manually to bypass this check.
|
||||
if let Some(local_user_view) = local_user_view {
|
||||
// Read the comment view to get extra info
|
||||
let comment_view = CommentView::read(
|
||||
&mut context.pool(),
|
||||
comment_id,
|
||||
local_user_view.map(|view| &view.local_user),
|
||||
Some(&local_user_view.local_user),
|
||||
)
|
||||
.await?;
|
||||
(
|
||||
|
@ -151,6 +133,12 @@ pub async fn send_local_notifs(
|
|||
comment_view.post,
|
||||
comment_view.community,
|
||||
)
|
||||
} else {
|
||||
let comment = Comment::read(&mut context.pool(), comment_id).await?;
|
||||
let post = Post::read(&mut context.pool(), comment.post_id).await?;
|
||||
let community = Community::read(&mut context.pool(), post.community_id).await?;
|
||||
(Some(comment), post, community)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ use lemmy_db_views::structs::{
|
|||
use lemmy_db_views_actor::structs::{
|
||||
CommentReplyView,
|
||||
CommunityModeratorView,
|
||||
InboxCombinedPaginationCursor,
|
||||
InboxCombinedView,
|
||||
PersonCommentMentionView,
|
||||
PersonPostMentionView,
|
||||
PersonView,
|
||||
|
@ -373,51 +375,25 @@ pub struct BlockPersonResponse {
|
|||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Get comment replies.
|
||||
pub struct GetReplies {
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sort: Option<CommentSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
/// Get your inbox (replies, comment mentions, post mentions, and messages)
|
||||
pub struct ListInbox {
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub unread_only: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Fetches your replies.
|
||||
// TODO, replies and mentions below should be redone as tagged enums.
|
||||
pub struct GetRepliesResponse {
|
||||
pub replies: Vec<CommentReplyView>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Get mentions for your user.
|
||||
pub struct GetPersonCommentMentions {
|
||||
pub sort: Option<CommentSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
pub page_cursor: Option<InboxCombinedPaginationCursor>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub unread_only: Option<bool>,
|
||||
pub page_back: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The response of mentions for your user.
|
||||
pub struct GetPersonCommentMentionsResponse {
|
||||
pub comment_mentions: Vec<PersonCommentMentionView>,
|
||||
/// Get your inbox (replies, comment mentions, post mentions, and messages)
|
||||
pub struct ListInboxResponse {
|
||||
pub inbox: Vec<InboxCombinedView>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||
|
@ -437,26 +413,6 @@ pub struct PersonCommentMentionResponse {
|
|||
pub person_comment_mention_view: PersonCommentMentionView,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Get mentions for your user.
|
||||
pub struct GetPersonPostMentions {
|
||||
pub sort: Option<PostSortType>,
|
||||
pub page: Option<i64>,
|
||||
pub limit: Option<i64>,
|
||||
pub unread_only: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The response of mentions for your user.
|
||||
pub struct GetPersonPostMentionsResponse {
|
||||
pub post_mentions: Vec<PersonPostMentionView>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
|
@ -540,12 +496,9 @@ pub struct GetReportCountResponse {
|
|||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A response containing counts for your notifications.
|
||||
/// A response containing a count of unread notifications.
|
||||
pub struct GetUnreadCountResponse {
|
||||
pub replies: i64,
|
||||
pub comment_mentions: i64,
|
||||
pub post_mentions: i64,
|
||||
pub private_messages: i64,
|
||||
pub count: i64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq, Hash)]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use lemmy_db_schema::newtypes::{PersonId, PrivateMessageId};
|
||||
use lemmy_db_views::structs::PrivateMessageView;
|
||||
use lemmy_db_views_actor::structs::PrivateMessageView;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::skip_serializing_none;
|
||||
#[cfg(feature = "full")]
|
||||
use ts_rs::TS;
|
||||
|
||||
|
@ -41,30 +40,6 @@ pub struct MarkPrivateMessageAsRead {
|
|||
pub read: bool,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Get your private messages.
|
||||
pub struct GetPrivateMessages {
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub unread_only: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub creator_id: Option<PersonId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The private messages response.
|
||||
pub struct PrivateMessagesResponse {
|
||||
pub private_messages: Vec<PrivateMessageView>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
|
|
|
@ -11,7 +11,7 @@ use lemmy_db_schema::{
|
|||
private_message::PrivateMessage,
|
||||
},
|
||||
};
|
||||
use lemmy_db_views::structs::PrivateMessageView;
|
||||
use lemmy_db_views_actor::structs::PrivateMessageView;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
use std::sync::{LazyLock, OnceLock};
|
||||
use tokio::{
|
||||
|
|
|
@ -16,7 +16,7 @@ use lemmy_api_common::{
|
|||
},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
impls::actor_language::default_post_language,
|
||||
impls::actor_language::validate_post_language,
|
||||
newtypes::PostOrCommentId,
|
||||
source::{
|
||||
comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm},
|
||||
|
|
|
@ -14,6 +14,7 @@ use lemmy_api_common::{
|
|||
},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
impls::actor_language::validate_post_language,
|
||||
newtypes::PostOrCommentId,
|
||||
source::{
|
||||
comment::{Comment, CommentUpdateForm},
|
||||
|
|
|
@ -16,7 +16,7 @@ use lemmy_api_common::{
|
|||
},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
impls::actor_language::default_post_language,
|
||||
impls::actor_language::validate_post_language,
|
||||
newtypes::PostOrCommentId,
|
||||
source::{
|
||||
community::Community,
|
||||
|
@ -162,9 +162,8 @@ pub async fn create_post(
|
|||
)
|
||||
.await?;
|
||||
|
||||
// TODO
|
||||
PostRead::mark_as_read(&mut context.pool(), &read_form).await?;
|
||||
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
|
||||
let read_form = PostReadForm::new(post_id, person_id);
|
||||
PostRead::mark_as_read(&mut context.pool(), &read_form).await?;
|
||||
|
||||
build_post_response(&context, community_id, local_user_view, post_id).await
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ use lemmy_db_schema::{
|
|||
},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_db_views::structs::{LocalUserView, PrivateMessageView};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_db_views_actor::structs::PrivateMessageView;
|
||||
use lemmy_utils::{
|
||||
error::{LemmyErrorExt, LemmyErrorType, LemmyResult},
|
||||
utils::{markdown::markdown_to_html, validation::is_valid_body_field},
|
||||
|
|
|
@ -9,7 +9,8 @@ use lemmy_db_schema::{
|
|||
source::private_message::{PrivateMessage, PrivateMessageUpdateForm},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_db_views::structs::{LocalUserView, PrivateMessageView};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_db_views_actor::structs::PrivateMessageView;
|
||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
pub mod create;
|
||||
pub mod delete;
|
||||
pub mod read;
|
||||
pub mod update;
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
use actix_web::web::{Data, Json, Query};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
private_message::{GetPrivateMessages, PrivateMessagesResponse},
|
||||
};
|
||||
use lemmy_db_views::{private_message_view::PrivateMessageQuery, structs::LocalUserView};
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn get_private_message(
|
||||
data: Query<GetPrivateMessages>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<PrivateMessagesResponse>> {
|
||||
let person_id = local_user_view.person.id;
|
||||
|
||||
let page = data.page;
|
||||
let limit = data.limit;
|
||||
let unread_only = data.unread_only.unwrap_or_default();
|
||||
let creator_id = data.creator_id;
|
||||
let messages = PrivateMessageQuery {
|
||||
page,
|
||||
limit,
|
||||
unread_only,
|
||||
creator_id,
|
||||
}
|
||||
.list(&mut context.pool(), person_id)
|
||||
.await?;
|
||||
|
||||
Ok(Json(PrivateMessagesResponse {
|
||||
private_messages: messages,
|
||||
}))
|
||||
}
|
|
@ -14,7 +14,8 @@ use lemmy_db_schema::{
|
|||
},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_db_views::structs::{LocalUserView, PrivateMessageView};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_db_views_actor::structs::PrivateMessageView;
|
||||
use lemmy_utils::{
|
||||
error::{LemmyErrorExt, LemmyErrorType, LemmyResult},
|
||||
utils::validation::is_valid_body_field,
|
||||
|
|
|
@ -14,7 +14,7 @@ use activitypub_federation::{
|
|||
};
|
||||
use lemmy_api_common::context::LemmyContext;
|
||||
use lemmy_db_schema::source::activity::ActivitySendTargets;
|
||||
use lemmy_db_views::structs::PrivateMessageView;
|
||||
use lemmy_db_views_actor::structs::PrivateMessageView;
|
||||
use lemmy_utils::error::{LemmyError, LemmyResult};
|
||||
use url::Url;
|
||||
|
||||
|
|
|
@ -836,3 +836,35 @@ CALL r.create_modlog_combined_trigger ('mod_remove_post');
|
|||
|
||||
CALL r.create_modlog_combined_trigger ('mod_transfer_community');
|
||||
|
||||
|
||||
-- Inbox: (replies, comment mentions, post mentions, and private_messages)
|
||||
CREATE PROCEDURE r.create_inbox_combined_trigger (table_name text)
|
||||
LANGUAGE plpgsql
|
||||
AS $a$
|
||||
BEGIN
|
||||
EXECUTE replace($b$ CREATE FUNCTION r.inbox_combined_thing_insert ( )
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
INSERT INTO inbox_combined (published, thing_id)
|
||||
VALUES (NEW.published, NEW.id);
|
||||
RETURN NEW;
|
||||
END $$;
|
||||
CREATE TRIGGER inbox_combined
|
||||
AFTER INSERT ON thing
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION r.inbox_combined_thing_insert ( );
|
||||
$b$,
|
||||
'thing',
|
||||
table_name);
|
||||
END;
|
||||
$a$;
|
||||
|
||||
CALL r.create_inbox_combined_trigger ('comment_reply');
|
||||
|
||||
CALL r.create_inbox_combined_trigger ('person_comment_mention');
|
||||
|
||||
CALL r.create_inbox_combined_trigger ('person_post_mention');
|
||||
|
||||
CALL r.create_inbox_combined_trigger ('private_message');
|
||||
|
|
|
@ -76,7 +76,7 @@ pub struct LocalUserId(pub i32);
|
|||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The private message id.
|
||||
pub struct PrivateMessageId(i32);
|
||||
pub struct PrivateMessageId(pub i32);
|
||||
|
||||
impl fmt::Display for PrivateMessageId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
@ -88,13 +88,13 @@ impl fmt::Display for PrivateMessageId {
|
|||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The person comment mention id.
|
||||
pub struct PersonCommentMentionId(i32);
|
||||
pub struct PersonCommentMentionId(pub i32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The person post mention id.
|
||||
pub struct PersonPostMentionId(i32);
|
||||
pub struct PersonPostMentionId(pub i32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||
|
@ -130,7 +130,7 @@ pub struct LanguageId(pub i32);
|
|||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The comment reply id.
|
||||
pub struct CommentReplyId(i32);
|
||||
pub struct CommentReplyId(pub i32);
|
||||
|
||||
#[derive(
|
||||
Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default, Ord, PartialOrd,
|
||||
|
@ -211,6 +211,11 @@ pub struct PersonSavedCombinedId(i32);
|
|||
#[cfg_attr(feature = "full", derive(DieselNewType))]
|
||||
pub struct ModlogCombinedId(i32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "full", derive(DieselNewType))]
|
||||
/// The inbox combined id
|
||||
pub struct InboxCombinedId(i32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
|
|
|
@ -330,6 +330,17 @@ diesel::table! {
|
|||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
inbox_combined (id) {
|
||||
id -> Int4,
|
||||
published -> Timestamptz,
|
||||
comment_reply_id -> Nullable<Int4>,
|
||||
person_comment_mention_id -> Nullable<Int4>,
|
||||
person_post_mention_id -> Nullable<Int4>,
|
||||
private_message_id -> Nullable<Int4>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
instance (id) {
|
||||
id -> Int4,
|
||||
|
@ -1052,6 +1063,10 @@ diesel::joinable!(email_verification -> local_user (local_user_id));
|
|||
diesel::joinable!(federation_allowlist -> instance (instance_id));
|
||||
diesel::joinable!(federation_blocklist -> instance (instance_id));
|
||||
diesel::joinable!(federation_queue_state -> instance (instance_id));
|
||||
diesel::joinable!(inbox_combined -> comment_reply (comment_reply_id));
|
||||
diesel::joinable!(inbox_combined -> person_comment_mention (person_comment_mention_id));
|
||||
diesel::joinable!(inbox_combined -> person_post_mention (person_post_mention_id));
|
||||
diesel::joinable!(inbox_combined -> private_message (private_message_id));
|
||||
diesel::joinable!(instance_actions -> instance (instance_id));
|
||||
diesel::joinable!(instance_actions -> person (person_id));
|
||||
diesel::joinable!(local_image -> local_user (local_user_id));
|
||||
|
@ -1154,6 +1169,7 @@ diesel::allow_tables_to_appear_in_same_query!(
|
|||
federation_blocklist,
|
||||
federation_queue_state,
|
||||
image_details,
|
||||
inbox_combined,
|
||||
instance,
|
||||
instance_actions,
|
||||
language,
|
||||
|
|
33
crates/db_schema/src/source/combined/inbox.rs
Normal file
33
crates/db_schema/src/source/combined/inbox.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
use crate::newtypes::{
|
||||
CommentReplyId,
|
||||
InboxCombinedId,
|
||||
PersonCommentMentionId,
|
||||
PersonPostMentionId,
|
||||
PrivateMessageId,
|
||||
};
|
||||
#[cfg(feature = "full")]
|
||||
use crate::schema::inbox_combined;
|
||||
use chrono::{DateTime, Utc};
|
||||
#[cfg(feature = "full")]
|
||||
use i_love_jesus::CursorKeysModule;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::skip_serializing_none;
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(PartialEq, Eq, Serialize, Deserialize, Debug, Clone)]
|
||||
#[cfg_attr(
|
||||
feature = "full",
|
||||
derive(Identifiable, Queryable, Selectable, CursorKeysModule)
|
||||
)]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = inbox_combined))]
|
||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||
#[cfg_attr(feature = "full", cursor_keys_module(name = inbox_combined_keys))]
|
||||
/// A combined inbox table.
|
||||
pub struct InboxCombined {
|
||||
pub id: InboxCombinedId,
|
||||
pub published: DateTime<Utc>,
|
||||
pub comment_reply_id: Option<CommentReplyId>,
|
||||
pub person_comment_mention_id: Option<PersonCommentMentionId>,
|
||||
pub person_post_mention_id: Option<PersonPostMentionId>,
|
||||
pub private_message_id: Option<PrivateMessageId>,
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
pub mod inbox;
|
||||
pub mod modlog;
|
||||
pub mod person_content;
|
||||
pub mod person_saved;
|
||||
|
|
|
@ -22,8 +22,6 @@ pub mod post_view;
|
|||
#[cfg(feature = "full")]
|
||||
pub mod private_message_report_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod private_message_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod registration_application_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod report_combined_view;
|
||||
|
|
|
@ -171,17 +171,6 @@ pub struct PostView {
|
|||
pub unread_comments: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A private message view.
|
||||
pub struct PrivateMessageView {
|
||||
pub private_message: PrivateMessage,
|
||||
pub creator: Person,
|
||||
pub recipient: Person,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
||||
|
|
|
@ -18,6 +18,8 @@ workspace = true
|
|||
full = [
|
||||
"lemmy_db_schema/full",
|
||||
"lemmy_utils/full",
|
||||
"tracing",
|
||||
"i-love-jesus",
|
||||
"diesel",
|
||||
"diesel-async",
|
||||
"ts-rs",
|
||||
|
@ -40,6 +42,9 @@ ts-rs = { workspace = true, optional = true }
|
|||
chrono.workspace = true
|
||||
strum = { workspace = true }
|
||||
lemmy_utils = { workspace = true, optional = true }
|
||||
tracing = { workspace = true, optional = true }
|
||||
i-love-jesus = { workspace = true, optional = true }
|
||||
derive-new.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = { workspace = true }
|
||||
|
|
|
@ -40,6 +40,7 @@ use lemmy_db_schema::{
|
|||
CommentSortType,
|
||||
};
|
||||
|
||||
// TODO get rid of all this
|
||||
fn queries<'a>() -> Queries<
|
||||
impl ReadFn<'a, CommentReplyView, (CommentReplyId, Option<PersonId>)>,
|
||||
impl ListFn<'a, CommentReplyView, CommentReplyQuery>,
|
||||
|
@ -130,6 +131,9 @@ fn queries<'a>() -> Queries<
|
|||
query = query.filter(not(person::bot_account));
|
||||
};
|
||||
|
||||
// Don't show replies from blocked persons
|
||||
query = query.filter(person_actions::blocked.is_null());
|
||||
|
||||
query = match options.sort.unwrap_or(CommentSortType::New) {
|
||||
CommentSortType::Hot => query.then_order_by(comment_aggregates::hot_rank.desc()),
|
||||
CommentSortType::Controversial => {
|
||||
|
@ -140,9 +144,6 @@ fn queries<'a>() -> Queries<
|
|||
CommentSortType::Top => query.order_by(comment_aggregates::score.desc()),
|
||||
};
|
||||
|
||||
// Don't show replies from blocked persons
|
||||
query = query.filter(person_actions::blocked.is_null());
|
||||
|
||||
let (limit, offset) = limit_and_offset(options.page, options.limit)?;
|
||||
|
||||
query
|
||||
|
|
971
crates/db_views_actor/src/inbox_combined_view.rs
Normal file
971
crates/db_views_actor/src/inbox_combined_view.rs
Normal file
|
@ -0,0 +1,971 @@
|
|||
use crate::structs::{
|
||||
CommentReplyView,
|
||||
InboxCombinedPaginationCursor,
|
||||
InboxCombinedView,
|
||||
InboxCombinedViewInternal,
|
||||
PersonCommentMentionView,
|
||||
PersonPostMentionView,
|
||||
PrivateMessageView,
|
||||
};
|
||||
use diesel::{
|
||||
dsl::not,
|
||||
result::Error,
|
||||
BoolExpressionMethods,
|
||||
ExpressionMethods,
|
||||
JoinOnDsl,
|
||||
NullableExpressionMethods,
|
||||
QueryDsl,
|
||||
SelectableHelper,
|
||||
};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use i_love_jesus::PaginatedQueryBuilder;
|
||||
use lemmy_db_schema::{
|
||||
aliases::{self, creator_community_actions},
|
||||
newtypes::PersonId,
|
||||
schema::{
|
||||
comment,
|
||||
comment_actions,
|
||||
comment_aggregates,
|
||||
comment_reply,
|
||||
community,
|
||||
community_actions,
|
||||
image_details,
|
||||
inbox_combined,
|
||||
instance_actions,
|
||||
local_user,
|
||||
person,
|
||||
person_actions,
|
||||
person_comment_mention,
|
||||
person_post_mention,
|
||||
post,
|
||||
post_actions,
|
||||
post_aggregates,
|
||||
private_message,
|
||||
},
|
||||
source::{
|
||||
combined::inbox::{inbox_combined_keys as key, InboxCombined},
|
||||
community::CommunityFollower,
|
||||
},
|
||||
utils::{actions, actions_alias, functions::coalesce, get_conn, DbPool},
|
||||
InternalToCombinedView,
|
||||
};
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
impl InboxCombinedViewInternal {
|
||||
/// Gets the number of unread mentions
|
||||
// TODO need to test this
|
||||
pub async fn get_unread_count(
|
||||
pool: &mut DbPool<'_>,
|
||||
my_person_id: PersonId,
|
||||
show_bot_accounts: bool,
|
||||
) -> Result<i64, Error> {
|
||||
use diesel::dsl::count;
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
|
||||
let item_creator = person::id;
|
||||
let recipient_person = aliases::person1.field(person::id);
|
||||
|
||||
let unread_filter = comment_reply::read
|
||||
.eq(false)
|
||||
.or(person_comment_mention::read.eq(false))
|
||||
.or(person_post_mention::read.eq(false))
|
||||
// If its unread, I only want the messages to me
|
||||
.or(
|
||||
private_message::read
|
||||
.eq(false)
|
||||
.and(private_message::recipient_id.eq(my_person_id)),
|
||||
);
|
||||
|
||||
let item_creator_join = comment::creator_id
|
||||
.eq(item_creator)
|
||||
.or(
|
||||
inbox_combined::person_post_mention_id
|
||||
.is_not_null()
|
||||
.and(post::creator_id.eq(item_creator)),
|
||||
)
|
||||
.or(private_message::creator_id.eq(item_creator));
|
||||
|
||||
let recipient_join = comment_reply::recipient_id
|
||||
.eq(recipient_person)
|
||||
.or(person_comment_mention::recipient_id.eq(recipient_person))
|
||||
.or(person_post_mention::recipient_id.eq(recipient_person));
|
||||
|
||||
let comment_join = comment_reply::comment_id
|
||||
.eq(comment::id)
|
||||
.or(person_comment_mention::comment_id.eq(comment::id));
|
||||
|
||||
let post_join = person_post_mention::post_id
|
||||
.eq(post::id)
|
||||
.or(comment::post_id.eq(post::id));
|
||||
|
||||
let mut query = inbox_combined::table
|
||||
.left_join(comment_reply::table)
|
||||
.left_join(person_comment_mention::table)
|
||||
.left_join(person_post_mention::table)
|
||||
.left_join(private_message::table)
|
||||
.left_join(comment::table.on(comment_join))
|
||||
.left_join(post::table.on(post_join))
|
||||
// The item creator
|
||||
.inner_join(person::table.on(item_creator_join))
|
||||
// The recipient
|
||||
.inner_join(aliases::person1.on(recipient_join))
|
||||
.left_join(actions(
|
||||
instance_actions::table,
|
||||
Some(my_person_id),
|
||||
person::instance_id,
|
||||
))
|
||||
.left_join(actions(
|
||||
person_actions::table,
|
||||
Some(my_person_id),
|
||||
item_creator,
|
||||
))
|
||||
// Filter for your user
|
||||
.filter(recipient_person.eq(my_person_id))
|
||||
// Filter unreads
|
||||
.filter(unread_filter)
|
||||
// Don't count replies from blocked users
|
||||
.filter(person_actions::blocked.is_null())
|
||||
.filter(instance_actions::blocked.is_null())
|
||||
.filter(comment::deleted.eq(false))
|
||||
.filter(comment::removed.eq(false))
|
||||
.filter(post::deleted.eq(false))
|
||||
.filter(post::removed.eq(false))
|
||||
.filter(private_message::deleted.eq(false))
|
||||
.into_boxed();
|
||||
|
||||
// These filters need to be kept in sync with the filters in queries().list()
|
||||
if !show_bot_accounts {
|
||||
query = query.filter(not(person::bot_account));
|
||||
}
|
||||
|
||||
query
|
||||
.select(count(inbox_combined::id))
|
||||
.first::<i64>(conn)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl InboxCombinedPaginationCursor {
|
||||
// get cursor for page that starts immediately after the given post
|
||||
pub fn after_post(view: &InboxCombinedView) -> InboxCombinedPaginationCursor {
|
||||
let (prefix, id) = match view {
|
||||
InboxCombinedView::CommentReply(v) => ('R', v.comment_reply.id.0),
|
||||
InboxCombinedView::CommentMention(v) => ('C', v.person_comment_mention.id.0),
|
||||
InboxCombinedView::PostMention(v) => ('P', v.person_post_mention.id.0),
|
||||
InboxCombinedView::PrivateMessage(v) => ('M', v.private_message.id.0),
|
||||
};
|
||||
// hex encoding to prevent ossification
|
||||
InboxCombinedPaginationCursor(format!("{prefix}{id:x}"))
|
||||
}
|
||||
|
||||
pub async fn read(&self, pool: &mut DbPool<'_>) -> Result<PaginationCursorData, Error> {
|
||||
let err_msg = || Error::QueryBuilderError("Could not parse pagination token".into());
|
||||
let mut query = inbox_combined::table
|
||||
.select(InboxCombined::as_select())
|
||||
.into_boxed();
|
||||
let (prefix, id_str) = self.0.split_at_checked(1).ok_or_else(err_msg)?;
|
||||
let id = i32::from_str_radix(id_str, 16).map_err(|_err| err_msg())?;
|
||||
query = match prefix {
|
||||
"R" => query.filter(inbox_combined::comment_reply_id.eq(id)),
|
||||
"C" => query.filter(inbox_combined::person_comment_mention_id.eq(id)),
|
||||
"P" => query.filter(inbox_combined::person_post_mention_id.eq(id)),
|
||||
"M" => query.filter(inbox_combined::private_message_id.eq(id)),
|
||||
_ => return Err(err_msg()),
|
||||
};
|
||||
let token = query.first(&mut get_conn(pool).await?).await?;
|
||||
|
||||
Ok(PaginationCursorData(token))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PaginationCursorData(InboxCombined);
|
||||
|
||||
#[derive(derive_new::new)]
|
||||
pub struct InboxCombinedQuery {
|
||||
pub my_person_id: PersonId,
|
||||
#[new(default)]
|
||||
pub unread_only: Option<bool>,
|
||||
#[new(default)]
|
||||
pub show_bot_accounts: Option<bool>,
|
||||
#[new(default)]
|
||||
pub page_after: Option<PaginationCursorData>,
|
||||
#[new(default)]
|
||||
pub page_back: Option<bool>,
|
||||
}
|
||||
|
||||
impl InboxCombinedQuery {
|
||||
pub async fn list(self, pool: &mut DbPool<'_>) -> LemmyResult<Vec<InboxCombinedView>> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
|
||||
let my_person_id = Some(self.my_person_id);
|
||||
let item_creator = person::id;
|
||||
let recipient_person = aliases::person1.field(person::id);
|
||||
|
||||
let item_creator_join = comment::creator_id
|
||||
.eq(item_creator)
|
||||
.or(
|
||||
inbox_combined::person_post_mention_id
|
||||
.is_not_null()
|
||||
.and(post::creator_id.eq(item_creator)),
|
||||
)
|
||||
.or(private_message::creator_id.eq(item_creator));
|
||||
|
||||
let recipient_join = comment_reply::recipient_id
|
||||
.eq(recipient_person)
|
||||
.or(person_comment_mention::recipient_id.eq(recipient_person))
|
||||
.or(person_post_mention::recipient_id.eq(recipient_person));
|
||||
// TODO this might need fixing, because if its not unread, you want all pms, even the ones you
|
||||
// sent
|
||||
// .or(private_message::recipient_id.eq(recipient_person));
|
||||
|
||||
let comment_join = comment_reply::comment_id
|
||||
.eq(comment::id)
|
||||
.or(person_comment_mention::comment_id.eq(comment::id));
|
||||
|
||||
let post_join = person_post_mention::post_id
|
||||
.eq(post::id)
|
||||
.or(comment::post_id.eq(post::id));
|
||||
|
||||
let community_join = post::id.eq(community::id);
|
||||
|
||||
let mut query = inbox_combined::table
|
||||
.left_join(comment_reply::table)
|
||||
.left_join(person_comment_mention::table)
|
||||
.left_join(person_post_mention::table)
|
||||
.left_join(private_message::table)
|
||||
.left_join(comment::table.on(comment_join))
|
||||
.left_join(post::table.on(post_join))
|
||||
.left_join(community::table.on(community_join))
|
||||
// The item creator
|
||||
.inner_join(person::table.on(item_creator_join))
|
||||
// The recipient
|
||||
.inner_join(aliases::person1.on(recipient_join))
|
||||
.left_join(actions_alias(
|
||||
creator_community_actions,
|
||||
item_creator,
|
||||
post::community_id,
|
||||
))
|
||||
.left_join(
|
||||
local_user::table.on(
|
||||
item_creator
|
||||
.eq(local_user::person_id)
|
||||
.and(local_user::admin.eq(true)),
|
||||
),
|
||||
)
|
||||
.left_join(actions(
|
||||
community_actions::table,
|
||||
my_person_id,
|
||||
post::community_id,
|
||||
))
|
||||
.left_join(actions(
|
||||
instance_actions::table,
|
||||
my_person_id,
|
||||
person::instance_id,
|
||||
))
|
||||
.left_join(actions(post_actions::table, my_person_id, post::id))
|
||||
.left_join(actions(person_actions::table, my_person_id, item_creator))
|
||||
.left_join(post_aggregates::table.on(post::id.eq(post_aggregates::post_id)))
|
||||
.left_join(comment_aggregates::table.on(comment::id.eq(comment_aggregates::comment_id)))
|
||||
.left_join(actions(comment_actions::table, my_person_id, comment::id))
|
||||
.left_join(image_details::table.on(post::thumbnail_url.eq(image_details::link.nullable())))
|
||||
// The recipient filter (IE only show replies to you)
|
||||
.filter(recipient_person.eq(self.my_person_id))
|
||||
.select((
|
||||
// Specific
|
||||
comment_reply::all_columns.nullable(),
|
||||
person_comment_mention::all_columns.nullable(),
|
||||
person_post_mention::all_columns.nullable(),
|
||||
post_aggregates::all_columns.nullable(),
|
||||
coalesce(
|
||||
post_aggregates::comments.nullable() - post_actions::read_comments_amount.nullable(),
|
||||
post_aggregates::comments,
|
||||
)
|
||||
.nullable(),
|
||||
post_actions::saved.nullable().is_not_null(),
|
||||
post_actions::read.nullable().is_not_null(),
|
||||
post_actions::hidden.nullable().is_not_null(),
|
||||
post_actions::like_score.nullable(),
|
||||
image_details::all_columns.nullable(),
|
||||
private_message::all_columns.nullable(),
|
||||
// Shared
|
||||
post::all_columns.nullable(),
|
||||
community::all_columns.nullable(),
|
||||
comment::all_columns.nullable(),
|
||||
comment_aggregates::all_columns.nullable(),
|
||||
comment_actions::saved.nullable().is_not_null(),
|
||||
comment_actions::like_score.nullable(),
|
||||
CommunityFollower::select_subscribed_type(),
|
||||
person::all_columns,
|
||||
aliases::person1.fields(person::all_columns),
|
||||
local_user::admin.nullable().is_not_null(),
|
||||
creator_community_actions
|
||||
.field(community_actions::became_moderator)
|
||||
.nullable()
|
||||
.is_not_null(),
|
||||
creator_community_actions
|
||||
.field(community_actions::received_ban)
|
||||
.nullable()
|
||||
.is_not_null(),
|
||||
person_actions::blocked.nullable().is_not_null(),
|
||||
community_actions::received_ban.nullable().is_not_null(),
|
||||
))
|
||||
.into_boxed();
|
||||
|
||||
// Filters
|
||||
if self.unread_only.unwrap_or_default() {
|
||||
query = query.filter(
|
||||
comment_reply::read
|
||||
.eq(false)
|
||||
.or(person_comment_mention::read.eq(false))
|
||||
.or(person_post_mention::read.eq(false))
|
||||
// If its unread, I only want the messages to me
|
||||
.or(
|
||||
private_message::read
|
||||
.eq(false)
|
||||
.and(private_message::recipient_id.eq(self.my_person_id)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if !(self.show_bot_accounts.unwrap_or_default()) {
|
||||
query = query.filter(not(person::bot_account));
|
||||
};
|
||||
|
||||
// Dont show replies from blocked users or instances
|
||||
query = query
|
||||
.filter(person_actions::blocked.is_null())
|
||||
.filter(instance_actions::blocked.is_null());
|
||||
|
||||
let mut query = PaginatedQueryBuilder::new(query);
|
||||
|
||||
let page_after = self.page_after.map(|c| c.0);
|
||||
|
||||
if self.page_back.unwrap_or_default() {
|
||||
query = query.before(page_after).limit_and_offset_from_end();
|
||||
} else {
|
||||
query = query.after(page_after);
|
||||
}
|
||||
|
||||
// Sorting by published
|
||||
query = query
|
||||
.then_desc(key::published)
|
||||
// Tie breaker
|
||||
.then_desc(key::id);
|
||||
|
||||
let res = query.load::<InboxCombinedViewInternal>(conn).await?;
|
||||
|
||||
// Map the query results to the enum
|
||||
let out = res.into_iter().filter_map(|u| u.map_to_enum()).collect();
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
||||
impl InternalToCombinedView for InboxCombinedViewInternal {
|
||||
type CombinedView = InboxCombinedView;
|
||||
|
||||
fn map_to_enum(&self) -> Option<Self::CombinedView> {
|
||||
// Use for a short alias
|
||||
let v = self.clone();
|
||||
|
||||
if let (Some(comment_reply), Some(comment), Some(counts), Some(post), Some(community)) = (
|
||||
v.comment_reply,
|
||||
v.comment.clone(),
|
||||
v.comment_counts.clone(),
|
||||
v.post.clone(),
|
||||
v.community.clone(),
|
||||
) {
|
||||
Some(InboxCombinedView::CommentReply(CommentReplyView {
|
||||
comment_reply,
|
||||
comment,
|
||||
counts,
|
||||
recipient: v.item_recipient,
|
||||
post,
|
||||
community,
|
||||
creator: v.item_creator,
|
||||
creator_banned_from_community: v.item_creator_banned_from_community,
|
||||
creator_is_moderator: v.item_creator_is_moderator,
|
||||
creator_is_admin: v.item_creator_is_admin,
|
||||
creator_blocked: v.item_creator_blocked,
|
||||
subscribed: v.subscribed,
|
||||
saved: v.comment_saved,
|
||||
my_vote: v.my_comment_vote,
|
||||
banned_from_community: v.banned_from_community,
|
||||
}))
|
||||
} else if let (
|
||||
Some(person_comment_mention),
|
||||
Some(comment),
|
||||
Some(counts),
|
||||
Some(post),
|
||||
Some(community),
|
||||
) = (
|
||||
v.person_comment_mention,
|
||||
v.comment,
|
||||
v.comment_counts,
|
||||
v.post.clone(),
|
||||
v.community.clone(),
|
||||
) {
|
||||
Some(InboxCombinedView::CommentMention(
|
||||
PersonCommentMentionView {
|
||||
person_comment_mention,
|
||||
comment,
|
||||
counts,
|
||||
recipient: v.item_recipient,
|
||||
post,
|
||||
community,
|
||||
creator: v.item_creator,
|
||||
creator_banned_from_community: v.item_creator_banned_from_community,
|
||||
creator_is_moderator: v.item_creator_is_moderator,
|
||||
creator_is_admin: v.item_creator_is_admin,
|
||||
creator_blocked: v.item_creator_blocked,
|
||||
subscribed: v.subscribed,
|
||||
saved: v.comment_saved,
|
||||
my_vote: v.my_comment_vote,
|
||||
banned_from_community: v.banned_from_community,
|
||||
},
|
||||
))
|
||||
} else if let (
|
||||
Some(person_post_mention),
|
||||
Some(post),
|
||||
Some(counts),
|
||||
Some(unread_comments),
|
||||
Some(community),
|
||||
) = (
|
||||
v.person_post_mention,
|
||||
v.post,
|
||||
v.post_counts,
|
||||
v.post_unread_comments,
|
||||
v.community,
|
||||
) {
|
||||
Some(InboxCombinedView::PostMention(PersonPostMentionView {
|
||||
person_post_mention,
|
||||
counts,
|
||||
post,
|
||||
community,
|
||||
recipient: v.item_recipient,
|
||||
unread_comments,
|
||||
creator: v.item_creator,
|
||||
creator_banned_from_community: v.item_creator_banned_from_community,
|
||||
creator_is_moderator: v.item_creator_is_moderator,
|
||||
creator_is_admin: v.item_creator_is_admin,
|
||||
creator_blocked: v.item_creator_blocked,
|
||||
subscribed: v.subscribed,
|
||||
saved: v.post_saved,
|
||||
read: v.post_read,
|
||||
hidden: v.post_hidden,
|
||||
my_vote: v.my_post_vote,
|
||||
image_details: v.image_details,
|
||||
banned_from_community: v.banned_from_community,
|
||||
}))
|
||||
} else if let Some(private_message) = v.private_message {
|
||||
Some(InboxCombinedView::PrivateMessage(PrivateMessageView {
|
||||
private_message,
|
||||
creator: v.item_creator,
|
||||
recipient: v.item_recipient,
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Dont delete these
|
||||
// #[cfg(test)]
|
||||
// #[expect(clippy::indexing_slicing)]
|
||||
// mod tests {
|
||||
|
||||
// use crate::{inbox_combined_view::InboxCombinedQuery, structs::InboxCombinedView};
|
||||
// use lemmy_db_schema::{
|
||||
// source::{
|
||||
// comment::{Comment, CommentInsertForm},
|
||||
// community::{Community, CommunityInsertForm},
|
||||
// instance::Instance,
|
||||
// person::{Person, PersonInsertForm},
|
||||
// post::{Post, PostInsertForm},
|
||||
// },
|
||||
// traits::Crud,
|
||||
// utils::{build_db_pool_for_tests, DbPool},
|
||||
// };
|
||||
// use lemmy_utils::error::LemmyResult;
|
||||
// use pretty_assertions::assert_eq;
|
||||
// use serial_test::serial;
|
||||
|
||||
// struct Data {
|
||||
// instance: Instance,
|
||||
// timmy: Person,
|
||||
// sara: Person,
|
||||
// timmy_post: Post,
|
||||
// timmy_post_2: Post,
|
||||
// sara_post: Post,
|
||||
// timmy_comment: Comment,
|
||||
// sara_comment: Comment,
|
||||
// sara_comment_2: Comment,
|
||||
// }
|
||||
|
||||
// async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
|
||||
// let instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||
|
||||
// let timmy_form = PersonInsertForm::test_form(instance.id, "timmy_pcv");
|
||||
// let timmy = Person::create(pool, &timmy_form).await?;
|
||||
|
||||
// let sara_form = PersonInsertForm::test_form(instance.id, "sara_pcv");
|
||||
// let sara = Person::create(pool, &sara_form).await?;
|
||||
|
||||
// let community_form = CommunityInsertForm::new(
|
||||
// instance.id,
|
||||
// "test community pcv".to_string(),
|
||||
// "nada".to_owned(),
|
||||
// "pubkey".to_string(),
|
||||
// );
|
||||
// let community = Community::create(pool, &community_form).await?;
|
||||
|
||||
// let timmy_post_form = PostInsertForm::new("timmy post prv".into(), timmy.id, community.id);
|
||||
// let timmy_post = Post::create(pool, &timmy_post_form).await?;
|
||||
|
||||
// let timmy_post_form_2 = PostInsertForm::new("timmy post prv 2".into(), timmy.id,
|
||||
// community.id); let timmy_post_2 = Post::create(pool, &timmy_post_form_2).await?;
|
||||
|
||||
// let sara_post_form = PostInsertForm::new("sara post prv".into(), sara.id, community.id);
|
||||
// let sara_post = Post::create(pool, &sara_post_form).await?;
|
||||
|
||||
// let timmy_comment_form =
|
||||
// CommentInsertForm::new(timmy.id, timmy_post.id, "timmy comment prv".into());
|
||||
// let timmy_comment = Comment::create(pool, &timmy_comment_form, None).await?;
|
||||
|
||||
// let sara_comment_form =
|
||||
// CommentInsertForm::new(sara.id, timmy_post.id, "sara comment prv".into());
|
||||
// let sara_comment = Comment::create(pool, &sara_comment_form, None).await?;
|
||||
|
||||
// let sara_comment_form_2 =
|
||||
// CommentInsertForm::new(sara.id, timmy_post_2.id, "sara comment prv 2".into());
|
||||
// let sara_comment_2 = Comment::create(pool, &sara_comment_form_2, None).await?;
|
||||
|
||||
// Ok(Data {
|
||||
// instance,
|
||||
// timmy,
|
||||
// sara,
|
||||
// timmy_post,
|
||||
// timmy_post_2,
|
||||
// sara_post,
|
||||
// timmy_comment,
|
||||
// sara_comment,
|
||||
// sara_comment_2,
|
||||
// })
|
||||
// }
|
||||
|
||||
// async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
|
||||
// Instance::delete(pool, data.instance.id).await?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// #[tokio::test]
|
||||
// #[serial]
|
||||
// async fn test_combined() -> LemmyResult<()> {
|
||||
// let pool = &build_db_pool_for_tests();
|
||||
// let pool = &mut pool.into();
|
||||
// let data = init_data(pool).await?;
|
||||
|
||||
// // Do a batch read of timmy
|
||||
// let timmy_content = InboxCombinedQuery::new(data.timmy.id)
|
||||
// .list(pool, &None)
|
||||
// .await?;
|
||||
// assert_eq!(3, timmy_content.len());
|
||||
|
||||
// // Make sure the types are correct
|
||||
// if let InboxCombinedView::Comment(v) = &timmy_content[0] {
|
||||
// assert_eq!(data.timmy_comment.id, v.comment.id);
|
||||
// assert_eq!(data.timmy.id, v.creator.id);
|
||||
// } else {
|
||||
// panic!("wrong type");
|
||||
// }
|
||||
// if let InboxCombinedView::Post(v) = &timmy_content[1] {
|
||||
// assert_eq!(data.timmy_post_2.id, v.post.id);
|
||||
// assert_eq!(data.timmy.id, v.post.creator_id);
|
||||
// } else {
|
||||
// panic!("wrong type");
|
||||
// }
|
||||
// if let InboxCombinedView::Post(v) = &timmy_content[2] {
|
||||
// assert_eq!(data.timmy_post.id, v.post.id);
|
||||
// assert_eq!(data.timmy.id, v.post.creator_id);
|
||||
// } else {
|
||||
// panic!("wrong type");
|
||||
// }
|
||||
|
||||
// // Do a batch read of sara
|
||||
// let sara_content = InboxCombinedQuery::new(data.sara.id)
|
||||
// .list(pool, &None)
|
||||
// .await?;
|
||||
// assert_eq!(3, sara_content.len());
|
||||
|
||||
// // Make sure the report types are correct
|
||||
// if let InboxCombinedView::Comment(v) = &sara_content[0] {
|
||||
// assert_eq!(data.sara_comment_2.id, v.comment.id);
|
||||
// assert_eq!(data.sara.id, v.creator.id);
|
||||
// // This one was to timmy_post_2
|
||||
// assert_eq!(data.timmy_post_2.id, v.post.id);
|
||||
// assert_eq!(data.timmy.id, v.post.creator_id);
|
||||
// } else {
|
||||
// panic!("wrong type");
|
||||
// }
|
||||
// if let InboxCombinedView::Comment(v) = &sara_content[1] {
|
||||
// assert_eq!(data.sara_comment.id, v.comment.id);
|
||||
// assert_eq!(data.sara.id, v.creator.id);
|
||||
// assert_eq!(data.timmy_post.id, v.post.id);
|
||||
// assert_eq!(data.timmy.id, v.post.creator_id);
|
||||
// } else {
|
||||
// panic!("wrong type");
|
||||
// }
|
||||
// if let InboxCombinedView::Post(v) = &sara_content[2] {
|
||||
// assert_eq!(data.sara_post.id, v.post.id);
|
||||
// assert_eq!(data.sara.id, v.post.creator_id);
|
||||
// } else {
|
||||
// panic!("wrong type");
|
||||
// }
|
||||
|
||||
// cleanup(data, pool).await?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
|
||||
//
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
|
||||
// use crate::{
|
||||
// person_comment_mention_view::PersonCommentMentionQuery,
|
||||
// structs::PersonCommentMentionView,
|
||||
// };
|
||||
// use lemmy_db_schema::{
|
||||
// source::{
|
||||
// comment::{Comment, CommentInsertForm},
|
||||
// community::{Community, CommunityInsertForm},
|
||||
// instance::Instance,
|
||||
// local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
|
||||
// person::{Person, PersonInsertForm, PersonUpdateForm},
|
||||
// person_block::{PersonBlock, PersonBlockForm},
|
||||
// person_comment_mention::{
|
||||
// PersonCommentMention,
|
||||
// PersonCommentMentionInsertForm,
|
||||
// PersonCommentMentionUpdateForm,
|
||||
// },
|
||||
// post::{Post, PostInsertForm},
|
||||
// },
|
||||
// traits::{Blockable, Crud},
|
||||
// utils::build_db_pool_for_tests,
|
||||
// };
|
||||
// use lemmy_db_views::structs::LocalUserView;
|
||||
// use lemmy_utils::error::LemmyResult;
|
||||
// use pretty_assertions::assert_eq;
|
||||
// use serial_test::serial;
|
||||
|
||||
// #[tokio::test]
|
||||
// #[serial]
|
||||
// async fn test_crud() -> LemmyResult<()> {
|
||||
// let pool = &build_db_pool_for_tests();
|
||||
// let pool = &mut pool.into();
|
||||
|
||||
// let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||
|
||||
// let new_person = PersonInsertForm::test_form(inserted_instance.id, "terrylake");
|
||||
|
||||
// let inserted_person = Person::create(pool, &new_person).await?;
|
||||
|
||||
// let recipient_form = PersonInsertForm::test_form(inserted_instance.id, "terrylakes
|
||||
// recipient");
|
||||
|
||||
// let inserted_recipient = Person::create(pool, &recipient_form).await?;
|
||||
// let recipient_id = inserted_recipient.id;
|
||||
|
||||
// let recipient_local_user =
|
||||
// LocalUser::create(pool, &LocalUserInsertForm::test_form(recipient_id), vec![]).await?;
|
||||
|
||||
// let new_community = CommunityInsertForm::new(
|
||||
// inserted_instance.id,
|
||||
// "test community lake".to_string(),
|
||||
// "nada".to_owned(),
|
||||
// "pubkey".to_string(),
|
||||
// );
|
||||
// let inserted_community = Community::create(pool, &new_community).await?;
|
||||
|
||||
// let new_post = PostInsertForm::new(
|
||||
// "A test post".into(),
|
||||
// inserted_person.id,
|
||||
// inserted_community.id,
|
||||
// );
|
||||
// let inserted_post = Post::create(pool, &new_post).await?;
|
||||
|
||||
// let comment_form = CommentInsertForm::new(
|
||||
// inserted_person.id,
|
||||
// inserted_post.id,
|
||||
// "A test comment".into(),
|
||||
// );
|
||||
// let inserted_comment = Comment::create(pool, &comment_form, None).await?;
|
||||
|
||||
// let person_comment_mention_form = PersonCommentMentionInsertForm {
|
||||
// recipient_id: inserted_recipient.id,
|
||||
// comment_id: inserted_comment.id,
|
||||
// read: None,
|
||||
// };
|
||||
|
||||
// let inserted_mention = PersonCommentMention::create(pool,
|
||||
// &person_comment_mention_form).await?;
|
||||
|
||||
// let expected_mention = PersonCommentMention {
|
||||
// id: inserted_mention.id,
|
||||
// recipient_id: inserted_mention.recipient_id,
|
||||
// comment_id: inserted_mention.comment_id,
|
||||
// read: false,
|
||||
// published: inserted_mention.published,
|
||||
// };
|
||||
|
||||
// let read_mention = PersonCommentMention::read(pool, inserted_mention.id).await?;
|
||||
|
||||
// let person_comment_mention_update_form = PersonCommentMentionUpdateForm { read: Some(false)
|
||||
// }; let updated_mention = PersonCommentMention::update(
|
||||
// pool,
|
||||
// inserted_mention.id,
|
||||
// &person_comment_mention_update_form,
|
||||
// )
|
||||
// .await?;
|
||||
|
||||
// // Test to make sure counts and blocks work correctly
|
||||
// let unread_mentions =
|
||||
// PersonCommentMentionView::get_unread_count(pool, &recipient_local_user).await?;
|
||||
|
||||
// let query = PersonCommentMentionQuery {
|
||||
// recipient_id: Some(recipient_id),
|
||||
// my_person_id: Some(recipient_id),
|
||||
// sort: None,
|
||||
// unread_only: false,
|
||||
// show_bot_accounts: true,
|
||||
// page: None,
|
||||
// limit: None,
|
||||
// };
|
||||
// let mentions = query.clone().list(pool).await?;
|
||||
// assert_eq!(1, unread_mentions);
|
||||
// assert_eq!(1, mentions.len());
|
||||
|
||||
// // Block the person, and make sure these counts are now empty
|
||||
// let block_form = PersonBlockForm {
|
||||
// person_id: recipient_id,
|
||||
// target_id: inserted_person.id,
|
||||
// };
|
||||
// PersonBlock::block(pool, &block_form).await?;
|
||||
|
||||
// let unread_mentions_after_block =
|
||||
// PersonCommentMentionView::get_unread_count(pool, &recipient_local_user).await?;
|
||||
// let mentions_after_block = query.clone().list(pool).await?;
|
||||
// assert_eq!(0, unread_mentions_after_block);
|
||||
// assert_eq!(0, mentions_after_block.len());
|
||||
|
||||
// // Unblock user so we can reuse the same person
|
||||
// PersonBlock::unblock(pool, &block_form).await?;
|
||||
|
||||
// // Turn Terry into a bot account
|
||||
// let person_update_form = PersonUpdateForm {
|
||||
// bot_account: Some(true),
|
||||
// ..Default::default()
|
||||
// };
|
||||
// Person::update(pool, inserted_person.id, &person_update_form).await?;
|
||||
|
||||
// let recipient_local_user_update_form = LocalUserUpdateForm {
|
||||
// show_bot_accounts: Some(false),
|
||||
// ..Default::default()
|
||||
// };
|
||||
// LocalUser::update(
|
||||
// pool,
|
||||
// recipient_local_user.id,
|
||||
// &recipient_local_user_update_form,
|
||||
// )
|
||||
// .await?;
|
||||
// let recipient_local_user_view = LocalUserView::read(pool, recipient_local_user.id).await?;
|
||||
|
||||
// let unread_mentions_after_hide_bots =
|
||||
// PersonCommentMentionView::get_unread_count(pool, &recipient_local_user_view.local_user)
|
||||
// .await?;
|
||||
|
||||
// let mut query_without_bots = query.clone();
|
||||
// query_without_bots.show_bot_accounts = false;
|
||||
// let replies_after_hide_bots = query_without_bots.list(pool).await?;
|
||||
// assert_eq!(0, unread_mentions_after_hide_bots);
|
||||
// assert_eq!(0, replies_after_hide_bots.len());
|
||||
|
||||
// Comment::delete(pool, inserted_comment.id).await?;
|
||||
// Post::delete(pool, inserted_post.id).await?;
|
||||
// Community::delete(pool, inserted_community.id).await?;
|
||||
// Person::delete(pool, inserted_person.id).await?;
|
||||
// Person::delete(pool, inserted_recipient.id).await?;
|
||||
// Instance::delete(pool, inserted_instance.id).await?;
|
||||
|
||||
// assert_eq!(expected_mention, read_mention);
|
||||
// assert_eq!(expected_mention, inserted_mention);
|
||||
// assert_eq!(expected_mention, updated_mention);
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
|
||||
// use crate::{person_post_mention_view::PersonPostMentionQuery, structs::PersonPostMentionView};
|
||||
// use lemmy_db_schema::{
|
||||
// source::{
|
||||
// community::{Community, CommunityInsertForm},
|
||||
// instance::Instance,
|
||||
// local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
|
||||
// person::{Person, PersonInsertForm, PersonUpdateForm},
|
||||
// person_block::{PersonBlock, PersonBlockForm},
|
||||
// person_post_mention::{
|
||||
// PersonPostMention,
|
||||
// PersonPostMentionInsertForm,
|
||||
// PersonPostMentionUpdateForm,
|
||||
// },
|
||||
// post::{Post, PostInsertForm},
|
||||
// },
|
||||
// traits::{Blockable, Crud},
|
||||
// utils::build_db_pool_for_tests,
|
||||
// };
|
||||
// use lemmy_db_views::structs::LocalUserView;
|
||||
// use lemmy_utils::error::LemmyResult;
|
||||
// use pretty_assertions::assert_eq;
|
||||
// use serial_test::serial;
|
||||
|
||||
// #[tokio::test]
|
||||
// #[serial]
|
||||
// async fn test_crud() -> LemmyResult<()> {
|
||||
// let pool = &build_db_pool_for_tests().await;
|
||||
// let pool = &mut pool.into();
|
||||
|
||||
// let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||
|
||||
// let new_person = PersonInsertForm::test_form(inserted_instance.id, "terrylake");
|
||||
|
||||
// let inserted_person = Person::create(pool, &new_person).await?;
|
||||
|
||||
// let recipient_form = PersonInsertForm::test_form(inserted_instance.id, "terrylakes
|
||||
// recipient");
|
||||
|
||||
// let inserted_recipient = Person::create(pool, &recipient_form).await?;
|
||||
// let recipient_id = inserted_recipient.id;
|
||||
|
||||
// let recipient_local_user =
|
||||
// LocalUser::create(pool, &LocalUserInsertForm::test_form(recipient_id), vec![]).await?;
|
||||
|
||||
// let new_community = CommunityInsertForm::new(
|
||||
// inserted_instance.id,
|
||||
// "test community lake".to_string(),
|
||||
// "nada".to_owned(),
|
||||
// "pubkey".to_string(),
|
||||
// );
|
||||
// let inserted_community = Community::create(pool, &new_community).await?;
|
||||
|
||||
// let new_post = PostInsertForm::new(
|
||||
// "A test post".into(),
|
||||
// inserted_person.id,
|
||||
// inserted_community.id,
|
||||
// );
|
||||
// let inserted_post = Post::create(pool, &new_post).await?;
|
||||
|
||||
// let person_post_mention_form = PersonPostMentionInsertForm {
|
||||
// recipient_id: inserted_recipient.id,
|
||||
// post_id: inserted_post.id,
|
||||
// read: None,
|
||||
// };
|
||||
|
||||
// let inserted_mention = PersonPostMention::create(pool, &person_post_mention_form).await?;
|
||||
|
||||
// let expected_mention = PersonPostMention {
|
||||
// id: inserted_mention.id,
|
||||
// recipient_id: inserted_mention.recipient_id,
|
||||
// post_id: inserted_mention.post_id,
|
||||
// read: false,
|
||||
// published: inserted_mention.published,
|
||||
// };
|
||||
|
||||
// let read_mention = PersonPostMention::read(pool, inserted_mention.id).await?;
|
||||
|
||||
// let person_post_mention_update_form = PersonPostMentionUpdateForm { read: Some(false) };
|
||||
// let updated_mention =
|
||||
// PersonPostMention::update(pool, inserted_mention.id, &person_post_mention_update_form)
|
||||
// .await?;
|
||||
|
||||
// // Test to make sure counts and blocks work correctly
|
||||
// let unread_mentions =
|
||||
// PersonPostMentionView::get_unread_count(pool, &recipient_local_user).await?;
|
||||
|
||||
// let query = PersonPostMentionQuery {
|
||||
// recipient_id: Some(recipient_id),
|
||||
// my_person_id: Some(recipient_id),
|
||||
// sort: None,
|
||||
// unread_only: false,
|
||||
// show_bot_accounts: true,
|
||||
// page: None,
|
||||
// limit: None,
|
||||
// };
|
||||
// let mentions = query.clone().list(pool).await?;
|
||||
// assert_eq!(1, unread_mentions);
|
||||
// assert_eq!(1, mentions.len());
|
||||
|
||||
// // Block the person, and make sure these counts are now empty
|
||||
// let block_form = PersonBlockForm {
|
||||
// person_id: recipient_id,
|
||||
// target_id: inserted_person.id,
|
||||
// };
|
||||
// PersonBlock::block(pool, &block_form).await?;
|
||||
|
||||
// let unread_mentions_after_block =
|
||||
// PersonPostMentionView::get_unread_count(pool, &recipient_local_user).await?;
|
||||
// let mentions_after_block = query.clone().list(pool).await?;
|
||||
// assert_eq!(0, unread_mentions_after_block);
|
||||
// assert_eq!(0, mentions_after_block.len());
|
||||
|
||||
// // Unblock user so we can reuse the same person
|
||||
// PersonBlock::unblock(pool, &block_form).await?;
|
||||
|
||||
// // Turn Terry into a bot account
|
||||
// let person_update_form = PersonUpdateForm {
|
||||
// bot_account: Some(true),
|
||||
// ..Default::default()
|
||||
// };
|
||||
// Person::update(pool, inserted_person.id, &person_update_form).await?;
|
||||
|
||||
// let recipient_local_user_update_form = LocalUserUpdateForm {
|
||||
// show_bot_accounts: Some(false),
|
||||
// ..Default::default()
|
||||
// };
|
||||
// LocalUser::update(
|
||||
// pool,
|
||||
// recipient_local_user.id,
|
||||
// &recipient_local_user_update_form,
|
||||
// )
|
||||
// .await?;
|
||||
// let recipient_local_user_view = LocalUserView::read(pool, recipient_local_user.id).await?;
|
||||
|
||||
// let unread_mentions_after_hide_bots =
|
||||
// PersonPostMentionView::get_unread_count(pool,
|
||||
// &recipient_local_user_view.local_user).await?;
|
||||
|
||||
// let mut query_without_bots = query.clone();
|
||||
// query_without_bots.show_bot_accounts = false;
|
||||
// let replies_after_hide_bots = query_without_bots.list(pool).await?;
|
||||
// assert_eq!(0, unread_mentions_after_hide_bots);
|
||||
// assert_eq!(0, replies_after_hide_bots.len());
|
||||
|
||||
// Post::delete(pool, inserted_post.id).await?;
|
||||
// Post::delete(pool, inserted_post.id).await?;
|
||||
// Community::delete(pool, inserted_community.id).await?;
|
||||
// Person::delete(pool, inserted_person.id).await?;
|
||||
// Person::delete(pool, inserted_recipient.id).await?;
|
||||
// Instance::delete(pool, inserted_instance.id).await?;
|
||||
|
||||
// assert_eq!(expected_mention, read_mention);
|
||||
// assert_eq!(expected_mention, inserted_mention);
|
||||
// assert_eq!(expected_mention, updated_mention);
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
|
@ -9,7 +9,13 @@ pub mod community_person_ban_view;
|
|||
#[cfg(feature = "full")]
|
||||
pub mod community_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod inbox_combined_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod person_comment_mention_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod person_post_mention_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod person_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod private_message_view;
|
||||
pub mod structs;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::structs::PersonCommentMentionView;
|
||||
use diesel::{
|
||||
dsl::{exists, not},
|
||||
pg::Pg,
|
||||
result::Error,
|
||||
BoolExpressionMethods,
|
||||
ExpressionMethods,
|
||||
|
@ -26,24 +25,17 @@ use lemmy_db_schema::{
|
|||
post,
|
||||
},
|
||||
source::{community::CommunityFollower, local_user::LocalUser},
|
||||
utils::{
|
||||
actions,
|
||||
actions_alias,
|
||||
get_conn,
|
||||
limit_and_offset,
|
||||
DbConn,
|
||||
DbPool,
|
||||
ListFn,
|
||||
Queries,
|
||||
ReadFn,
|
||||
},
|
||||
CommentSortType,
|
||||
utils::{actions, actions_alias, get_conn, DbPool},
|
||||
};
|
||||
|
||||
fn queries<'a>() -> Queries<
|
||||
impl ReadFn<'a, PersonCommentMentionView, (PersonCommentMentionId, Option<PersonId>)>,
|
||||
impl ListFn<'a, PersonCommentMentionView, PersonCommentMentionQuery>,
|
||||
> {
|
||||
impl PersonCommentMentionView {
|
||||
pub async fn read(
|
||||
pool: &mut DbPool<'_>,
|
||||
person_comment_mention_id: PersonCommentMentionId,
|
||||
my_person_id: Option<PersonId>,
|
||||
) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
|
||||
let creator_is_admin = exists(
|
||||
local_user::table.filter(
|
||||
comment::creator_id
|
||||
|
@ -52,9 +44,8 @@ fn queries<'a>() -> Queries<
|
|||
),
|
||||
);
|
||||
|
||||
let all_joins = move |query: person_comment_mention::BoxedQuery<'a, Pg>,
|
||||
my_person_id: Option<PersonId>| {
|
||||
query
|
||||
person_comment_mention::table
|
||||
.find(person_comment_mention_id)
|
||||
.inner_join(comment::table)
|
||||
.inner_join(person::table.on(comment::creator_id.eq(person::id)))
|
||||
.inner_join(post::table.on(comment::post_id.eq(post::id)))
|
||||
|
@ -100,80 +91,12 @@ fn queries<'a>() -> Queries<
|
|||
person_actions::blocked.nullable().is_not_null(),
|
||||
comment_actions::like_score.nullable(),
|
||||
))
|
||||
};
|
||||
|
||||
let read = move |mut conn: DbConn<'a>,
|
||||
(person_comment_mention_id, my_person_id): (
|
||||
PersonCommentMentionId,
|
||||
Option<PersonId>,
|
||||
)| async move {
|
||||
all_joins(
|
||||
person_comment_mention::table
|
||||
.find(person_comment_mention_id)
|
||||
.into_boxed(),
|
||||
my_person_id,
|
||||
)
|
||||
.first(&mut conn)
|
||||
.await
|
||||
};
|
||||
|
||||
let list = move |mut conn: DbConn<'a>, options: PersonCommentMentionQuery| async move {
|
||||
// These filters need to be kept in sync with the filters in
|
||||
// PersonCommentMentionView::get_unread_mentions()
|
||||
let mut query = all_joins(
|
||||
person_comment_mention::table.into_boxed(),
|
||||
options.my_person_id,
|
||||
);
|
||||
|
||||
if let Some(recipient_id) = options.recipient_id {
|
||||
query = query.filter(person_comment_mention::recipient_id.eq(recipient_id));
|
||||
}
|
||||
|
||||
if options.unread_only {
|
||||
query = query.filter(person_comment_mention::read.eq(false));
|
||||
}
|
||||
|
||||
if !options.show_bot_accounts {
|
||||
query = query.filter(not(person::bot_account));
|
||||
};
|
||||
|
||||
query = match options.sort.unwrap_or(CommentSortType::New) {
|
||||
CommentSortType::Hot => query.then_order_by(comment_aggregates::hot_rank.desc()),
|
||||
CommentSortType::Controversial => {
|
||||
query.then_order_by(comment_aggregates::controversy_rank.desc())
|
||||
}
|
||||
CommentSortType::New => query.then_order_by(comment::published.desc()),
|
||||
CommentSortType::Old => query.then_order_by(comment::published.asc()),
|
||||
CommentSortType::Top => query.order_by(comment_aggregates::score.desc()),
|
||||
};
|
||||
|
||||
// Don't show mentions from blocked persons
|
||||
query = query.filter(person_actions::blocked.is_null());
|
||||
|
||||
let (limit, offset) = limit_and_offset(options.page, options.limit)?;
|
||||
|
||||
query
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.load::<PersonCommentMentionView>(&mut conn)
|
||||
.await
|
||||
};
|
||||
|
||||
Queries::new(read, list)
|
||||
}
|
||||
|
||||
impl PersonCommentMentionView {
|
||||
pub async fn read(
|
||||
pool: &mut DbPool<'_>,
|
||||
person_comment_mention_id: PersonCommentMentionId,
|
||||
my_person_id: Option<PersonId>,
|
||||
) -> Result<Self, Error> {
|
||||
queries()
|
||||
.read(pool, (person_comment_mention_id, my_person_id))
|
||||
.first(conn)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Gets the number of unread mentions
|
||||
// TODO get rid of this
|
||||
pub async fn get_unread_count(
|
||||
pool: &mut DbPool<'_>,
|
||||
local_user: &LocalUser,
|
||||
|
@ -208,195 +131,3 @@ impl PersonCommentMentionView {
|
|||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct PersonCommentMentionQuery {
|
||||
pub my_person_id: Option<PersonId>,
|
||||
pub recipient_id: Option<PersonId>,
|
||||
pub sort: Option<CommentSortType>,
|
||||
pub unread_only: bool,
|
||||
pub show_bot_accounts: bool,
|
||||
pub page: Option<i64>,
|
||||
pub limit: Option<i64>,
|
||||
}
|
||||
|
||||
impl PersonCommentMentionQuery {
|
||||
pub async fn list(self, pool: &mut DbPool<'_>) -> Result<Vec<PersonCommentMentionView>, Error> {
|
||||
queries().list(pool, self).await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
person_comment_mention_view::PersonCommentMentionQuery,
|
||||
structs::PersonCommentMentionView,
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
comment::{Comment, CommentInsertForm},
|
||||
community::{Community, CommunityInsertForm},
|
||||
instance::Instance,
|
||||
local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
|
||||
person::{Person, PersonInsertForm, PersonUpdateForm},
|
||||
person_block::{PersonBlock, PersonBlockForm},
|
||||
person_comment_mention::{
|
||||
PersonCommentMention,
|
||||
PersonCommentMentionInsertForm,
|
||||
PersonCommentMentionUpdateForm,
|
||||
},
|
||||
post::{Post, PostInsertForm},
|
||||
},
|
||||
traits::{Blockable, Crud},
|
||||
utils::build_db_pool_for_tests,
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serial_test::serial;
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_crud() -> LemmyResult<()> {
|
||||
let pool = &build_db_pool_for_tests();
|
||||
let pool = &mut pool.into();
|
||||
|
||||
let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||
|
||||
let new_person = PersonInsertForm::test_form(inserted_instance.id, "terrylake");
|
||||
|
||||
let inserted_person = Person::create(pool, &new_person).await?;
|
||||
|
||||
let recipient_form = PersonInsertForm::test_form(inserted_instance.id, "terrylakes recipient");
|
||||
|
||||
let inserted_recipient = Person::create(pool, &recipient_form).await?;
|
||||
let recipient_id = inserted_recipient.id;
|
||||
|
||||
let recipient_local_user =
|
||||
LocalUser::create(pool, &LocalUserInsertForm::test_form(recipient_id), vec![]).await?;
|
||||
|
||||
let new_community = CommunityInsertForm::new(
|
||||
inserted_instance.id,
|
||||
"test community lake".to_string(),
|
||||
"nada".to_owned(),
|
||||
"pubkey".to_string(),
|
||||
);
|
||||
let inserted_community = Community::create(pool, &new_community).await?;
|
||||
|
||||
let new_post = PostInsertForm::new(
|
||||
"A test post".into(),
|
||||
inserted_person.id,
|
||||
inserted_community.id,
|
||||
);
|
||||
let inserted_post = Post::create(pool, &new_post).await?;
|
||||
|
||||
let comment_form = CommentInsertForm::new(
|
||||
inserted_person.id,
|
||||
inserted_post.id,
|
||||
"A test comment".into(),
|
||||
);
|
||||
let inserted_comment = Comment::create(pool, &comment_form, None).await?;
|
||||
|
||||
let person_comment_mention_form = PersonCommentMentionInsertForm {
|
||||
recipient_id: inserted_recipient.id,
|
||||
comment_id: inserted_comment.id,
|
||||
read: None,
|
||||
};
|
||||
|
||||
let inserted_mention = PersonCommentMention::create(pool, &person_comment_mention_form).await?;
|
||||
|
||||
let expected_mention = PersonCommentMention {
|
||||
id: inserted_mention.id,
|
||||
recipient_id: inserted_mention.recipient_id,
|
||||
comment_id: inserted_mention.comment_id,
|
||||
read: false,
|
||||
published: inserted_mention.published,
|
||||
};
|
||||
|
||||
let read_mention = PersonCommentMention::read(pool, inserted_mention.id).await?;
|
||||
|
||||
let person_comment_mention_update_form = PersonCommentMentionUpdateForm { read: Some(false) };
|
||||
let updated_mention = PersonCommentMention::update(
|
||||
pool,
|
||||
inserted_mention.id,
|
||||
&person_comment_mention_update_form,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Test to make sure counts and blocks work correctly
|
||||
let unread_mentions =
|
||||
PersonCommentMentionView::get_unread_count(pool, &recipient_local_user).await?;
|
||||
|
||||
let query = PersonCommentMentionQuery {
|
||||
recipient_id: Some(recipient_id),
|
||||
my_person_id: Some(recipient_id),
|
||||
sort: None,
|
||||
unread_only: false,
|
||||
show_bot_accounts: true,
|
||||
page: None,
|
||||
limit: None,
|
||||
};
|
||||
let mentions = query.clone().list(pool).await?;
|
||||
assert_eq!(1, unread_mentions);
|
||||
assert_eq!(1, mentions.len());
|
||||
|
||||
// Block the person, and make sure these counts are now empty
|
||||
let block_form = PersonBlockForm {
|
||||
person_id: recipient_id,
|
||||
target_id: inserted_person.id,
|
||||
};
|
||||
PersonBlock::block(pool, &block_form).await?;
|
||||
|
||||
let unread_mentions_after_block =
|
||||
PersonCommentMentionView::get_unread_count(pool, &recipient_local_user).await?;
|
||||
let mentions_after_block = query.clone().list(pool).await?;
|
||||
assert_eq!(0, unread_mentions_after_block);
|
||||
assert_eq!(0, mentions_after_block.len());
|
||||
|
||||
// Unblock user so we can reuse the same person
|
||||
PersonBlock::unblock(pool, &block_form).await?;
|
||||
|
||||
// Turn Terry into a bot account
|
||||
let person_update_form = PersonUpdateForm {
|
||||
bot_account: Some(true),
|
||||
..Default::default()
|
||||
};
|
||||
Person::update(pool, inserted_person.id, &person_update_form).await?;
|
||||
|
||||
let recipient_local_user_update_form = LocalUserUpdateForm {
|
||||
show_bot_accounts: Some(false),
|
||||
..Default::default()
|
||||
};
|
||||
LocalUser::update(
|
||||
pool,
|
||||
recipient_local_user.id,
|
||||
&recipient_local_user_update_form,
|
||||
)
|
||||
.await?;
|
||||
let recipient_local_user_view = LocalUserView::read(pool, recipient_local_user.id).await?;
|
||||
|
||||
let unread_mentions_after_hide_bots =
|
||||
PersonCommentMentionView::get_unread_count(pool, &recipient_local_user_view.local_user)
|
||||
.await?;
|
||||
|
||||
let mut query_without_bots = query.clone();
|
||||
query_without_bots.show_bot_accounts = false;
|
||||
let replies_after_hide_bots = query_without_bots.list(pool).await?;
|
||||
assert_eq!(0, unread_mentions_after_hide_bots);
|
||||
assert_eq!(0, replies_after_hide_bots.len());
|
||||
|
||||
Comment::delete(pool, inserted_comment.id).await?;
|
||||
Post::delete(pool, inserted_post.id).await?;
|
||||
Community::delete(pool, inserted_community.id).await?;
|
||||
Person::delete(pool, inserted_person.id).await?;
|
||||
Person::delete(pool, inserted_recipient.id).await?;
|
||||
Instance::delete(pool, inserted_instance.id).await?;
|
||||
|
||||
assert_eq!(expected_mention, read_mention);
|
||||
assert_eq!(expected_mention, inserted_mention);
|
||||
assert_eq!(expected_mention, updated_mention);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
103
crates/db_views_actor/src/person_post_mention_view.rs
Normal file
103
crates/db_views_actor/src/person_post_mention_view.rs
Normal file
|
@ -0,0 +1,103 @@
|
|||
use crate::structs::PersonPostMentionView;
|
||||
use diesel::{
|
||||
dsl::exists,
|
||||
result::Error,
|
||||
BoolExpressionMethods,
|
||||
ExpressionMethods,
|
||||
JoinOnDsl,
|
||||
NullableExpressionMethods,
|
||||
QueryDsl,
|
||||
};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_db_schema::{
|
||||
aliases::{self, creator_community_actions},
|
||||
newtypes::{PersonId, PersonPostMentionId},
|
||||
schema::{
|
||||
community,
|
||||
community_actions,
|
||||
image_details,
|
||||
local_user,
|
||||
person,
|
||||
person_actions,
|
||||
person_post_mention,
|
||||
post,
|
||||
post_actions,
|
||||
post_aggregates,
|
||||
},
|
||||
source::community::CommunityFollower,
|
||||
utils::{actions, actions_alias, functions::coalesce, get_conn, DbPool},
|
||||
};
|
||||
|
||||
impl PersonPostMentionView {
|
||||
pub async fn read(
|
||||
pool: &mut DbPool<'_>,
|
||||
person_post_mention_id: PersonPostMentionId,
|
||||
my_person_id: Option<PersonId>,
|
||||
) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
|
||||
let creator_is_admin = exists(
|
||||
local_user::table.filter(
|
||||
post::creator_id
|
||||
.eq(local_user::person_id)
|
||||
.and(local_user::admin.eq(true)),
|
||||
),
|
||||
);
|
||||
|
||||
person_post_mention::table
|
||||
.find(person_post_mention_id)
|
||||
.inner_join(post::table)
|
||||
.inner_join(person::table.on(post::creator_id.eq(person::id)))
|
||||
.inner_join(community::table.on(post::community_id.eq(community::id)))
|
||||
.inner_join(aliases::person1)
|
||||
.inner_join(post_aggregates::table.on(post::id.eq(post_aggregates::post_id)))
|
||||
.left_join(image_details::table.on(post::thumbnail_url.eq(image_details::link.nullable())))
|
||||
.left_join(actions(
|
||||
community_actions::table,
|
||||
my_person_id,
|
||||
post::community_id,
|
||||
))
|
||||
.left_join(actions(post_actions::table, my_person_id, post::id))
|
||||
.left_join(actions(
|
||||
person_actions::table,
|
||||
my_person_id,
|
||||
post::creator_id,
|
||||
))
|
||||
.left_join(actions_alias(
|
||||
creator_community_actions,
|
||||
post::creator_id,
|
||||
post::community_id,
|
||||
))
|
||||
.select((
|
||||
person_post_mention::all_columns,
|
||||
post::all_columns,
|
||||
person::all_columns,
|
||||
community::all_columns,
|
||||
image_details::all_columns.nullable(),
|
||||
aliases::person1.fields(person::all_columns),
|
||||
post_aggregates::all_columns,
|
||||
creator_community_actions
|
||||
.field(community_actions::received_ban)
|
||||
.nullable()
|
||||
.is_not_null(),
|
||||
community_actions::received_ban.nullable().is_not_null(),
|
||||
creator_community_actions
|
||||
.field(community_actions::became_moderator)
|
||||
.nullable()
|
||||
.is_not_null(),
|
||||
creator_is_admin,
|
||||
CommunityFollower::select_subscribed_type(),
|
||||
post_actions::saved.nullable().is_not_null(),
|
||||
post_actions::read.nullable().is_not_null(),
|
||||
post_actions::hidden.nullable().is_not_null(),
|
||||
person_actions::blocked.nullable().is_not_null(),
|
||||
post_actions::like_score.nullable(),
|
||||
coalesce(
|
||||
post_aggregates::comments.nullable() - post_actions::read_comments_amount.nullable(),
|
||||
post_aggregates::comments,
|
||||
),
|
||||
))
|
||||
.first(conn)
|
||||
.await
|
||||
}
|
||||
}
|
|
@ -6,10 +6,12 @@ use lemmy_db_schema::{
|
|||
comment::Comment,
|
||||
comment_reply::CommentReply,
|
||||
community::Community,
|
||||
images::ImageDetails,
|
||||
person::Person,
|
||||
person_comment_mention::PersonCommentMention,
|
||||
person_post_mention::PersonPostMention,
|
||||
post::Post,
|
||||
private_message::PrivateMessage,
|
||||
},
|
||||
SubscribedType,
|
||||
};
|
||||
|
@ -125,6 +127,8 @@ pub struct PersonPostMentionView {
|
|||
pub post: Post,
|
||||
pub creator: Person,
|
||||
pub community: Community,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub image_details: Option<ImageDetails>,
|
||||
pub recipient: Person,
|
||||
pub counts: PostAggregates,
|
||||
pub creator_banned_from_community: bool,
|
||||
|
@ -133,8 +137,12 @@ pub struct PersonPostMentionView {
|
|||
pub creator_is_admin: bool,
|
||||
pub subscribed: SubscribedType,
|
||||
pub saved: bool,
|
||||
pub read: bool,
|
||||
pub hidden: bool,
|
||||
pub creator_blocked: bool,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub my_vote: Option<i16>,
|
||||
pub unread_comments: i64,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
|
@ -183,3 +191,69 @@ pub struct PendingFollow {
|
|||
pub is_new_instance: bool,
|
||||
pub subscribed: SubscribedType,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A private message view.
|
||||
pub struct PrivateMessageView {
|
||||
pub private_message: PrivateMessage,
|
||||
pub creator: Person,
|
||||
pub recipient: Person,
|
||||
}
|
||||
|
||||
/// like PaginationCursor but for the report_combined table
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
pub struct InboxCombinedPaginationCursor(pub String);
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(Queryable))]
|
||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||
/// A combined inbox view
|
||||
pub struct InboxCombinedViewInternal {
|
||||
// Comment reply
|
||||
pub comment_reply: Option<CommentReply>,
|
||||
// Person comment mention
|
||||
pub person_comment_mention: Option<PersonCommentMention>,
|
||||
// Person post mention
|
||||
pub person_post_mention: Option<PersonPostMention>,
|
||||
pub post_counts: Option<PostAggregates>,
|
||||
pub post_unread_comments: Option<i64>,
|
||||
pub post_saved: bool,
|
||||
pub post_read: bool,
|
||||
pub post_hidden: bool,
|
||||
pub my_post_vote: Option<i16>,
|
||||
pub image_details: Option<ImageDetails>,
|
||||
// Private message
|
||||
pub private_message: Option<PrivateMessage>,
|
||||
// Shared
|
||||
pub post: Option<Post>,
|
||||
pub community: Option<Community>,
|
||||
pub comment: Option<Comment>,
|
||||
pub comment_counts: Option<CommentAggregates>,
|
||||
pub comment_saved: bool,
|
||||
pub my_comment_vote: Option<i16>,
|
||||
pub subscribed: SubscribedType,
|
||||
pub item_creator: Person,
|
||||
pub item_recipient: Person,
|
||||
pub item_creator_is_admin: bool,
|
||||
pub item_creator_is_moderator: bool,
|
||||
pub item_creator_banned_from_community: bool,
|
||||
pub item_creator_blocked: bool,
|
||||
pub banned_from_community: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
// Use serde's internal tagging, to work easier with javascript libraries
|
||||
#[serde(tag = "type_")]
|
||||
pub enum InboxCombinedView {
|
||||
CommentReply(CommentReplyView),
|
||||
CommentMention(PersonCommentMentionView),
|
||||
PostMention(PersonPostMentionView),
|
||||
PrivateMessage(PrivateMessageView),
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ use lemmy_api_common::{context::LemmyContext, utils::check_private_instance};
|
|||
use lemmy_db_schema::{
|
||||
source::{community::Community, person::Person},
|
||||
traits::ApubActor,
|
||||
CommentSortType,
|
||||
CommunityVisibility,
|
||||
ListingType,
|
||||
PostSortType,
|
||||
|
@ -15,12 +14,7 @@ use lemmy_db_views::{
|
|||
post_view::PostQuery,
|
||||
structs::{PostView, SiteView},
|
||||
};
|
||||
use lemmy_db_views_actor::{
|
||||
comment_reply_view::CommentReplyQuery,
|
||||
person_comment_mention_view::PersonCommentMentionQuery,
|
||||
person_post_mention_view::PersonPostMentionQuery,
|
||||
structs::{CommentReplyView, PersonCommentMentionView, PersonPostMentionView},
|
||||
};
|
||||
use lemmy_db_views_actor::{inbox_combined_view::InboxCombinedQuery, structs::InboxCombinedView};
|
||||
use lemmy_utils::{
|
||||
cache_header::cache_1hour,
|
||||
error::{LemmyError, LemmyErrorType, LemmyResult},
|
||||
|
@ -361,53 +355,24 @@ async fn get_feed_front(
|
|||
async fn get_feed_inbox(context: &LemmyContext, jwt: &str) -> LemmyResult<Channel> {
|
||||
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
||||
let local_user = local_user_view_from_jwt(jwt, context).await?;
|
||||
let my_person_id = Some(local_user.person.id);
|
||||
let recipient_id = Some(local_user.local_user.person_id);
|
||||
let show_bot_accounts = local_user.local_user.show_bot_accounts;
|
||||
let limit = Some(RSS_FETCH_LIMIT);
|
||||
let my_person_id = local_user.person.id;
|
||||
let show_bot_accounts = Some(local_user.local_user.show_bot_accounts);
|
||||
let unread_only = Some(false);
|
||||
|
||||
check_private_instance(&Some(local_user.clone()), &site_view.local_site)?;
|
||||
|
||||
let replies = CommentReplyQuery {
|
||||
recipient_id,
|
||||
let inbox = InboxCombinedQuery {
|
||||
my_person_id,
|
||||
unread_only,
|
||||
show_bot_accounts,
|
||||
sort: Some(CommentSortType::New),
|
||||
limit,
|
||||
..Default::default()
|
||||
}
|
||||
.list(&mut context.pool())
|
||||
.await?;
|
||||
|
||||
let comment_mentions = PersonCommentMentionQuery {
|
||||
recipient_id,
|
||||
my_person_id,
|
||||
show_bot_accounts,
|
||||
sort: Some(CommentSortType::New),
|
||||
limit,
|
||||
..Default::default()
|
||||
}
|
||||
.list(&mut context.pool())
|
||||
.await?;
|
||||
|
||||
let post_mentions = PersonPostMentionQuery {
|
||||
recipient_id,
|
||||
my_person_id,
|
||||
show_bot_accounts,
|
||||
sort: Some(PostSortType::New),
|
||||
limit,
|
||||
..Default::default()
|
||||
page_after: None,
|
||||
page_back: None,
|
||||
}
|
||||
.list(&mut context.pool())
|
||||
.await?;
|
||||
|
||||
let protocol_and_hostname = context.settings().get_protocol_and_hostname();
|
||||
let items = create_reply_and_mention_items(
|
||||
replies,
|
||||
comment_mentions,
|
||||
post_mentions,
|
||||
&protocol_and_hostname,
|
||||
)?;
|
||||
let items = create_reply_and_mention_items(inbox, &protocol_and_hostname)?;
|
||||
|
||||
let mut channel = Channel {
|
||||
namespaces: RSS_NAMESPACE.clone(),
|
||||
|
@ -426,57 +391,55 @@ async fn get_feed_inbox(context: &LemmyContext, jwt: &str) -> LemmyResult<Channe
|
|||
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn create_reply_and_mention_items(
|
||||
replies: Vec<CommentReplyView>,
|
||||
comment_mentions: Vec<PersonCommentMentionView>,
|
||||
post_mentions: Vec<PersonPostMentionView>,
|
||||
inbox: Vec<InboxCombinedView>,
|
||||
protocol_and_hostname: &str,
|
||||
) -> LemmyResult<Vec<Item>> {
|
||||
let mut reply_items: Vec<Item> = replies
|
||||
let reply_items: Vec<Item> = inbox
|
||||
.iter()
|
||||
.map(|r| {
|
||||
let reply_url = format!("{}/comment/{}", protocol_and_hostname, r.comment.id);
|
||||
.map(|r| match r {
|
||||
InboxCombinedView::CommentReply(v) => {
|
||||
let reply_url = format!("{}/comment/{}", protocol_and_hostname, v.comment.id);
|
||||
build_item(
|
||||
&r.creator.name,
|
||||
&r.comment.published,
|
||||
&v.creator.name,
|
||||
&v.comment.published,
|
||||
&reply_url,
|
||||
&r.comment.content,
|
||||
&v.comment.content,
|
||||
protocol_and_hostname,
|
||||
)
|
||||
})
|
||||
.collect::<LemmyResult<Vec<Item>>>()?;
|
||||
|
||||
let mut comment_mention_items: Vec<Item> = comment_mentions
|
||||
.iter()
|
||||
.map(|m| {
|
||||
let mention_url = format!("{}/comment/{}", protocol_and_hostname, m.comment.id);
|
||||
}
|
||||
InboxCombinedView::CommentMention(v) => {
|
||||
let mention_url = format!("{}/comment/{}", protocol_and_hostname, v.comment.id);
|
||||
build_item(
|
||||
&m.creator.name,
|
||||
&m.comment.published,
|
||||
&v.creator.name,
|
||||
&v.comment.published,
|
||||
&mention_url,
|
||||
&m.comment.content,
|
||||
&v.comment.content,
|
||||
protocol_and_hostname,
|
||||
)
|
||||
})
|
||||
.collect::<LemmyResult<Vec<Item>>>()?;
|
||||
|
||||
reply_items.append(&mut comment_mention_items);
|
||||
|
||||
let mut post_mention_items: Vec<Item> = post_mentions
|
||||
.iter()
|
||||
.map(|m| {
|
||||
let mention_url = format!("{}/post/{}", protocol_and_hostname, m.post.id);
|
||||
}
|
||||
InboxCombinedView::PostMention(v) => {
|
||||
let mention_url = format!("{}/post/{}", protocol_and_hostname, v.post.id);
|
||||
build_item(
|
||||
&m.creator.name,
|
||||
&m.post.published,
|
||||
&v.creator.name,
|
||||
&v.post.published,
|
||||
&mention_url,
|
||||
&m.post.body.clone().unwrap_or_default(),
|
||||
&v.post.body.clone().unwrap_or_default(),
|
||||
protocol_and_hostname,
|
||||
)
|
||||
}
|
||||
InboxCombinedView::PrivateMessage(v) => {
|
||||
let inbox_url = format!("{}/inbox", protocol_and_hostname);
|
||||
build_item(
|
||||
&v.creator.name,
|
||||
&v.private_message.published,
|
||||
&inbox_url,
|
||||
&v.private_message.content,
|
||||
protocol_and_hostname,
|
||||
)
|
||||
}
|
||||
})
|
||||
.collect::<LemmyResult<Vec<Item>>>()?;
|
||||
|
||||
reply_items.append(&mut post_mention_items);
|
||||
|
||||
Ok(reply_items)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
-- Rename the person_mention table to person_comment_mention
|
||||
ALTER TABLE person_mention RENAME TO person_comment_mention;
|
||||
|
||||
-- Create the new post_mention table
|
||||
CREATE TABLE person_post_mention (
|
||||
id serial PRIMARY KEY,
|
||||
recipient_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||
post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||
read boolean DEFAULT FALSE NOT NULL,
|
||||
published timestamptz NOT NULL DEFAULT now(),
|
||||
UNIQUE (recipient_id, post_id)
|
||||
);
|
|
@ -1,5 +1,5 @@
|
|||
-- Rename the person_mention table to person_comment_mention
|
||||
ALTER TABLE person_comment_mention RENAME TO person_mention;
|
||||
|
||||
-- Drop the new table
|
||||
DROP TABLE person_post_mention;
|
||||
-- Drop the new tables
|
||||
DROP TABLE person_post_mention, inbox_combined;
|
71
migrations/2024-12-10-193418_add_inbox_combined_table/up.sql
Normal file
71
migrations/2024-12-10-193418_add_inbox_combined_table/up.sql
Normal file
|
@ -0,0 +1,71 @@
|
|||
-- Creates combined tables for
|
||||
-- Inbox: (replies, comment mentions, post mentions, and private_messages)
|
||||
|
||||
-- Also add post mentions, since these didn't exist before.
|
||||
|
||||
-- Rename the person_mention table to person_comment_mention
|
||||
ALTER TABLE person_mention RENAME TO person_comment_mention;
|
||||
|
||||
-- Create the new post_mention table
|
||||
CREATE TABLE person_post_mention (
|
||||
id serial PRIMARY KEY,
|
||||
recipient_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||
post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||
read boolean DEFAULT FALSE NOT NULL,
|
||||
published timestamptz NOT NULL DEFAULT now(),
|
||||
UNIQUE (recipient_id, post_id)
|
||||
);
|
||||
|
||||
CREATE TABLE inbox_combined (
|
||||
id serial PRIMARY KEY,
|
||||
published timestamptz NOT NULL,
|
||||
comment_reply_id int UNIQUE REFERENCES comment_reply ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
person_comment_mention_id int UNIQUE REFERENCES person_comment_mention ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
person_post_mention_id int UNIQUE REFERENCES person_post_mention ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
private_message_id int UNIQUE REFERENCES private_message ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
-- Make sure only one of the columns is not null
|
||||
CHECK (num_nonnulls (comment_reply_id, person_comment_mention_id, person_post_mention_id, private_message_id) = 1)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_inbox_combined_published ON inbox_combined (published DESC, id DESC);
|
||||
|
||||
CREATE INDEX idx_inbox_combined_published_asc ON inbox_combined (reverse_timestamp_sort (published) DESC, id DESC);
|
||||
|
||||
-- Updating the history
|
||||
INSERT INTO inbox_combined (published, comment_reply_id, person_comment_mention_id, person_post_mention_id, private_message_id)
|
||||
SELECT
|
||||
published,
|
||||
id,
|
||||
NULL::int,
|
||||
NULL::int,
|
||||
NULL::int
|
||||
FROM
|
||||
comment_reply
|
||||
UNION ALL
|
||||
SELECT
|
||||
published,
|
||||
NULL::int,
|
||||
id,
|
||||
NULL::int,
|
||||
NULL::int
|
||||
FROM
|
||||
person_comment_mention
|
||||
UNION ALL
|
||||
SELECT
|
||||
published,
|
||||
NULL::int,
|
||||
NULL::int,
|
||||
id,
|
||||
NULL::int
|
||||
FROM
|
||||
person_post_mention
|
||||
UNION ALL
|
||||
SELECT
|
||||
published,
|
||||
NULL::int,
|
||||
NULL::int,
|
||||
NULL::int,
|
||||
id
|
||||
FROM
|
||||
private_message;
|
||||
|
|
@ -28,10 +28,9 @@ use lemmy_api::{
|
|||
login::login,
|
||||
logout::logout,
|
||||
notifications::{
|
||||
list_mentions::list_mentions,
|
||||
list_replies::list_replies,
|
||||
mark_all_read::mark_all_notifications_read,
|
||||
mark_mention_read::mark_person_mention_as_read,
|
||||
mark_comment_mention_read::mark_comment_mention_as_read,
|
||||
mark_post_mention_read::mark_post_mention_as_read,
|
||||
mark_reply_read::mark_reply_as_read,
|
||||
unread_count::unread_count,
|
||||
},
|
||||
|
@ -109,7 +108,6 @@ use lemmy_api_crud::{
|
|||
private_message::{
|
||||
create::create_private_message,
|
||||
delete::delete_private_message,
|
||||
read::get_private_message,
|
||||
update::update_private_message,
|
||||
},
|
||||
site::{create::create_site, read::get_site_v3, update::update_site},
|
||||
|
@ -242,7 +240,6 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) {
|
|||
.service(
|
||||
scope("/private_message")
|
||||
.wrap(rate_limit.message())
|
||||
.route("/list", get().to(get_private_message))
|
||||
.route("", post().to(create_private_message))
|
||||
.route("", put().to(update_private_message))
|
||||
.route("/delete", post().to(delete_private_message))
|
||||
|
@ -302,12 +299,14 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) {
|
|||
scope("/user")
|
||||
.wrap(rate_limit.message())
|
||||
.route("", get().to(read_person))
|
||||
.route("/mention", get().to(list_mentions))
|
||||
.route(
|
||||
"/mention/mark_as_read",
|
||||
post().to(mark_person_mention_as_read),
|
||||
"/mention/comment/mark_as_read",
|
||||
post().to(mark_comment_mention_as_read),
|
||||
)
|
||||
.route(
|
||||
"/mention/post/mark_as_read",
|
||||
post().to(mark_post_mention_as_read),
|
||||
)
|
||||
.route("/replies", get().to(list_replies))
|
||||
// Admin action. I don't like that it's in /user
|
||||
.route("/ban", post().to(ban_from_site))
|
||||
.route("/banned", get().to(list_banned_users))
|
||||
|
|
|
@ -35,10 +35,10 @@ use lemmy_api::{
|
|||
login::login,
|
||||
logout::logout,
|
||||
notifications::{
|
||||
list_mentions::list_mentions,
|
||||
list_replies::list_replies,
|
||||
list_inbox::list_inbox,
|
||||
mark_all_read::mark_all_notifications_read,
|
||||
mark_mention_read::mark_person_mention_as_read,
|
||||
mark_comment_mention_read::mark_comment_mention_as_read,
|
||||
mark_post_mention_read::mark_post_mention_as_read,
|
||||
mark_reply_read::mark_reply_as_read,
|
||||
unread_count::unread_count,
|
||||
},
|
||||
|
@ -126,7 +126,6 @@ use lemmy_api_crud::{
|
|||
private_message::{
|
||||
create::create_private_message,
|
||||
delete::delete_private_message,
|
||||
read::get_private_message,
|
||||
update::update_private_message,
|
||||
},
|
||||
site::{create::create_site, read::get_site_v4, update::update_site},
|
||||
|
@ -256,7 +255,6 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) {
|
|||
// Private Message
|
||||
.service(
|
||||
scope("/private_message")
|
||||
.route("/list", get().to(get_private_message))
|
||||
.route("", post().to(create_private_message))
|
||||
.route("", put().to(update_private_message))
|
||||
.route("/delete", post().to(delete_private_message))
|
||||
|
@ -298,12 +296,15 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) {
|
|||
scope("/account")
|
||||
.route("", get().to(get_my_user))
|
||||
.route("/list_media", get().to(list_media))
|
||||
.route("/mention", get().to(list_mentions))
|
||||
.route("/replies", get().to(list_replies))
|
||||
.route("/inbox", get().to(list_inbox))
|
||||
.route("/delete", post().to(delete_account))
|
||||
.route(
|
||||
"/mention/mark_as_read",
|
||||
post().to(mark_person_mention_as_read),
|
||||
"/mention/comment/mark_as_read",
|
||||
post().to(mark_comment_mention_as_read),
|
||||
)
|
||||
.route(
|
||||
"/mention/post/mark_as_read",
|
||||
post().to(mark_post_mention_as_read),
|
||||
)
|
||||
.route(
|
||||
"/mention/mark_as_read/all",
|
||||
|
|
Loading…
Reference in a new issue