mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-12-31 15:21:31 +00:00
Finishing up combined person_saved and person_content.
This commit is contained in:
parent
32b5411abd
commit
3abc46fad9
14 changed files with 486 additions and 567 deletions
|
@ -16,10 +16,7 @@ pub async fn save_comment(
|
|||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<CommentResponse>> {
|
||||
let comment_saved_form = CommentSavedForm {
|
||||
comment_id: data.comment_id,
|
||||
person_id: local_user_view.person.id,
|
||||
};
|
||||
let comment_saved_form = CommentSavedForm::new(data.comment_id, local_user_view.person.id);
|
||||
|
||||
if data.save {
|
||||
CommentSaved::save(&mut context.pool(), &comment_saved_form)
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
use activitypub_federation::config::Data;
|
||||
use actix_web::web::{Json, Query};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
person::{ListPersonSaved, ListPersonSavedResponse},
|
||||
utils::check_private_instance,
|
||||
};
|
||||
use lemmy_db_views::{
|
||||
person_saved_combined_view::PersonSavedCombinedQuery,
|
||||
structs::{LocalUserView, SiteView},
|
||||
};
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn list_person_saved(
|
||||
data: Query<ListPersonSaved>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<ListPersonSavedResponse>> {
|
||||
let local_site = SiteView::read_local(&mut context.pool()).await?;
|
||||
|
||||
check_private_instance(&Some(local_user_view.clone()), &local_site.local_site)?;
|
||||
|
||||
// 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 saved = PersonSavedCombinedQuery {
|
||||
page_after,
|
||||
page_back,
|
||||
}
|
||||
.list(&mut context.pool(), &local_user_view)
|
||||
.await?;
|
||||
|
||||
Ok(Json(ListPersonSavedResponse { saved }))
|
||||
}
|
|
@ -11,6 +11,7 @@ use lemmy_db_views::structs::{
|
|||
LocalImageView,
|
||||
PersonContentCombinedPaginationCursor,
|
||||
PersonContentCombinedView,
|
||||
PersonSavedCombinedPaginationCursor,
|
||||
};
|
||||
use lemmy_db_views_actor::structs::{
|
||||
CommentReplyView,
|
||||
|
@ -273,9 +274,9 @@ pub struct ListPersonContentResponse {
|
|||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Gets your saved posts and comments
|
||||
pub struct ListSaved {
|
||||
pub struct ListPersonSaved {
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page_cursor: Option<PersonContentCombinedPaginationCursor>,
|
||||
pub page_cursor: Option<PersonSavedCombinedPaginationCursor>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page_back: Option<bool>,
|
||||
}
|
||||
|
@ -285,7 +286,7 @@ pub struct ListSaved {
|
|||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A person's saved content response.
|
||||
pub struct ListSavedResponse {
|
||||
pub struct ListPersonSavedResponse {
|
||||
pub saved: Vec<PersonContentCombinedView>,
|
||||
}
|
||||
|
||||
|
|
|
@ -212,10 +212,7 @@ pub async fn import_settings(
|
|||
&context,
|
||||
|(saved, context)| async move {
|
||||
let comment = saved.dereference(&context).await?;
|
||||
let form = CommentSavedForm {
|
||||
person_id,
|
||||
comment_id: comment.id,
|
||||
};
|
||||
let form = CommentSavedForm::new(comment.id, person_id);
|
||||
CommentSaved::save(&mut context.pool(), &form).await?;
|
||||
LemmyResult::Ok(())
|
||||
},
|
||||
|
|
|
@ -714,33 +714,74 @@ CALL r.create_person_content_combined_trigger ('post');
|
|||
CALL r.create_person_content_combined_trigger ('comment');
|
||||
|
||||
-- person_saved (comment, post)
|
||||
-- TODO, not sure how to handle changes to post_actions and comment_actions.saved column.
|
||||
-- False should delete this row, true should insert
|
||||
-- CREATE PROCEDURE r.create_person_saved_combined_trigger (table_name text)
|
||||
-- LANGUAGE plpgsql
|
||||
-- AS $a$
|
||||
-- BEGIN
|
||||
-- EXECUTE replace($b$ CREATE FUNCTION r.person_saved_combined_thing_insert ( )
|
||||
-- RETURNS TRIGGER
|
||||
-- LANGUAGE plpgsql
|
||||
-- AS $$
|
||||
-- BEGIN
|
||||
-- INSERT INTO person_saved_combined (published, thing_id)
|
||||
-- VALUES (NEW.saved, NEW.id);
|
||||
-- RETURN NEW;
|
||||
-- END $$;
|
||||
-- CREATE TRIGGER person_saved_combined
|
||||
-- AFTER INSERT ON thing
|
||||
-- FOR EACH ROW
|
||||
-- EXECUTE FUNCTION r.person_saved_combined_thing_insert ( );
|
||||
-- $b$,
|
||||
-- 'thing',
|
||||
-- table_name);
|
||||
-- END;
|
||||
-- $a$;
|
||||
-- TODO, not sure how to handle changes to post_actions and comment_actions.saved column using @dullbanana's trigger method.
|
||||
-- Post
|
||||
CREATE FUNCTION r.person_saved_combined_change_values_post ()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
IF (TG_OP = 'DELETE') THEN
|
||||
DELETE FROM person_saved_combined AS p
|
||||
WHERE p.person_id = OLD.person_id
|
||||
AND p.post_id = OLD.post_id;
|
||||
ELSIF (TG_OP = 'INSERT') THEN
|
||||
IF NEW.saved IS NOT NULL THEN
|
||||
INSERT INTO person_saved_combined (published, person_id, post_id)
|
||||
VALUES (NEW.saved, NEW.person_id, NEW.post_id);
|
||||
END IF;
|
||||
ELSIF (TG_OP = 'UPDATE') THEN
|
||||
IF NEW.saved IS NOT NULL THEN
|
||||
INSERT INTO person_saved_combined (published, person_id, post_id)
|
||||
VALUES (NEW.saved, NEW.person_id, NEW.post_id);
|
||||
-- If saved gets set as null, delete the row
|
||||
ELSE
|
||||
DELETE FROM person_saved_combined AS p
|
||||
WHERE p.person_id = NEW.person_id
|
||||
AND p.post_id = NEW.post_id;
|
||||
END IF;
|
||||
END IF;
|
||||
RETURN NULL;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- CALL r.create_person_saved_combined_trigger ('post_actions');
|
||||
CREATE TRIGGER person_saved_combined_post
|
||||
AFTER INSERT OR DELETE OR UPDATE OF saved ON post_actions
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION r.person_saved_combined_change_values_post ();
|
||||
|
||||
-- CALL r.create_person_saved_combined_trigger ('comment_actions');
|
||||
-- Comment
|
||||
CREATE FUNCTION r.person_saved_combined_change_values_comment ()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
IF (TG_OP = 'DELETE') THEN
|
||||
DELETE FROM person_saved_combined AS p
|
||||
WHERE p.person_id = OLD.person_id
|
||||
AND p.comment_id = OLD.comment_id;
|
||||
ELSIF (TG_OP = 'INSERT') THEN
|
||||
IF NEW.saved IS NOT NULL THEN
|
||||
INSERT INTO person_saved_combined (published, person_id, comment_id)
|
||||
VALUES (NEW.saved, NEW.person_id, NEW.comment_id);
|
||||
END IF;
|
||||
ELSIF (TG_OP = 'UPDATE') THEN
|
||||
IF NEW.saved IS NOT NULL THEN
|
||||
INSERT INTO person_saved_combined (published, person_id, comment_id)
|
||||
VALUES (NEW.saved, NEW.person_id, NEW.comment_id);
|
||||
-- If saved gets set as null, delete the row
|
||||
ELSE
|
||||
DELETE FROM person_saved_combined AS p
|
||||
WHERE p.person_id = NEW.person_id
|
||||
AND p.comment_id = NEW.comment_id;
|
||||
END IF;
|
||||
END IF;
|
||||
RETURN NULL;
|
||||
END
|
||||
$$;
|
||||
|
||||
CREATE TRIGGER person_saved_combined_comment
|
||||
AFTER INSERT OR DELETE OR UPDATE OF saved ON comment_actions
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION r.person_saved_combined_change_values_comment ();
|
||||
|
||||
|
|
|
@ -184,10 +184,6 @@ impl Saveable for CommentSaved {
|
|||
comment_saved_form: &CommentSavedForm,
|
||||
) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
let comment_saved_form = (
|
||||
comment_saved_form,
|
||||
comment_actions::saved.eq(now().nullable()),
|
||||
);
|
||||
insert_into(comment_actions::table)
|
||||
.values(comment_saved_form)
|
||||
.on_conflict((comment_actions::comment_id, comment_actions::person_id))
|
||||
|
@ -319,11 +315,7 @@ mod tests {
|
|||
};
|
||||
|
||||
// Comment Saved
|
||||
let comment_saved_form = CommentSavedForm {
|
||||
comment_id: inserted_comment.id,
|
||||
person_id: inserted_person.id,
|
||||
};
|
||||
|
||||
let comment_saved_form = CommentSavedForm::new(inserted_comment.id, inserted_person.id);
|
||||
let inserted_comment_saved = CommentSaved::save(pool, &comment_saved_form).await?;
|
||||
|
||||
let expected_comment_saved = CommentSaved {
|
||||
|
|
|
@ -752,6 +752,7 @@ diesel::table! {
|
|||
person_saved_combined (id) {
|
||||
id -> Int4,
|
||||
published -> Timestamptz,
|
||||
person_id -> Int4,
|
||||
post_id -> Nullable<Int4>,
|
||||
comment_id -> Nullable<Int4>,
|
||||
}
|
||||
|
@ -1053,6 +1054,7 @@ diesel::joinable!(person_content_combined -> post (post_id));
|
|||
diesel::joinable!(person_mention -> comment (comment_id));
|
||||
diesel::joinable!(person_mention -> person (recipient_id));
|
||||
diesel::joinable!(person_saved_combined -> comment (comment_id));
|
||||
diesel::joinable!(person_saved_combined -> person (person_id));
|
||||
diesel::joinable!(person_saved_combined -> post (post_id));
|
||||
diesel::joinable!(post -> community (community_id));
|
||||
diesel::joinable!(post -> language (language_id));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::newtypes::{CommentId, PersonSavedCombinedId, PostId};
|
||||
use crate::newtypes::{CommentId, PersonId, PersonSavedCombinedId, PostId};
|
||||
#[cfg(feature = "full")]
|
||||
use crate::schema::person_saved_combined;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
@ -23,6 +23,7 @@ use ts_rs::TS;
|
|||
pub struct PersonSavedCombined {
|
||||
pub id: PersonSavedCombinedId,
|
||||
pub published: DateTime<Utc>,
|
||||
pub person_id: PersonId,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub post_id: Option<PostId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
|
|
|
@ -142,7 +142,10 @@ pub struct CommentSaved {
|
|||
|
||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = comment_actions))]
|
||||
#[derive(derive_new::new)]
|
||||
pub struct CommentSavedForm {
|
||||
pub comment_id: CommentId,
|
||||
pub person_id: PersonId,
|
||||
#[new(value = "Utc::now()")]
|
||||
pub saved: DateTime<Utc>,
|
||||
}
|
||||
|
|
|
@ -121,8 +121,8 @@ impl PersonContentCombinedQuery {
|
|||
person::table.on(
|
||||
comment::creator_id
|
||||
.eq(item_creator)
|
||||
// Need to filter out the post rows where both the post and comment creator are the
|
||||
// same.
|
||||
// Need to filter out the post rows where the post_id given is null
|
||||
// Otherwise you'll get duped post rows
|
||||
.or(
|
||||
post::creator_id
|
||||
.eq(item_creator)
|
||||
|
@ -372,7 +372,7 @@ mod tests {
|
|||
.await?;
|
||||
assert_eq!(3, timmy_content.len());
|
||||
|
||||
// Make sure the report types are correct
|
||||
// Make sure the types are correct
|
||||
if let PersonContentCombinedView::Comment(v) = &timmy_content[0] {
|
||||
assert_eq!(data.timmy_comment.id, v.comment.id);
|
||||
assert_eq!(data.timmy.id, v.creator.id);
|
||||
|
|
|
@ -1,554 +1,393 @@
|
|||
// use crate::{
|
||||
// structs::{
|
||||
// CommentView,
|
||||
// LocalUserView,
|
||||
// PostView,
|
||||
// ProfileCombinedPaginationCursor,
|
||||
// PersonContentCombinedView,
|
||||
// PersonContentViewInternal,
|
||||
// },
|
||||
// InternalToCombinedView,
|
||||
// };
|
||||
// use diesel::{
|
||||
// result::Error,
|
||||
// BoolExpressionMethods,
|
||||
// ExpressionMethods,
|
||||
// JoinOnDsl,
|
||||
// NullableExpressionMethods,
|
||||
// QueryDsl,
|
||||
// SelectableHelper,
|
||||
// };
|
||||
// use diesel_async::RunQueryDsl;
|
||||
// use i_love_jesus::PaginatedQueryBuilder;
|
||||
// use lemmy_db_schema::{
|
||||
// aliases::creator_community_actions,
|
||||
// newtypes::{CommunityId, PersonId},
|
||||
// schema::{
|
||||
// comment,
|
||||
// comment_actions,
|
||||
// comment_aggregates,
|
||||
// community,
|
||||
// community_actions,
|
||||
// image_details,
|
||||
// local_user,
|
||||
// person,
|
||||
// person_actions,
|
||||
// post,
|
||||
// post_actions,
|
||||
// post_aggregates,
|
||||
// profile_combined,
|
||||
// },
|
||||
// source::{
|
||||
// combined::profile::{profile_combined_keys as key, ProfileCombined},
|
||||
// community::CommunityFollower,
|
||||
// },
|
||||
// utils::{actions, actions_alias, functions::coalesce, get_conn, DbPool, ReverseTimestampKey},
|
||||
// };
|
||||
// use lemmy_utils::error::LemmyResult;
|
||||
use crate::{
|
||||
structs::{
|
||||
LocalUserView,
|
||||
PersonContentCombinedView,
|
||||
PersonContentViewInternal,
|
||||
PersonSavedCombinedPaginationCursor,
|
||||
},
|
||||
InternalToCombinedView,
|
||||
};
|
||||
use diesel::{
|
||||
result::Error,
|
||||
BoolExpressionMethods,
|
||||
ExpressionMethods,
|
||||
JoinOnDsl,
|
||||
NullableExpressionMethods,
|
||||
QueryDsl,
|
||||
SelectableHelper,
|
||||
};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use i_love_jesus::PaginatedQueryBuilder;
|
||||
use lemmy_db_schema::{
|
||||
aliases::creator_community_actions,
|
||||
schema::{
|
||||
comment,
|
||||
comment_actions,
|
||||
comment_aggregates,
|
||||
community,
|
||||
community_actions,
|
||||
image_details,
|
||||
local_user,
|
||||
person,
|
||||
person_actions,
|
||||
person_saved_combined,
|
||||
post,
|
||||
post_actions,
|
||||
post_aggregates,
|
||||
},
|
||||
source::{
|
||||
combined::person_saved::{person_saved_combined_keys as key, PersonSavedCombined},
|
||||
community::CommunityFollower,
|
||||
},
|
||||
utils::{actions, actions_alias, functions::coalesce, get_conn, DbPool},
|
||||
};
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
// impl ProfileCombinedPaginationCursor {
|
||||
// // get cursor for page that starts immediately after the given post
|
||||
// pub fn after_post(view: &PersonContentCombinedView) -> ProfileCombinedPaginationCursor {
|
||||
// let (prefix, id) = match view {
|
||||
// PersonContentCombinedView::Comment(v) => ('C', v.comment.id.0),
|
||||
// PersonContentCombinedView::Post(v) => ('P', v.post.id.0),
|
||||
// };
|
||||
// // hex encoding to prevent ossification
|
||||
// ProfileCombinedPaginationCursor(format!("{prefix}{id:x}"))
|
||||
// }
|
||||
impl PersonSavedCombinedPaginationCursor {
|
||||
// get cursor for page that starts immediately after the given post
|
||||
pub fn after_post(view: &PersonContentCombinedView) -> PersonSavedCombinedPaginationCursor {
|
||||
let (prefix, id) = match view {
|
||||
PersonContentCombinedView::Comment(v) => ('C', v.comment.id.0),
|
||||
PersonContentCombinedView::Post(v) => ('P', v.post.id.0),
|
||||
};
|
||||
// hex encoding to prevent ossification
|
||||
PersonSavedCombinedPaginationCursor(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 = profile_combined::table
|
||||
// .select(ProfileCombined::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 {
|
||||
// "C" => query.filter(profile_combined::comment_id.eq(id)),
|
||||
// "P" => query.filter(profile_combined::post_id.eq(id)),
|
||||
// _ => return Err(err_msg()),
|
||||
// };
|
||||
// let token = query.first(&mut get_conn(pool).await?).await?;
|
||||
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 = person_saved_combined::table
|
||||
.select(PersonSavedCombined::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 {
|
||||
"C" => query.filter(person_saved_combined::comment_id.eq(id)),
|
||||
"P" => query.filter(person_saved_combined::post_id.eq(id)),
|
||||
_ => return Err(err_msg()),
|
||||
};
|
||||
let token = query.first(&mut get_conn(pool).await?).await?;
|
||||
|
||||
// Ok(PaginationCursorData(token))
|
||||
// }
|
||||
// }
|
||||
Ok(PaginationCursorData(token))
|
||||
}
|
||||
}
|
||||
|
||||
// #[derive(Clone)]
|
||||
// pub struct PaginationCursorData(ProfileCombined);
|
||||
#[derive(Clone)]
|
||||
pub struct PaginationCursorData(PersonSavedCombined);
|
||||
|
||||
// #[derive(Default)]
|
||||
// pub struct ProfileCombinedQuery {
|
||||
// pub creator_id: PersonId,
|
||||
// pub page_after: Option<PaginationCursorData>,
|
||||
// pub page_back: Option<bool>,
|
||||
// }
|
||||
#[derive(Default)]
|
||||
pub struct PersonSavedCombinedQuery {
|
||||
pub page_after: Option<PaginationCursorData>,
|
||||
pub page_back: Option<bool>,
|
||||
}
|
||||
|
||||
// impl ProfileCombinedQuery {
|
||||
// pub async fn list(
|
||||
// self,
|
||||
// pool: &mut DbPool<'_>,
|
||||
// user: &Option<LocalUserView>,
|
||||
// ) -> LemmyResult<Vec<PersonContentCombinedView>> {
|
||||
// let my_person_id = user
|
||||
// .as_ref()
|
||||
// .map(|u| u.local_user.person_id)
|
||||
// .unwrap_or(PersonId(-1));
|
||||
// let item_creator = person::id;
|
||||
impl PersonSavedCombinedQuery {
|
||||
pub async fn list(
|
||||
self,
|
||||
pool: &mut DbPool<'_>,
|
||||
user: &LocalUserView,
|
||||
) -> LemmyResult<Vec<PersonContentCombinedView>> {
|
||||
let my_person_id = user.local_user.person_id;
|
||||
let item_creator = person::id;
|
||||
|
||||
// let conn = &mut get_conn(pool).await?;
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
|
||||
// // Notes: since the post_id and comment_id are optional columns,
|
||||
// // many joins must use an OR condition.
|
||||
// // For example, the creator must be the person table joined to either:
|
||||
// // - post.creator_id
|
||||
// // - comment.creator_id
|
||||
// let mut query = profile_combined::table
|
||||
// // The comment
|
||||
// .left_join(comment::table.on(profile_combined::comment_id.eq(comment::id.nullable())))
|
||||
// // The post
|
||||
// .inner_join(
|
||||
// post::table.on(
|
||||
// profile_combined::post_id
|
||||
// .eq(post::id.nullable())
|
||||
// .or(comment::post_id.nullable().eq(profile_combined::post_id)),
|
||||
// ),
|
||||
// )
|
||||
// // The item creator
|
||||
// .inner_join(
|
||||
// person::table.on(
|
||||
// comment::creator_id
|
||||
// .eq(person::id)
|
||||
// .or(post::creator_id.eq(person::id)),
|
||||
// ),
|
||||
// )
|
||||
// // The community
|
||||
// .inner_join(community::table.on(post::community_id.eq(community::id)))
|
||||
// .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,
|
||||
// Some(my_person_id),
|
||||
// post::community_id,
|
||||
// ))
|
||||
// .left_join(actions(post_actions::table, Some(my_person_id), post::id))
|
||||
// .left_join(actions(
|
||||
// person_actions::table,
|
||||
// Some(my_person_id),
|
||||
// item_creator,
|
||||
// ))
|
||||
// .inner_join(post_aggregates::table.on(post::id.eq(post_aggregates::post_id)))
|
||||
// .left_join(
|
||||
// comment_aggregates::table
|
||||
// .on(profile_combined::comment_id.eq(comment_aggregates::comment_id.nullable())),
|
||||
// )
|
||||
// .left_join(actions(
|
||||
// comment_actions::table,
|
||||
// Some(my_person_id),
|
||||
// comment::id,
|
||||
// ))
|
||||
// .left_join(image_details::table.on(post::thumbnail_url.eq(image_details::link.nullable())))
|
||||
// // The creator id filter
|
||||
// .filter(item_creator.eq(self.creator_id))
|
||||
// .select((
|
||||
// // Post-specific
|
||||
// post_aggregates::all_columns,
|
||||
// coalesce(
|
||||
// post_aggregates::comments.nullable() - post_actions::read_comments_amount.nullable(),
|
||||
// post_aggregates::comments,
|
||||
// ),
|
||||
// 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(),
|
||||
// // Comment-specific
|
||||
// comment::all_columns.nullable(),
|
||||
// comment_aggregates::all_columns.nullable(),
|
||||
// comment_actions::saved.nullable().is_not_null(),
|
||||
// comment_actions::like_score.nullable(),
|
||||
// // Shared
|
||||
// post::all_columns,
|
||||
// community::all_columns,
|
||||
// person::all_columns,
|
||||
// CommunityFollower::select_subscribed_type(),
|
||||
// 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();
|
||||
// Notes: since the post_id and comment_id are optional columns,
|
||||
// many joins must use an OR condition.
|
||||
// For example, the creator must be the person table joined to either:
|
||||
// - post.creator_id
|
||||
// - comment.creator_id
|
||||
let query = person_saved_combined::table
|
||||
// The comment
|
||||
.left_join(comment::table.on(person_saved_combined::comment_id.eq(comment::id.nullable())))
|
||||
// The post
|
||||
// It gets a bit complicated here, because since both comments and post combined have a post
|
||||
// attached, you can do an inner join.
|
||||
.inner_join(
|
||||
post::table.on(
|
||||
person_saved_combined::post_id
|
||||
.eq(post::id.nullable())
|
||||
.or(comment::post_id.eq(post::id)),
|
||||
),
|
||||
)
|
||||
// The item creator
|
||||
.inner_join(
|
||||
person::table.on(
|
||||
comment::creator_id
|
||||
.eq(item_creator)
|
||||
// Need to filter out the post rows where the post_id given is null
|
||||
// Otherwise you'll get duped post rows
|
||||
.or(
|
||||
post::creator_id
|
||||
.eq(item_creator)
|
||||
.and(person_saved_combined::post_id.is_not_null()),
|
||||
),
|
||||
),
|
||||
)
|
||||
// The community
|
||||
.inner_join(community::table.on(post::community_id.eq(community::id)))
|
||||
.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,
|
||||
Some(my_person_id),
|
||||
post::community_id,
|
||||
))
|
||||
.left_join(actions(post_actions::table, Some(my_person_id), post::id))
|
||||
.left_join(actions(
|
||||
person_actions::table,
|
||||
Some(my_person_id),
|
||||
item_creator,
|
||||
))
|
||||
.inner_join(post_aggregates::table.on(post::id.eq(post_aggregates::post_id)))
|
||||
.left_join(
|
||||
comment_aggregates::table
|
||||
.on(person_saved_combined::comment_id.eq(comment_aggregates::comment_id.nullable())),
|
||||
)
|
||||
.left_join(actions(
|
||||
comment_actions::table,
|
||||
Some(my_person_id),
|
||||
comment::id,
|
||||
))
|
||||
.left_join(image_details::table.on(post::thumbnail_url.eq(image_details::link.nullable())))
|
||||
// The person id filter
|
||||
.filter(person_saved_combined::person_id.eq(my_person_id))
|
||||
.select((
|
||||
// Post-specific
|
||||
post_aggregates::all_columns,
|
||||
coalesce(
|
||||
post_aggregates::comments.nullable() - post_actions::read_comments_amount.nullable(),
|
||||
post_aggregates::comments,
|
||||
),
|
||||
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(),
|
||||
// Comment-specific
|
||||
comment::all_columns.nullable(),
|
||||
comment_aggregates::all_columns.nullable(),
|
||||
comment_actions::saved.nullable().is_not_null(),
|
||||
comment_actions::like_score.nullable(),
|
||||
// Shared
|
||||
post::all_columns,
|
||||
community::all_columns,
|
||||
person::all_columns,
|
||||
CommunityFollower::select_subscribed_type(),
|
||||
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();
|
||||
|
||||
// let mut query = PaginatedQueryBuilder::new(query);
|
||||
let mut query = PaginatedQueryBuilder::new(query);
|
||||
|
||||
// let page_after = self.page_after.map(|c| c.0);
|
||||
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);
|
||||
// }
|
||||
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(ReverseTimestampKey(key::published))
|
||||
// // Tie breaker
|
||||
// .then_desc(key::id);
|
||||
// Sorting by published
|
||||
query = query
|
||||
.then_desc(key::published)
|
||||
// Tie breaker
|
||||
.then_desc(key::id);
|
||||
|
||||
// let res = query.load::<PersonContentViewInternal>(conn).await?;
|
||||
let res = query.load::<PersonContentViewInternal>(conn).await?;
|
||||
|
||||
// // Map the query results to the enum
|
||||
// let out = res.into_iter().filter_map(|u| u.map_to_enum()).collect();
|
||||
// Map the query results to the enum
|
||||
let out = res.into_iter().filter_map(|u| u.map_to_enum()).collect();
|
||||
|
||||
// Ok(out)
|
||||
// }
|
||||
// }
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
||||
// impl InternalToCombinedView for PersonContentViewInternal {
|
||||
// type CombinedView = PersonContentCombinedView;
|
||||
#[cfg(test)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
// fn map_to_enum(&self) -> Option<Self::CombinedView> {
|
||||
// // Use for a short alias
|
||||
// let v = self.clone();
|
||||
use crate::{
|
||||
person_saved_combined_view::PersonSavedCombinedQuery,
|
||||
structs::{LocalUserView, PersonContentCombinedView},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
comment::{Comment, CommentInsertForm, CommentSaved, CommentSavedForm},
|
||||
community::{Community, CommunityInsertForm},
|
||||
instance::Instance,
|
||||
local_user::{LocalUser, LocalUserInsertForm},
|
||||
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||
person::{Person, PersonInsertForm},
|
||||
post::{Post, PostInsertForm, PostSaved, PostSavedForm},
|
||||
},
|
||||
traits::{Crud, Saveable},
|
||||
utils::{build_db_pool_for_tests, DbPool},
|
||||
};
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serial_test::serial;
|
||||
|
||||
// if let (Some(comment), Some(counts)) = (v.comment, v.comment_counts) {
|
||||
// Some(PersonContentCombinedView::Comment(CommentView {
|
||||
// comment,
|
||||
// counts,
|
||||
// post: v.post,
|
||||
// community: v.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 {
|
||||
// Some(PersonContentCombinedView::Post(PostView {
|
||||
// post: v.post,
|
||||
// community: v.community,
|
||||
// unread_comments: v.post_unread_comments,
|
||||
// counts: v.post_counts,
|
||||
// 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,
|
||||
// }))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
struct Data {
|
||||
instance: Instance,
|
||||
timmy: Person,
|
||||
timmy_view: LocalUserView,
|
||||
sara: Person,
|
||||
timmy_post: Post,
|
||||
sara_comment: Comment,
|
||||
sara_comment_2: Comment,
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// #[expect(clippy::indexing_slicing)]
|
||||
// mod tests {
|
||||
async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
|
||||
let instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||
|
||||
// use crate::{
|
||||
// profile_combined_view::ProfileCombinedQuery,
|
||||
// report_combined_view::ReportCombinedQuery,
|
||||
// structs::{
|
||||
// CommentReportView,
|
||||
// LocalUserView,
|
||||
// PostReportView,
|
||||
// PersonContentCombinedView,
|
||||
// ReportCombinedView,
|
||||
// ReportCombinedViewInternal,
|
||||
// },
|
||||
// };
|
||||
// use lemmy_db_schema::{
|
||||
// aggregates::structs::{CommentAggregates, PostAggregates},
|
||||
// assert_length,
|
||||
// source::{
|
||||
// comment::{Comment, CommentInsertForm, CommentSaved, CommentSavedForm},
|
||||
// comment_report::{CommentReport, CommentReportForm},
|
||||
// community::{Community, CommunityInsertForm, CommunityModerator, CommunityModeratorForm},
|
||||
// instance::Instance,
|
||||
// local_user::{LocalUser, LocalUserInsertForm},
|
||||
// local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||
// person::{Person, PersonInsertForm},
|
||||
// post::{Post, PostInsertForm},
|
||||
// post_report::{PostReport, PostReportForm},
|
||||
// private_message::{PrivateMessage, PrivateMessageInsertForm},
|
||||
// private_message_report::{PrivateMessageReport, PrivateMessageReportForm},
|
||||
// },
|
||||
// traits::{Crud, Joinable, Reportable, Saveable},
|
||||
// utils::{build_db_pool_for_tests, DbPool},
|
||||
// };
|
||||
// use lemmy_utils::error::LemmyResult;
|
||||
// use pretty_assertions::assert_eq;
|
||||
// use serial_test::serial;
|
||||
let timmy_form = PersonInsertForm::test_form(instance.id, "timmy_pcv");
|
||||
let timmy = Person::create(pool, &timmy_form).await?;
|
||||
let timmy_local_user_form = LocalUserInsertForm::test_form(timmy.id);
|
||||
let timmy_local_user = LocalUser::create(pool, &timmy_local_user_form, vec![]).await?;
|
||||
let timmy_view = LocalUserView {
|
||||
local_user: timmy_local_user,
|
||||
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||
person: timmy.clone(),
|
||||
counts: Default::default(),
|
||||
};
|
||||
|
||||
// struct Data {
|
||||
// instance: Instance,
|
||||
// timmy: Person,
|
||||
// sara: Person,
|
||||
// timmy_view: LocalUserView,
|
||||
// community: Community,
|
||||
// timmy_post: Post,
|
||||
// timmy_post_2: Post,
|
||||
// sara_post: Post,
|
||||
// timmy_comment: Comment,
|
||||
// sara_comment: Comment,
|
||||
// sara_comment_2: Comment,
|
||||
// }
|
||||
let sara_form = PersonInsertForm::test_form(instance.id, "sara_pcv");
|
||||
let sara = Person::create(pool, &sara_form).await?;
|
||||
|
||||
// async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
|
||||
// let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).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_form = PersonInsertForm::test_form(inserted_instance.id, "timmy_pcv");
|
||||
// let inserted_timmy = Person::create(pool, &timmy_form).await?;
|
||||
// let timmy_local_user_form = LocalUserInsertForm::test_form(inserted_timmy.id);
|
||||
// let timmy_local_user = LocalUser::create(pool, &timmy_local_user_form, vec![]).await?;
|
||||
// let timmy_view = LocalUserView {
|
||||
// local_user: timmy_local_user,
|
||||
// local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||
// person: inserted_timmy.clone(),
|
||||
// counts: Default::default(),
|
||||
// };
|
||||
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 sara_form = PersonInsertForm::test_form(inserted_instance.id, "sara_pcv");
|
||||
// let inserted_sara = Person::create(pool, &sara_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 community_form = CommunityInsertForm::new(
|
||||
// inserted_instance.id,
|
||||
// "test community pcv".to_string(),
|
||||
// "nada".to_owned(),
|
||||
// "pubkey".to_string(),
|
||||
// );
|
||||
// let inserted_community = Community::create(pool, &community_form).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_post_form = PostInsertForm::new(
|
||||
// "timmy post prv".into(),
|
||||
// inserted_timmy.id,
|
||||
// inserted_community.id,
|
||||
// );
|
||||
// let timmy_post = Post::create(pool, &timmy_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 timmy_post_form_2 = PostInsertForm::new(
|
||||
// "timmy post prv 2".into(),
|
||||
// inserted_timmy.id,
|
||||
// inserted_community.id,
|
||||
// );
|
||||
// let timmy_post_2 = Post::create(pool, &timmy_post_form_2).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_post_form = PostInsertForm::new(
|
||||
// "sara post prv".into(),
|
||||
// inserted_sara.id,
|
||||
// inserted_community.id,
|
||||
// );
|
||||
// let sara_post = Post::create(pool, &sara_post_form).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?;
|
||||
|
||||
// let timmy_comment_form =
|
||||
// CommentInsertForm::new(inserted_timmy.id, timmy_post.id, "timmy comment prv".into());
|
||||
// let timmy_comment = Comment::create(pool, &timmy_comment_form, None).await?;
|
||||
Ok(Data {
|
||||
instance,
|
||||
timmy,
|
||||
timmy_view,
|
||||
sara,
|
||||
timmy_post,
|
||||
sara_comment,
|
||||
sara_comment_2,
|
||||
})
|
||||
}
|
||||
|
||||
// let sara_comment_form =
|
||||
// CommentInsertForm::new(inserted_sara.id, timmy_post.id, "sara comment prv".into());
|
||||
// let sara_comment = Comment::create(pool, &sara_comment_form, None).await?;
|
||||
async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
|
||||
Instance::delete(pool, data.instance.id).await?;
|
||||
|
||||
// let sara_comment_form_2 = CommentInsertForm::new(
|
||||
// inserted_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(())
|
||||
}
|
||||
|
||||
// Ok(Data {
|
||||
// instance: inserted_instance,
|
||||
// timmy: inserted_timmy,
|
||||
// sara: inserted_sara,
|
||||
// timmy_view,
|
||||
// community: inserted_community,
|
||||
// timmy_post,
|
||||
// timmy_post_2,
|
||||
// sara_post,
|
||||
// timmy_comment,
|
||||
// sara_comment,
|
||||
// sara_comment_2,
|
||||
// })
|
||||
// }
|
||||
#[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?;
|
||||
|
||||
// async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
|
||||
// Instance::delete(pool, data.instance.id).await?;
|
||||
// Do a batch read of timmy saved
|
||||
let timmy_saved = PersonSavedCombinedQuery::default()
|
||||
.list(pool, &data.timmy_view)
|
||||
.await?;
|
||||
assert_eq!(0, timmy_saved.len());
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
// Save a few things
|
||||
let save_sara_comment_2 =
|
||||
CommentSavedForm::new(data.sara_comment_2.id, data.timmy_view.person.id);
|
||||
CommentSaved::save(pool, &save_sara_comment_2).await?;
|
||||
|
||||
// #[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?;
|
||||
let save_sara_comment = CommentSavedForm::new(data.sara_comment.id, data.timmy_view.person.id);
|
||||
CommentSaved::save(pool, &save_sara_comment).await?;
|
||||
|
||||
// // Do a batch read of timmy
|
||||
// let timmy_content = ProfileCombinedQuery::default().list(pool, &None).await?;
|
||||
// assert_eq!(3, timmy_content.len());
|
||||
let post_save_form = PostSavedForm::new(data.timmy_post.id, data.timmy.id);
|
||||
PostSaved::save(pool, &post_save_form).await?;
|
||||
|
||||
// // Make sure the report types are correct
|
||||
// if let PersonContentCombinedView::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 PersonContentCombinedView::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 PersonContentCombinedView::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");
|
||||
// }
|
||||
let timmy_saved = PersonSavedCombinedQuery::default()
|
||||
.list(pool, &data.timmy_view)
|
||||
.await?;
|
||||
assert_eq!(3, timmy_saved.len());
|
||||
|
||||
// // Do a batch read of sara
|
||||
// let sara_content = ProfileCombinedQuery::default().list(pool, &None).await?;
|
||||
// assert_eq!(3, sara_content.len());
|
||||
// Make sure the types and order are correct
|
||||
if let PersonContentCombinedView::Post(v) = &timmy_saved[0] {
|
||||
assert_eq!(data.timmy_post.id, v.post.id);
|
||||
assert_eq!(data.timmy.id, v.post.creator_id);
|
||||
} else {
|
||||
panic!("wrong type");
|
||||
}
|
||||
if let PersonContentCombinedView::Comment(v) = &timmy_saved[1] {
|
||||
assert_eq!(data.sara_comment.id, v.comment.id);
|
||||
assert_eq!(data.sara.id, v.comment.creator_id);
|
||||
} else {
|
||||
panic!("wrong type");
|
||||
}
|
||||
if let PersonContentCombinedView::Comment(v) = &timmy_saved[2] {
|
||||
assert_eq!(data.sara_comment_2.id, v.comment.id);
|
||||
assert_eq!(data.sara.id, v.comment.creator_id);
|
||||
} else {
|
||||
panic!("wrong type");
|
||||
}
|
||||
|
||||
// // Make sure the report types are correct
|
||||
// if let PersonContentCombinedView::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 PersonContentCombinedView::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 PersonContentCombinedView::Post(v) = &sara_content[2] {
|
||||
// assert_eq!(data.timmy_post.id, v.post.id);
|
||||
// assert_eq!(data.timmy.id, v.post.creator_id);
|
||||
// } else {
|
||||
// panic!("wrong type");
|
||||
// }
|
||||
// Try unsaving 2 things
|
||||
CommentSaved::unsave(pool, &save_sara_comment).await?;
|
||||
PostSaved::unsave(pool, &post_save_form).await?;
|
||||
|
||||
// // Timmy saves sara's comment, and his 2nd post
|
||||
// let save_comment_0_form = CommentSavedForm {
|
||||
// person_id: data.timmy.id,
|
||||
// comment_id: data.sara_comment.id,
|
||||
// };
|
||||
// CommentSaved::save(pool, &save_comment_0_form).await?;
|
||||
let timmy_saved = PersonSavedCombinedQuery::default()
|
||||
.list(pool, &data.timmy_view)
|
||||
.await?;
|
||||
assert_eq!(1, timmy_saved.len());
|
||||
|
||||
// // Timmy saves sara's comment, and his 2nd post
|
||||
// let save_comment_0_form = CommentSavedForm {
|
||||
// person_id: data.timmy.id,
|
||||
// comment_id: data.sara_comment.id,
|
||||
// };
|
||||
// CommentSaved::save(pool, &save_comment_0_form).await?;
|
||||
if let PersonContentCombinedView::Comment(v) = &timmy_saved[0] {
|
||||
assert_eq!(data.sara_comment_2.id, v.comment.id);
|
||||
assert_eq!(data.sara.id, v.comment.creator_id);
|
||||
} else {
|
||||
panic!("wrong type");
|
||||
}
|
||||
|
||||
// // Do a saved_only query
|
||||
// let timmy_content_saved_only = ProfileCombinedQuery {}.list(pool, &None).await?;
|
||||
cleanup(data, pool).await?;
|
||||
|
||||
// cleanup(data, pool).await?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
// #[tokio::test]
|
||||
// #[serial]
|
||||
// async fn test_saved_order() -> LemmyResult<()> {
|
||||
// let pool = &build_db_pool_for_tests();
|
||||
// let pool = &mut pool.into();
|
||||
// let data = init_data(pool).await?;
|
||||
|
||||
// // Save two comments
|
||||
// let save_comment_0_form = CommentSavedForm {
|
||||
// person_id: data.timmy_local_user_view.person.id,
|
||||
// comment_id: data.inserted_comment_0.id,
|
||||
// };
|
||||
// CommentSaved::save(pool, &save_comment_0_form).await?;
|
||||
|
||||
// let save_comment_2_form = CommentSavedForm {
|
||||
// person_id: data.timmy_local_user_view.person.id,
|
||||
// comment_id: data.inserted_comment_2.id,
|
||||
// };
|
||||
// CommentSaved::save(pool, &save_comment_2_form).await?;
|
||||
|
||||
// // Fetch the saved comments
|
||||
// let comments = CommentQuery {
|
||||
// local_user: Some(&data.timmy_local_user_view.local_user),
|
||||
// saved_only: Some(true),
|
||||
// ..Default::default()
|
||||
// }
|
||||
// .list(&data.site, pool)
|
||||
// .await?;
|
||||
|
||||
// // There should only be two comments
|
||||
// assert_eq!(2, comments.len());
|
||||
|
||||
// // The first comment, should be the last one saved (descending order)
|
||||
// assert_eq!(comments[0].comment.id, data.inserted_comment_2.id);
|
||||
|
||||
// // The second comment, should be the first one saved
|
||||
// assert_eq!(comments[1].comment.id, data.inserted_comment_0.id);
|
||||
|
||||
// cleanup(data, pool).await
|
||||
// }
|
||||
// #[tokio::test]
|
||||
// #[serial]
|
||||
// async fn post_listing_saved_only() -> LemmyResult<()> {
|
||||
// let pool = &build_db_pool()?;
|
||||
// let pool = &mut pool.into();
|
||||
// let data = init_data(pool).await?;
|
||||
|
||||
// // Save only the bot post
|
||||
// // The saved_only should only show the bot post
|
||||
// let post_save_form =
|
||||
// PostSavedForm::new(data.inserted_bot_post.id, data.local_user_view.person.id);
|
||||
// PostSaved::save(pool, &post_save_form).await?;
|
||||
|
||||
// // Read the saved only
|
||||
// let read_saved_post_listing = PostQuery {
|
||||
// community_id: Some(data.inserted_community.id),
|
||||
// saved_only: Some(true),
|
||||
// ..data.default_post_query()
|
||||
// }
|
||||
// .list(&data.site, pool)
|
||||
// .await?;
|
||||
|
||||
// // This should only include the bot post, not the one you created
|
||||
// assert_eq!(vec![POST_BY_BOT], names(&read_saved_post_listing));
|
||||
|
||||
// cleanup(data, pool).await
|
||||
// }
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
DROP TABLE person_content_combined;
|
||||
|
||||
DROP TABLE person_saved_combined;
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ FROM
|
|||
CREATE TABLE person_saved_combined (
|
||||
id serial PRIMARY KEY,
|
||||
published timestamptz NOT NULL,
|
||||
person_id int NOT NULL REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
post_id int UNIQUE REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
comment_id int UNIQUE REFERENCES COMMENT ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
-- Make sure only one of the columns is not null
|
||||
|
@ -43,23 +44,26 @@ CREATE INDEX idx_person_saved_combined_published ON person_saved_combined (publi
|
|||
|
||||
CREATE INDEX idx_person_saved_combined_published_asc ON person_saved_combined (reverse_timestamp_sort (published) DESC, id DESC);
|
||||
|
||||
CREATE INDEX idx_person_saved_combined ON person_saved_combined (person_id);
|
||||
|
||||
-- Updating the history
|
||||
INSERT INTO person_saved_combined (published, post_id)
|
||||
INSERT INTO person_saved_combined (published, person_id, post_id)
|
||||
SELECT
|
||||
saved,
|
||||
person_id,
|
||||
post_id
|
||||
FROM
|
||||
post_actions
|
||||
WHERE
|
||||
WHERE
|
||||
saved IS NOT NULL;
|
||||
|
||||
INSERT INTO person_saved_combined (published, comment_id)
|
||||
INSERT INTO person_saved_combined (published, person_id, comment_id)
|
||||
SELECT
|
||||
saved,
|
||||
person_id,
|
||||
comment_id
|
||||
FROM
|
||||
comment_actions
|
||||
WHERE
|
||||
WHERE
|
||||
saved IS NOT NULL;
|
||||
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ use lemmy_api::{
|
|||
list_banned::list_banned_users,
|
||||
list_logins::list_logins,
|
||||
list_media::list_media,
|
||||
list_saved::list_person_saved,
|
||||
login::login,
|
||||
logout::logout,
|
||||
notifications::{
|
||||
|
@ -341,7 +342,7 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) {
|
|||
.route("", get().to(read_person))
|
||||
.route("/content", get().to(list_person_content))
|
||||
// TODO move this to /account/saved after http routes
|
||||
// .route("/saved", get().to(read_person_saved))
|
||||
.route("/saved", get().to(list_person_saved))
|
||||
.route("/mention", get().to(list_mentions))
|
||||
.route(
|
||||
"/mention/mark_as_read",
|
||||
|
|
Loading…
Reference in a new issue