mirror of
https://github.com/LemmyNet/lemmy.git
synced 2025-01-05 17:53:48 +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>,
|
context: Data<LemmyContext>,
|
||||||
local_user_view: LocalUserView,
|
local_user_view: LocalUserView,
|
||||||
) -> LemmyResult<Json<CommentResponse>> {
|
) -> LemmyResult<Json<CommentResponse>> {
|
||||||
let comment_saved_form = CommentSavedForm {
|
let comment_saved_form = CommentSavedForm::new(data.comment_id, local_user_view.person.id);
|
||||||
comment_id: data.comment_id,
|
|
||||||
person_id: local_user_view.person.id,
|
|
||||||
};
|
|
||||||
|
|
||||||
if data.save {
|
if data.save {
|
||||||
CommentSaved::save(&mut context.pool(), &comment_saved_form)
|
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,
|
LocalImageView,
|
||||||
PersonContentCombinedPaginationCursor,
|
PersonContentCombinedPaginationCursor,
|
||||||
PersonContentCombinedView,
|
PersonContentCombinedView,
|
||||||
|
PersonSavedCombinedPaginationCursor,
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::{
|
use lemmy_db_views_actor::structs::{
|
||||||
CommentReplyView,
|
CommentReplyView,
|
||||||
|
@ -273,9 +274,9 @@ pub struct ListPersonContentResponse {
|
||||||
#[cfg_attr(feature = "full", derive(TS))]
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
/// Gets your saved posts and comments
|
/// Gets your saved posts and comments
|
||||||
pub struct ListSaved {
|
pub struct ListPersonSaved {
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
pub page_cursor: Option<PersonContentCombinedPaginationCursor>,
|
pub page_cursor: Option<PersonSavedCombinedPaginationCursor>,
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
pub page_back: Option<bool>,
|
pub page_back: Option<bool>,
|
||||||
}
|
}
|
||||||
|
@ -285,7 +286,7 @@ pub struct ListSaved {
|
||||||
#[cfg_attr(feature = "full", derive(TS))]
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
/// A person's saved content response.
|
/// A person's saved content response.
|
||||||
pub struct ListSavedResponse {
|
pub struct ListPersonSavedResponse {
|
||||||
pub saved: Vec<PersonContentCombinedView>,
|
pub saved: Vec<PersonContentCombinedView>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -212,10 +212,7 @@ pub async fn import_settings(
|
||||||
&context,
|
&context,
|
||||||
|(saved, context)| async move {
|
|(saved, context)| async move {
|
||||||
let comment = saved.dereference(&context).await?;
|
let comment = saved.dereference(&context).await?;
|
||||||
let form = CommentSavedForm {
|
let form = CommentSavedForm::new(comment.id, person_id);
|
||||||
person_id,
|
|
||||||
comment_id: comment.id,
|
|
||||||
};
|
|
||||||
CommentSaved::save(&mut context.pool(), &form).await?;
|
CommentSaved::save(&mut context.pool(), &form).await?;
|
||||||
LemmyResult::Ok(())
|
LemmyResult::Ok(())
|
||||||
},
|
},
|
||||||
|
|
|
@ -714,33 +714,74 @@ CALL r.create_person_content_combined_trigger ('post');
|
||||||
CALL r.create_person_content_combined_trigger ('comment');
|
CALL r.create_person_content_combined_trigger ('comment');
|
||||||
|
|
||||||
-- person_saved (comment, post)
|
-- person_saved (comment, post)
|
||||||
-- TODO, not sure how to handle changes to post_actions and comment_actions.saved column.
|
-- TODO, not sure how to handle changes to post_actions and comment_actions.saved column using @dullbanana's trigger method.
|
||||||
-- False should delete this row, true should insert
|
-- Post
|
||||||
-- CREATE PROCEDURE r.create_person_saved_combined_trigger (table_name text)
|
CREATE FUNCTION r.person_saved_combined_change_values_post ()
|
||||||
-- LANGUAGE plpgsql
|
RETURNS TRIGGER
|
||||||
-- AS $a$
|
LANGUAGE plpgsql
|
||||||
-- BEGIN
|
AS $$
|
||||||
-- EXECUTE replace($b$ CREATE FUNCTION r.person_saved_combined_thing_insert ( )
|
BEGIN
|
||||||
-- RETURNS TRIGGER
|
IF (TG_OP = 'DELETE') THEN
|
||||||
-- LANGUAGE plpgsql
|
DELETE FROM person_saved_combined AS p
|
||||||
-- AS $$
|
WHERE p.person_id = OLD.person_id
|
||||||
-- BEGIN
|
AND p.post_id = OLD.post_id;
|
||||||
-- INSERT INTO person_saved_combined (published, thing_id)
|
ELSIF (TG_OP = 'INSERT') THEN
|
||||||
-- VALUES (NEW.saved, NEW.id);
|
IF NEW.saved IS NOT NULL THEN
|
||||||
-- RETURN NEW;
|
INSERT INTO person_saved_combined (published, person_id, post_id)
|
||||||
-- END $$;
|
VALUES (NEW.saved, NEW.person_id, NEW.post_id);
|
||||||
-- CREATE TRIGGER person_saved_combined
|
END IF;
|
||||||
-- AFTER INSERT ON thing
|
ELSIF (TG_OP = 'UPDATE') THEN
|
||||||
-- FOR EACH ROW
|
IF NEW.saved IS NOT NULL THEN
|
||||||
-- EXECUTE FUNCTION r.person_saved_combined_thing_insert ( );
|
INSERT INTO person_saved_combined (published, person_id, post_id)
|
||||||
-- $b$,
|
VALUES (NEW.saved, NEW.person_id, NEW.post_id);
|
||||||
-- 'thing',
|
-- If saved gets set as null, delete the row
|
||||||
-- table_name);
|
ELSE
|
||||||
-- END;
|
DELETE FROM person_saved_combined AS p
|
||||||
-- $a$;
|
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,
|
comment_saved_form: &CommentSavedForm,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
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)
|
insert_into(comment_actions::table)
|
||||||
.values(comment_saved_form)
|
.values(comment_saved_form)
|
||||||
.on_conflict((comment_actions::comment_id, comment_actions::person_id))
|
.on_conflict((comment_actions::comment_id, comment_actions::person_id))
|
||||||
|
@ -319,11 +315,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Comment Saved
|
// Comment Saved
|
||||||
let comment_saved_form = CommentSavedForm {
|
let comment_saved_form = CommentSavedForm::new(inserted_comment.id, inserted_person.id);
|
||||||
comment_id: inserted_comment.id,
|
|
||||||
person_id: inserted_person.id,
|
|
||||||
};
|
|
||||||
|
|
||||||
let inserted_comment_saved = CommentSaved::save(pool, &comment_saved_form).await?;
|
let inserted_comment_saved = CommentSaved::save(pool, &comment_saved_form).await?;
|
||||||
|
|
||||||
let expected_comment_saved = CommentSaved {
|
let expected_comment_saved = CommentSaved {
|
||||||
|
|
|
@ -752,6 +752,7 @@ diesel::table! {
|
||||||
person_saved_combined (id) {
|
person_saved_combined (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
person_id -> Int4,
|
||||||
post_id -> Nullable<Int4>,
|
post_id -> Nullable<Int4>,
|
||||||
comment_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 -> comment (comment_id));
|
||||||
diesel::joinable!(person_mention -> person (recipient_id));
|
diesel::joinable!(person_mention -> person (recipient_id));
|
||||||
diesel::joinable!(person_saved_combined -> comment (comment_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!(person_saved_combined -> post (post_id));
|
||||||
diesel::joinable!(post -> community (community_id));
|
diesel::joinable!(post -> community (community_id));
|
||||||
diesel::joinable!(post -> language (language_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")]
|
#[cfg(feature = "full")]
|
||||||
use crate::schema::person_saved_combined;
|
use crate::schema::person_saved_combined;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
@ -23,6 +23,7 @@ use ts_rs::TS;
|
||||||
pub struct PersonSavedCombined {
|
pub struct PersonSavedCombined {
|
||||||
pub id: PersonSavedCombinedId,
|
pub id: PersonSavedCombinedId,
|
||||||
pub published: DateTime<Utc>,
|
pub published: DateTime<Utc>,
|
||||||
|
pub person_id: PersonId,
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
pub post_id: Option<PostId>,
|
pub post_id: Option<PostId>,
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
|
|
|
@ -142,7 +142,10 @@ pub struct CommentSaved {
|
||||||
|
|
||||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = comment_actions))]
|
#[cfg_attr(feature = "full", diesel(table_name = comment_actions))]
|
||||||
|
#[derive(derive_new::new)]
|
||||||
pub struct CommentSavedForm {
|
pub struct CommentSavedForm {
|
||||||
pub comment_id: CommentId,
|
pub comment_id: CommentId,
|
||||||
pub person_id: PersonId,
|
pub person_id: PersonId,
|
||||||
|
#[new(value = "Utc::now()")]
|
||||||
|
pub saved: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,8 +121,8 @@ impl PersonContentCombinedQuery {
|
||||||
person::table.on(
|
person::table.on(
|
||||||
comment::creator_id
|
comment::creator_id
|
||||||
.eq(item_creator)
|
.eq(item_creator)
|
||||||
// Need to filter out the post rows where both the post and comment creator are the
|
// Need to filter out the post rows where the post_id given is null
|
||||||
// same.
|
// Otherwise you'll get duped post rows
|
||||||
.or(
|
.or(
|
||||||
post::creator_id
|
post::creator_id
|
||||||
.eq(item_creator)
|
.eq(item_creator)
|
||||||
|
@ -372,7 +372,7 @@ mod tests {
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(3, timmy_content.len());
|
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] {
|
if let PersonContentCombinedView::Comment(v) = &timmy_content[0] {
|
||||||
assert_eq!(data.timmy_comment.id, v.comment.id);
|
assert_eq!(data.timmy_comment.id, v.comment.id);
|
||||||
assert_eq!(data.timmy.id, v.creator.id);
|
assert_eq!(data.timmy.id, v.creator.id);
|
||||||
|
|
|
@ -1,554 +1,393 @@
|
||||||
// use crate::{
|
use crate::{
|
||||||
// structs::{
|
structs::{
|
||||||
// CommentView,
|
LocalUserView,
|
||||||
// LocalUserView,
|
PersonContentCombinedView,
|
||||||
// PostView,
|
PersonContentViewInternal,
|
||||||
// ProfileCombinedPaginationCursor,
|
PersonSavedCombinedPaginationCursor,
|
||||||
// PersonContentCombinedView,
|
},
|
||||||
// PersonContentViewInternal,
|
InternalToCombinedView,
|
||||||
// },
|
};
|
||||||
// InternalToCombinedView,
|
use diesel::{
|
||||||
// };
|
result::Error,
|
||||||
// use diesel::{
|
BoolExpressionMethods,
|
||||||
// result::Error,
|
ExpressionMethods,
|
||||||
// BoolExpressionMethods,
|
JoinOnDsl,
|
||||||
// ExpressionMethods,
|
NullableExpressionMethods,
|
||||||
// JoinOnDsl,
|
QueryDsl,
|
||||||
// NullableExpressionMethods,
|
SelectableHelper,
|
||||||
// QueryDsl,
|
};
|
||||||
// SelectableHelper,
|
use diesel_async::RunQueryDsl;
|
||||||
// };
|
use i_love_jesus::PaginatedQueryBuilder;
|
||||||
// use diesel_async::RunQueryDsl;
|
use lemmy_db_schema::{
|
||||||
// use i_love_jesus::PaginatedQueryBuilder;
|
aliases::creator_community_actions,
|
||||||
// use lemmy_db_schema::{
|
schema::{
|
||||||
// aliases::creator_community_actions,
|
comment,
|
||||||
// newtypes::{CommunityId, PersonId},
|
comment_actions,
|
||||||
// schema::{
|
comment_aggregates,
|
||||||
// comment,
|
community,
|
||||||
// comment_actions,
|
community_actions,
|
||||||
// comment_aggregates,
|
image_details,
|
||||||
// community,
|
local_user,
|
||||||
// community_actions,
|
person,
|
||||||
// image_details,
|
person_actions,
|
||||||
// local_user,
|
person_saved_combined,
|
||||||
// person,
|
post,
|
||||||
// person_actions,
|
post_actions,
|
||||||
// post,
|
post_aggregates,
|
||||||
// post_actions,
|
},
|
||||||
// post_aggregates,
|
source::{
|
||||||
// profile_combined,
|
combined::person_saved::{person_saved_combined_keys as key, PersonSavedCombined},
|
||||||
// },
|
community::CommunityFollower,
|
||||||
// source::{
|
},
|
||||||
// combined::profile::{profile_combined_keys as key, ProfileCombined},
|
utils::{actions, actions_alias, functions::coalesce, get_conn, DbPool},
|
||||||
// community::CommunityFollower,
|
};
|
||||||
// },
|
use lemmy_utils::error::LemmyResult;
|
||||||
// utils::{actions, actions_alias, functions::coalesce, get_conn, DbPool, ReverseTimestampKey},
|
|
||||||
// };
|
|
||||||
// use lemmy_utils::error::LemmyResult;
|
|
||||||
|
|
||||||
// impl ProfileCombinedPaginationCursor {
|
impl PersonSavedCombinedPaginationCursor {
|
||||||
// // get cursor for page that starts immediately after the given post
|
// get cursor for page that starts immediately after the given post
|
||||||
// pub fn after_post(view: &PersonContentCombinedView) -> ProfileCombinedPaginationCursor {
|
pub fn after_post(view: &PersonContentCombinedView) -> PersonSavedCombinedPaginationCursor {
|
||||||
// let (prefix, id) = match view {
|
let (prefix, id) = match view {
|
||||||
// PersonContentCombinedView::Comment(v) => ('C', v.comment.id.0),
|
PersonContentCombinedView::Comment(v) => ('C', v.comment.id.0),
|
||||||
// PersonContentCombinedView::Post(v) => ('P', v.post.id.0),
|
PersonContentCombinedView::Post(v) => ('P', v.post.id.0),
|
||||||
// };
|
};
|
||||||
// // hex encoding to prevent ossification
|
// hex encoding to prevent ossification
|
||||||
// ProfileCombinedPaginationCursor(format!("{prefix}{id:x}"))
|
PersonSavedCombinedPaginationCursor(format!("{prefix}{id:x}"))
|
||||||
// }
|
}
|
||||||
|
|
||||||
// pub async fn read(&self, pool: &mut DbPool<'_>) -> Result<PaginationCursorData, Error> {
|
pub async fn read(&self, pool: &mut DbPool<'_>) -> Result<PaginationCursorData, Error> {
|
||||||
// let err_msg = || Error::QueryBuilderError("Could not parse pagination token".into());
|
let err_msg = || Error::QueryBuilderError("Could not parse pagination token".into());
|
||||||
// let mut query = profile_combined::table
|
let mut query = person_saved_combined::table
|
||||||
// .select(ProfileCombined::as_select())
|
.select(PersonSavedCombined::as_select())
|
||||||
// .into_boxed();
|
.into_boxed();
|
||||||
// let (prefix, id_str) = self.0.split_at_checked(1).ok_or_else(err_msg)?;
|
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())?;
|
let id = i32::from_str_radix(id_str, 16).map_err(|_err| err_msg())?;
|
||||||
// query = match prefix {
|
query = match prefix {
|
||||||
// "C" => query.filter(profile_combined::comment_id.eq(id)),
|
"C" => query.filter(person_saved_combined::comment_id.eq(id)),
|
||||||
// "P" => query.filter(profile_combined::post_id.eq(id)),
|
"P" => query.filter(person_saved_combined::post_id.eq(id)),
|
||||||
// _ => return Err(err_msg()),
|
_ => return Err(err_msg()),
|
||||||
// };
|
};
|
||||||
// let token = query.first(&mut get_conn(pool).await?).await?;
|
let token = query.first(&mut get_conn(pool).await?).await?;
|
||||||
|
|
||||||
// Ok(PaginationCursorData(token))
|
Ok(PaginationCursorData(token))
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// #[derive(Clone)]
|
#[derive(Clone)]
|
||||||
// pub struct PaginationCursorData(ProfileCombined);
|
pub struct PaginationCursorData(PersonSavedCombined);
|
||||||
|
|
||||||
// #[derive(Default)]
|
#[derive(Default)]
|
||||||
// pub struct ProfileCombinedQuery {
|
pub struct PersonSavedCombinedQuery {
|
||||||
// pub creator_id: PersonId,
|
pub page_after: Option<PaginationCursorData>,
|
||||||
// pub page_after: Option<PaginationCursorData>,
|
pub page_back: Option<bool>,
|
||||||
// pub page_back: Option<bool>,
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// impl ProfileCombinedQuery {
|
impl PersonSavedCombinedQuery {
|
||||||
// pub async fn list(
|
pub async fn list(
|
||||||
// self,
|
self,
|
||||||
// pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
// user: &Option<LocalUserView>,
|
user: &LocalUserView,
|
||||||
// ) -> LemmyResult<Vec<PersonContentCombinedView>> {
|
) -> LemmyResult<Vec<PersonContentCombinedView>> {
|
||||||
// let my_person_id = user
|
let my_person_id = user.local_user.person_id;
|
||||||
// .as_ref()
|
let item_creator = person::id;
|
||||||
// .map(|u| u.local_user.person_id)
|
|
||||||
// .unwrap_or(PersonId(-1));
|
|
||||||
// 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,
|
// Notes: since the post_id and comment_id are optional columns,
|
||||||
// // many joins must use an OR condition.
|
// many joins must use an OR condition.
|
||||||
// // For example, the creator must be the person table joined to either:
|
// For example, the creator must be the person table joined to either:
|
||||||
// // - post.creator_id
|
// - post.creator_id
|
||||||
// // - comment.creator_id
|
// - comment.creator_id
|
||||||
// let mut query = profile_combined::table
|
let query = person_saved_combined::table
|
||||||
// // The comment
|
// The comment
|
||||||
// .left_join(comment::table.on(profile_combined::comment_id.eq(comment::id.nullable())))
|
.left_join(comment::table.on(person_saved_combined::comment_id.eq(comment::id.nullable())))
|
||||||
// // The post
|
// The post
|
||||||
// .inner_join(
|
// It gets a bit complicated here, because since both comments and post combined have a post
|
||||||
// post::table.on(
|
// attached, you can do an inner join.
|
||||||
// profile_combined::post_id
|
.inner_join(
|
||||||
// .eq(post::id.nullable())
|
post::table.on(
|
||||||
// .or(comment::post_id.nullable().eq(profile_combined::post_id)),
|
person_saved_combined::post_id
|
||||||
// ),
|
.eq(post::id.nullable())
|
||||||
// )
|
.or(comment::post_id.eq(post::id)),
|
||||||
// // The item creator
|
),
|
||||||
// .inner_join(
|
)
|
||||||
// person::table.on(
|
// The item creator
|
||||||
// comment::creator_id
|
.inner_join(
|
||||||
// .eq(person::id)
|
person::table.on(
|
||||||
// .or(post::creator_id.eq(person::id)),
|
comment::creator_id
|
||||||
// ),
|
.eq(item_creator)
|
||||||
// )
|
// Need to filter out the post rows where the post_id given is null
|
||||||
// // The community
|
// Otherwise you'll get duped post rows
|
||||||
// .inner_join(community::table.on(post::community_id.eq(community::id)))
|
.or(
|
||||||
// .left_join(actions_alias(
|
post::creator_id
|
||||||
// creator_community_actions,
|
.eq(item_creator)
|
||||||
// item_creator,
|
.and(person_saved_combined::post_id.is_not_null()),
|
||||||
// post::community_id,
|
),
|
||||||
// ))
|
),
|
||||||
// .left_join(
|
)
|
||||||
// local_user::table.on(
|
// The community
|
||||||
// item_creator
|
.inner_join(community::table.on(post::community_id.eq(community::id)))
|
||||||
// .eq(local_user::person_id)
|
.left_join(actions_alias(
|
||||||
// .and(local_user::admin.eq(true)),
|
creator_community_actions,
|
||||||
// ),
|
item_creator,
|
||||||
// )
|
post::community_id,
|
||||||
// .left_join(actions(
|
))
|
||||||
// community_actions::table,
|
.left_join(
|
||||||
// Some(my_person_id),
|
local_user::table.on(
|
||||||
// post::community_id,
|
item_creator
|
||||||
// ))
|
.eq(local_user::person_id)
|
||||||
// .left_join(actions(post_actions::table, Some(my_person_id), post::id))
|
.and(local_user::admin.eq(true)),
|
||||||
// .left_join(actions(
|
),
|
||||||
// person_actions::table,
|
)
|
||||||
// Some(my_person_id),
|
.left_join(actions(
|
||||||
// item_creator,
|
community_actions::table,
|
||||||
// ))
|
Some(my_person_id),
|
||||||
// .inner_join(post_aggregates::table.on(post::id.eq(post_aggregates::post_id)))
|
post::community_id,
|
||||||
// .left_join(
|
))
|
||||||
// comment_aggregates::table
|
.left_join(actions(post_actions::table, Some(my_person_id), post::id))
|
||||||
// .on(profile_combined::comment_id.eq(comment_aggregates::comment_id.nullable())),
|
.left_join(actions(
|
||||||
// )
|
person_actions::table,
|
||||||
// .left_join(actions(
|
Some(my_person_id),
|
||||||
// comment_actions::table,
|
item_creator,
|
||||||
// Some(my_person_id),
|
))
|
||||||
// comment::id,
|
.inner_join(post_aggregates::table.on(post::id.eq(post_aggregates::post_id)))
|
||||||
// ))
|
.left_join(
|
||||||
// .left_join(image_details::table.on(post::thumbnail_url.eq(image_details::link.nullable())))
|
comment_aggregates::table
|
||||||
// // The creator id filter
|
.on(person_saved_combined::comment_id.eq(comment_aggregates::comment_id.nullable())),
|
||||||
// .filter(item_creator.eq(self.creator_id))
|
)
|
||||||
// .select((
|
.left_join(actions(
|
||||||
// // Post-specific
|
comment_actions::table,
|
||||||
// post_aggregates::all_columns,
|
Some(my_person_id),
|
||||||
// coalesce(
|
comment::id,
|
||||||
// post_aggregates::comments.nullable() - post_actions::read_comments_amount.nullable(),
|
))
|
||||||
// post_aggregates::comments,
|
.left_join(image_details::table.on(post::thumbnail_url.eq(image_details::link.nullable())))
|
||||||
// ),
|
// The person id filter
|
||||||
// post_actions::saved.nullable().is_not_null(),
|
.filter(person_saved_combined::person_id.eq(my_person_id))
|
||||||
// post_actions::read.nullable().is_not_null(),
|
.select((
|
||||||
// post_actions::hidden.nullable().is_not_null(),
|
// Post-specific
|
||||||
// post_actions::like_score.nullable(),
|
post_aggregates::all_columns,
|
||||||
// image_details::all_columns.nullable(),
|
coalesce(
|
||||||
// // Comment-specific
|
post_aggregates::comments.nullable() - post_actions::read_comments_amount.nullable(),
|
||||||
// comment::all_columns.nullable(),
|
post_aggregates::comments,
|
||||||
// comment_aggregates::all_columns.nullable(),
|
),
|
||||||
// comment_actions::saved.nullable().is_not_null(),
|
post_actions::saved.nullable().is_not_null(),
|
||||||
// comment_actions::like_score.nullable(),
|
post_actions::read.nullable().is_not_null(),
|
||||||
// // Shared
|
post_actions::hidden.nullable().is_not_null(),
|
||||||
// post::all_columns,
|
post_actions::like_score.nullable(),
|
||||||
// community::all_columns,
|
image_details::all_columns.nullable(),
|
||||||
// person::all_columns,
|
// Comment-specific
|
||||||
// CommunityFollower::select_subscribed_type(),
|
comment::all_columns.nullable(),
|
||||||
// local_user::admin.nullable().is_not_null(),
|
comment_aggregates::all_columns.nullable(),
|
||||||
// creator_community_actions
|
comment_actions::saved.nullable().is_not_null(),
|
||||||
// .field(community_actions::became_moderator)
|
comment_actions::like_score.nullable(),
|
||||||
// .nullable()
|
// Shared
|
||||||
// .is_not_null(),
|
post::all_columns,
|
||||||
// creator_community_actions
|
community::all_columns,
|
||||||
// .field(community_actions::received_ban)
|
person::all_columns,
|
||||||
// .nullable()
|
CommunityFollower::select_subscribed_type(),
|
||||||
// .is_not_null(),
|
local_user::admin.nullable().is_not_null(),
|
||||||
// person_actions::blocked.nullable().is_not_null(),
|
creator_community_actions
|
||||||
// community_actions::received_ban.nullable().is_not_null(),
|
.field(community_actions::became_moderator)
|
||||||
// ))
|
.nullable()
|
||||||
// .into_boxed();
|
.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() {
|
if self.page_back.unwrap_or_default() {
|
||||||
// query = query.before(page_after).limit_and_offset_from_end();
|
query = query.before(page_after).limit_and_offset_from_end();
|
||||||
// } else {
|
} else {
|
||||||
// query = query.after(page_after);
|
query = query.after(page_after);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // Sorting by published
|
// Sorting by published
|
||||||
// query = query
|
query = query
|
||||||
// .then_desc(ReverseTimestampKey(key::published))
|
.then_desc(key::published)
|
||||||
// // Tie breaker
|
// Tie breaker
|
||||||
// .then_desc(key::id);
|
.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
|
// Map the query results to the enum
|
||||||
// let out = res.into_iter().filter_map(|u| u.map_to_enum()).collect();
|
let out = res.into_iter().filter_map(|u| u.map_to_enum()).collect();
|
||||||
|
|
||||||
// Ok(out)
|
Ok(out)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// impl InternalToCombinedView for PersonContentViewInternal {
|
#[cfg(test)]
|
||||||
// type CombinedView = PersonContentCombinedView;
|
#[expect(clippy::indexing_slicing)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
// fn map_to_enum(&self) -> Option<Self::CombinedView> {
|
use crate::{
|
||||||
// // Use for a short alias
|
person_saved_combined_view::PersonSavedCombinedQuery,
|
||||||
// let v = self.clone();
|
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) {
|
struct Data {
|
||||||
// Some(PersonContentCombinedView::Comment(CommentView {
|
instance: Instance,
|
||||||
// comment,
|
timmy: Person,
|
||||||
// counts,
|
timmy_view: LocalUserView,
|
||||||
// post: v.post,
|
sara: Person,
|
||||||
// community: v.community,
|
timmy_post: Post,
|
||||||
// creator: v.item_creator,
|
sara_comment: Comment,
|
||||||
// creator_banned_from_community: v.item_creator_banned_from_community,
|
sara_comment_2: Comment,
|
||||||
// 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,
|
|
||||||
// }))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[cfg(test)]
|
async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
|
||||||
// #[expect(clippy::indexing_slicing)]
|
let instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||||
// mod tests {
|
|
||||||
|
|
||||||
// use crate::{
|
let timmy_form = PersonInsertForm::test_form(instance.id, "timmy_pcv");
|
||||||
// profile_combined_view::ProfileCombinedQuery,
|
let timmy = Person::create(pool, &timmy_form).await?;
|
||||||
// report_combined_view::ReportCombinedQuery,
|
let timmy_local_user_form = LocalUserInsertForm::test_form(timmy.id);
|
||||||
// structs::{
|
let timmy_local_user = LocalUser::create(pool, &timmy_local_user_form, vec![]).await?;
|
||||||
// CommentReportView,
|
let timmy_view = LocalUserView {
|
||||||
// LocalUserView,
|
local_user: timmy_local_user,
|
||||||
// PostReportView,
|
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||||
// PersonContentCombinedView,
|
person: timmy.clone(),
|
||||||
// ReportCombinedView,
|
counts: Default::default(),
|
||||||
// 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;
|
|
||||||
|
|
||||||
// struct Data {
|
let sara_form = PersonInsertForm::test_form(instance.id, "sara_pcv");
|
||||||
// instance: Instance,
|
let sara = Person::create(pool, &sara_form).await?;
|
||||||
// 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,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
|
let community_form = CommunityInsertForm::new(
|
||||||
// let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
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 timmy_post_form = PostInsertForm::new("timmy post prv".into(), timmy.id, community.id);
|
||||||
// let inserted_timmy = Person::create(pool, &timmy_form).await?;
|
let timmy_post = Post::create(pool, &timmy_post_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 sara_form = PersonInsertForm::test_form(inserted_instance.id, "sara_pcv");
|
let timmy_post_form_2 = PostInsertForm::new("timmy post prv 2".into(), timmy.id, community.id);
|
||||||
// let inserted_sara = Person::create(pool, &sara_form).await?;
|
let timmy_post_2 = Post::create(pool, &timmy_post_form_2).await?;
|
||||||
|
|
||||||
// let community_form = CommunityInsertForm::new(
|
let sara_post_form = PostInsertForm::new("sara post prv".into(), sara.id, community.id);
|
||||||
// inserted_instance.id,
|
let _sara_post = Post::create(pool, &sara_post_form).await?;
|
||||||
// "test community pcv".to_string(),
|
|
||||||
// "nada".to_owned(),
|
|
||||||
// "pubkey".to_string(),
|
|
||||||
// );
|
|
||||||
// let inserted_community = Community::create(pool, &community_form).await?;
|
|
||||||
|
|
||||||
// let timmy_post_form = PostInsertForm::new(
|
let timmy_comment_form =
|
||||||
// "timmy post prv".into(),
|
CommentInsertForm::new(timmy.id, timmy_post.id, "timmy comment prv".into());
|
||||||
// inserted_timmy.id,
|
let _timmy_comment = Comment::create(pool, &timmy_comment_form, None).await?;
|
||||||
// inserted_community.id,
|
|
||||||
// );
|
|
||||||
// let timmy_post = Post::create(pool, &timmy_post_form).await?;
|
|
||||||
|
|
||||||
// let timmy_post_form_2 = PostInsertForm::new(
|
let sara_comment_form =
|
||||||
// "timmy post prv 2".into(),
|
CommentInsertForm::new(sara.id, timmy_post.id, "sara comment prv".into());
|
||||||
// inserted_timmy.id,
|
let sara_comment = Comment::create(pool, &sara_comment_form, None).await?;
|
||||||
// inserted_community.id,
|
|
||||||
// );
|
|
||||||
// let timmy_post_2 = Post::create(pool, &timmy_post_form_2).await?;
|
|
||||||
|
|
||||||
// let sara_post_form = PostInsertForm::new(
|
let sara_comment_form_2 =
|
||||||
// "sara post prv".into(),
|
CommentInsertForm::new(sara.id, timmy_post_2.id, "sara comment prv 2".into());
|
||||||
// inserted_sara.id,
|
let sara_comment_2 = Comment::create(pool, &sara_comment_form_2, None).await?;
|
||||||
// inserted_community.id,
|
|
||||||
// );
|
|
||||||
// let sara_post = Post::create(pool, &sara_post_form).await?;
|
|
||||||
|
|
||||||
// let timmy_comment_form =
|
Ok(Data {
|
||||||
// CommentInsertForm::new(inserted_timmy.id, timmy_post.id, "timmy comment prv".into());
|
instance,
|
||||||
// let timmy_comment = Comment::create(pool, &timmy_comment_form, None).await?;
|
timmy,
|
||||||
|
timmy_view,
|
||||||
|
sara,
|
||||||
|
timmy_post,
|
||||||
|
sara_comment,
|
||||||
|
sara_comment_2,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// let sara_comment_form =
|
async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
|
||||||
// CommentInsertForm::new(inserted_sara.id, timmy_post.id, "sara comment prv".into());
|
Instance::delete(pool, data.instance.id).await?;
|
||||||
// let sara_comment = Comment::create(pool, &sara_comment_form, None).await?;
|
|
||||||
|
|
||||||
// let sara_comment_form_2 = CommentInsertForm::new(
|
Ok(())
|
||||||
// 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(Data {
|
#[tokio::test]
|
||||||
// instance: inserted_instance,
|
#[serial]
|
||||||
// timmy: inserted_timmy,
|
async fn test_combined() -> LemmyResult<()> {
|
||||||
// sara: inserted_sara,
|
let pool = &build_db_pool_for_tests();
|
||||||
// timmy_view,
|
let pool = &mut pool.into();
|
||||||
// community: inserted_community,
|
let data = init_data(pool).await?;
|
||||||
// timmy_post,
|
|
||||||
// timmy_post_2,
|
|
||||||
// sara_post,
|
|
||||||
// timmy_comment,
|
|
||||||
// sara_comment,
|
|
||||||
// sara_comment_2,
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
|
// Do a batch read of timmy saved
|
||||||
// Instance::delete(pool, data.instance.id).await?;
|
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]
|
let save_sara_comment = CommentSavedForm::new(data.sara_comment.id, data.timmy_view.person.id);
|
||||||
// #[serial]
|
CommentSaved::save(pool, &save_sara_comment).await?;
|
||||||
// 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 post_save_form = PostSavedForm::new(data.timmy_post.id, data.timmy.id);
|
||||||
// let timmy_content = ProfileCombinedQuery::default().list(pool, &None).await?;
|
PostSaved::save(pool, &post_save_form).await?;
|
||||||
// assert_eq!(3, timmy_content.len());
|
|
||||||
|
|
||||||
// // Make sure the report types are correct
|
let timmy_saved = PersonSavedCombinedQuery::default()
|
||||||
// if let PersonContentCombinedView::Comment(v) = &timmy_content[0] {
|
.list(pool, &data.timmy_view)
|
||||||
// assert_eq!(data.timmy_comment.id, v.comment.id);
|
.await?;
|
||||||
// assert_eq!(data.timmy.id, v.creator.id);
|
assert_eq!(3, timmy_saved.len());
|
||||||
// } 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");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Do a batch read of sara
|
// Make sure the types and order are correct
|
||||||
// let sara_content = ProfileCombinedQuery::default().list(pool, &None).await?;
|
if let PersonContentCombinedView::Post(v) = &timmy_saved[0] {
|
||||||
// assert_eq!(3, sara_content.len());
|
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
|
// Try unsaving 2 things
|
||||||
// if let PersonContentCombinedView::Comment(v) = &sara_content[0] {
|
CommentSaved::unsave(pool, &save_sara_comment).await?;
|
||||||
// assert_eq!(data.sara_comment_2.id, v.comment.id);
|
PostSaved::unsave(pool, &post_save_form).await?;
|
||||||
// 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");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Timmy saves sara's comment, and his 2nd post
|
let timmy_saved = PersonSavedCombinedQuery::default()
|
||||||
// let save_comment_0_form = CommentSavedForm {
|
.list(pool, &data.timmy_view)
|
||||||
// person_id: data.timmy.id,
|
.await?;
|
||||||
// comment_id: data.sara_comment.id,
|
assert_eq!(1, timmy_saved.len());
|
||||||
// };
|
|
||||||
// CommentSaved::save(pool, &save_comment_0_form).await?;
|
|
||||||
|
|
||||||
// // Timmy saves sara's comment, and his 2nd post
|
if let PersonContentCombinedView::Comment(v) = &timmy_saved[0] {
|
||||||
// let save_comment_0_form = CommentSavedForm {
|
assert_eq!(data.sara_comment_2.id, v.comment.id);
|
||||||
// person_id: data.timmy.id,
|
assert_eq!(data.sara.id, v.comment.creator_id);
|
||||||
// comment_id: data.sara_comment.id,
|
} else {
|
||||||
// };
|
panic!("wrong type");
|
||||||
// CommentSaved::save(pool, &save_comment_0_form).await?;
|
}
|
||||||
|
|
||||||
// // Do a saved_only query
|
cleanup(data, pool).await?;
|
||||||
// let timmy_content_saved_only = ProfileCombinedQuery {}.list(pool, &None).await?;
|
|
||||||
|
|
||||||
// cleanup(data, pool).await?;
|
Ok(())
|
||||||
|
}
|
||||||
// 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
|
|
||||||
// }
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
DROP TABLE person_content_combined;
|
DROP TABLE person_content_combined;
|
||||||
|
|
||||||
DROP TABLE person_saved_combined;
|
DROP TABLE person_saved_combined;
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ FROM
|
||||||
CREATE TABLE person_saved_combined (
|
CREATE TABLE person_saved_combined (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
published timestamptz NOT NULL,
|
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,
|
post_id int UNIQUE REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
comment_id int UNIQUE REFERENCES COMMENT 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
|
-- 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_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
|
-- Updating the history
|
||||||
INSERT INTO person_saved_combined (published, post_id)
|
INSERT INTO person_saved_combined (published, person_id, post_id)
|
||||||
SELECT
|
SELECT
|
||||||
saved,
|
saved,
|
||||||
|
person_id,
|
||||||
post_id
|
post_id
|
||||||
FROM
|
FROM
|
||||||
post_actions
|
post_actions
|
||||||
WHERE
|
WHERE
|
||||||
saved IS NOT NULL;
|
saved IS NOT NULL;
|
||||||
|
|
||||||
INSERT INTO person_saved_combined (published, comment_id)
|
INSERT INTO person_saved_combined (published, person_id, comment_id)
|
||||||
SELECT
|
SELECT
|
||||||
saved,
|
saved,
|
||||||
|
person_id,
|
||||||
comment_id
|
comment_id
|
||||||
FROM
|
FROM
|
||||||
comment_actions
|
comment_actions
|
||||||
WHERE
|
WHERE
|
||||||
saved IS NOT NULL;
|
saved IS NOT NULL;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ use lemmy_api::{
|
||||||
list_banned::list_banned_users,
|
list_banned::list_banned_users,
|
||||||
list_logins::list_logins,
|
list_logins::list_logins,
|
||||||
list_media::list_media,
|
list_media::list_media,
|
||||||
|
list_saved::list_person_saved,
|
||||||
login::login,
|
login::login,
|
||||||
logout::logout,
|
logout::logout,
|
||||||
notifications::{
|
notifications::{
|
||||||
|
@ -341,7 +342,7 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) {
|
||||||
.route("", get().to(read_person))
|
.route("", get().to(read_person))
|
||||||
.route("/content", get().to(list_person_content))
|
.route("/content", get().to(list_person_content))
|
||||||
// TODO move this to /account/saved after http routes
|
// 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", get().to(list_mentions))
|
||||||
.route(
|
.route(
|
||||||
"/mention/mark_as_read",
|
"/mention/mark_as_read",
|
||||||
|
|
Loading…
Reference in a new issue