mirror of
https://github.com/LemmyNet/lemmy.git
synced 2025-09-03 11:43:51 +00:00
Move read only posts to its own endpoint. (#5610)
* migration * update code * tests * triggers * fix * fmt * clippy * post aggregate migration * changes for post aggregate code * wip: update tests for post aggregate * format * fix partialeq * trigger fix * fix post insert trigger * wip * reorder * fixes * community aggregate migration * update code * triggers * person aggregate migration * person aggregate code * person triggers * test fixes * fix scheduled task * update api tests * site_aggregates to local_site migration * site_aggregates code changes * triggers, tests * more fixes * Rename PersonPostAggregates to PostActions * Merge local_user_vote_display_mode into local_user * fix schema * Extracting pagination cursor utils into a trait. - Fixes #5275 * Refactoring to avoid stack overflows. * Fixing api_common feature. * Adding pagination for GetBannedPersons. - Must come after #5424 - Fixes #2847 * Starting to work on removing rest of page / limit. * Issues with community pagination. * Rename the traits and paginationcursor::new * remove duplicate fields * remove "aggregates" from index names * uncomment indices * if count = 0 * Using combined trait. * remove commentaggregates * Fix triggers in remove aggregates tables pr (#5451) * prevent all db_schema test errors * fix the delete_comments_before_post problem in a way that doesn't affect the returned number of affected rows * remove unnecessary recursion checks and add comment to remaining check * clean up * Fixing SQL format. * Update triggers.sql * Update triggers.sql * Update triggers.sql * Update triggers.sql * remove update of deleted column --------- Co-authored-by: Dessalines <tyhou13@gmx.com> * rename migration * Fix migration errors * Move community.hidden to visibility (fixes #5458) * Removing empty files. * Fixing person_saved_combined. (#5481) * Remove comment and post specific action structs. #5473 * Doing reports * fix up migration by dropping index * also add enum variant `LocalOnlyPublic`, rename `LocalOnly` to `LocalOnlyPrivate` fixes #5351 * fix column order in down.sql * wip * Moving blocks. * Adding a few more views. * more wip * fixes * migration for modlog * fix migration * Working views and schema. * Fix ts_optionals. * wip * db_schema compiling * make the code compile * Merging from main. * lint * Fixing SQL format. * fix down migration * Fixing api tests. * Adding field comments for the actions tables. * Refactoring CommunityFollower to include follow_state * fix test * make hidden status federate * ts attr * fix * fix api test * Update crates/api/src/reports/post_report/resolve.rs Co-authored-by: Nutomic <me@nutomic.com> * Addressing PR comments * Fix ts export. * update api client * review * Extracting filter_not_hidden_or_is_subscribed (#5497) * Extracting filter_not_hidden_or_is_subscribed * Cleanup. * Cleanup 2. * Remove follower_state_helper function. * Cleaning up some utils functions. * rename hidden to unlisted * Updating lemmy-js-client. * Fixing a few cases. * Fixing list_banned. * Starting to convert to lemmy results. * Fixing vote_view. * Close to finishing up errors. * Got compiling. * Remove tracing for CI. * Removing unused errors. * Fixing merge from main. * lower_name community_view sort. * Syntax errors. * Removing rest of Result from db_schema, db_views. * Finally compiling again. * fmt. * Subpath tries again. * Adding some more indexes./ * Fixing shear. * Fix keyword_blocks test. * @dullbananas fixes to Subpath, fixing comment tests. * sql fmt * Fixing unused error. * API test fixing * Moving read_only_posts to its own endpoint, sorted by read date. - Fixes #5505 * Adding a first_id helper function. * Fixing api_common * Addressing PR comments * Addressing PR comments 1. * Using id desc. * Addressing PR comments 2. * Removing the reverse_timestamp keys for the post table. * Make community_title and community_lower_name indexes desc * Remove featured_community from post sort * Forgot to drop index. * Addressing PR comments --------- Co-authored-by: Felix Ableitner <me@nutomic.com> Co-authored-by: dullbananas <dull.bananas0@gmail.com>
This commit is contained in:
parent
fe50d8ad67
commit
88dbf58373
6 changed files with 149 additions and 27 deletions
40
crates/api/src/local_user/list_read.rs
Normal file
40
crates/api/src/local_user/list_read.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
use activitypub_federation::config::Data;
|
||||
use actix_web::web::{Json, Query};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
person::{ListPersonRead, ListPersonReadResponse},
|
||||
};
|
||||
use lemmy_db_schema::source::post::PostActions;
|
||||
use lemmy_db_views_local_user::LocalUserView;
|
||||
use lemmy_db_views_post::PostView;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
pub async fn list_person_read(
|
||||
data: Query<ListPersonRead>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<ListPersonReadResponse>> {
|
||||
let cursor_data = if let Some(cursor) = &data.page_cursor {
|
||||
Some(PostActions::from_cursor(cursor, &mut context.pool()).await?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let read = PostView::list_read(
|
||||
&mut context.pool(),
|
||||
&local_user_view.person,
|
||||
cursor_data,
|
||||
data.page_back,
|
||||
data.limit,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let next_page = read.last().map(PostView::to_post_actions_cursor);
|
||||
let prev_page = read.first().map(PostView::to_post_actions_cursor);
|
||||
|
||||
Ok(Json(ListPersonReadResponse {
|
||||
read,
|
||||
next_page,
|
||||
prev_page,
|
||||
}))
|
||||
}
|
|
@ -9,6 +9,7 @@ pub mod get_captcha;
|
|||
pub mod list_banned;
|
||||
pub mod list_logins;
|
||||
pub mod list_media;
|
||||
pub mod list_read;
|
||||
pub mod list_saved;
|
||||
pub mod login;
|
||||
pub mod logout;
|
||||
|
|
|
@ -20,6 +20,7 @@ use lemmy_db_views_local_image::LocalImageView;
|
|||
use lemmy_db_views_person::PersonView;
|
||||
use lemmy_db_views_person_content_combined::PersonContentCombinedView;
|
||||
use lemmy_db_views_person_saved_combined::PersonSavedCombinedView;
|
||||
use lemmy_db_views_post::PostView;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::skip_serializing_none;
|
||||
#[cfg(feature = "full")]
|
||||
|
@ -312,6 +313,34 @@ pub struct ListPersonSavedResponse {
|
|||
pub prev_page: Option<PaginationCursor>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Gets your read posts.
|
||||
pub struct ListPersonRead {
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page_cursor: Option<PaginationCursor>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page_back: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// You read posts response.
|
||||
pub struct ListPersonReadResponse {
|
||||
pub read: Vec<PostView>,
|
||||
/// the pagination cursor to use to fetch the next page
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub next_page: Option<PaginationCursor>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub prev_page: Option<PaginationCursor>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
newtypes::{CommunityId, DbUrl, InstanceId, PersonId, PostId},
|
||||
newtypes::{CommunityId, DbUrl, InstanceId, PaginationCursor, PersonId, PostId},
|
||||
source::post::{
|
||||
Post,
|
||||
PostActions,
|
||||
|
@ -468,6 +468,18 @@ impl PostActions {
|
|||
.await
|
||||
.with_lemmy_type(LemmyErrorType::NotFound)
|
||||
}
|
||||
|
||||
pub async fn from_cursor(cursor: &PaginationCursor, pool: &mut DbPool<'_>) -> LemmyResult<Self> {
|
||||
let pids = cursor.prefixes_and_ids();
|
||||
let (_, person_id) = pids
|
||||
.as_slice()
|
||||
.first()
|
||||
.ok_or(LemmyErrorType::CouldntParsePaginationToken)?;
|
||||
let (_, post_id) = pids
|
||||
.get(1)
|
||||
.ok_or(LemmyErrorType::CouldntParsePaginationToken)?;
|
||||
Self::read(pool, PostId(*post_id), PersonId(*person_id)).await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -16,13 +16,14 @@ use diesel::{
|
|||
TextExpressionMethods,
|
||||
};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use i_love_jesus::asc_if;
|
||||
use i_love_jesus::{asc_if, SortDirection};
|
||||
use lemmy_db_schema::{
|
||||
impls::local_user::LocalUserOptionHelper,
|
||||
newtypes::{CommunityId, InstanceId, PaginationCursor, PersonId, PostId},
|
||||
source::{
|
||||
local_user::LocalUser,
|
||||
post::{post_keys as key, Post},
|
||||
person::Person,
|
||||
post::{post_actions_keys as pa_key, post_keys as key, Post, PostActions},
|
||||
site::Site,
|
||||
},
|
||||
traits::{Crud, PaginationCursorBuilder},
|
||||
|
@ -164,6 +165,44 @@ impl PostView {
|
|||
.with_lemmy_type(LemmyErrorType::NotFound)
|
||||
}
|
||||
|
||||
/// List all the read posts for your person, ordered by the read date.
|
||||
pub async fn list_read(
|
||||
pool: &mut DbPool<'_>,
|
||||
my_person: &Person,
|
||||
cursor_data: Option<PostActions>,
|
||||
page_back: Option<bool>,
|
||||
limit: Option<i64>,
|
||||
) -> LemmyResult<Vec<PostView>> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
let limit = limit_fetch(limit)?;
|
||||
|
||||
let query = PostView::joins(Some(my_person.id), my_person.instance_id)
|
||||
.filter(post_actions::person_id.eq(my_person.id))
|
||||
.filter(post_actions::read.is_not_null())
|
||||
.filter(filter_blocked())
|
||||
.select(PostView::as_select())
|
||||
.limit(limit)
|
||||
.into_boxed();
|
||||
|
||||
// Sorting by the read date
|
||||
let paginated_query = paginate(query, SortDirection::Desc, cursor_data, None, page_back)
|
||||
.then_order_by(pa_key::read)
|
||||
// Tie breaker
|
||||
.then_order_by(pa_key::post_id);
|
||||
|
||||
paginated_query
|
||||
.load::<Self>(conn)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::NotFound)
|
||||
}
|
||||
|
||||
pub fn to_post_actions_cursor(&self) -> PaginationCursor {
|
||||
// This needs a person and post
|
||||
let prefixes_and_ids = [('P', self.creator.id.0), ('O', self.post.id.0)];
|
||||
|
||||
PaginationCursor::new(&prefixes_and_ids)
|
||||
}
|
||||
|
||||
// TODO this function needs to be checked
|
||||
/// Prefetches an upper bound to build the cursor before data.
|
||||
pub async fn prefetch_cursor_before_data(
|
||||
|
@ -988,34 +1027,33 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// TODO these need to get moved to the post_read_list
|
||||
// #[test_context(Data)]
|
||||
// #[tokio::test]
|
||||
// #[serial]
|
||||
// async fn post_listing_read_only(data: &mut Data) -> LemmyResult<()> {
|
||||
// let pool = &data.pool();
|
||||
// let pool = &mut pool.into();
|
||||
#[test_context(Data)]
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn post_listing_read_only(data: &mut Data) -> LemmyResult<()> {
|
||||
let pool = &data.pool();
|
||||
let pool = &mut pool.into();
|
||||
|
||||
// // Only mark the bot post as read
|
||||
// // The read_only should only show the bot post
|
||||
// let post_read_form = PostReadForm::new(data.bot_post.id,
|
||||
// data.tegan_local_user_view.person.id); PostActions::mark_as_read(pool,
|
||||
// &post_read_form).await?;
|
||||
// Mark the bot post, then the tags post as read
|
||||
let bot_post_read_form =
|
||||
PostReadForm::new(data.bot_post.id, data.tegan_local_user_view.person.id);
|
||||
PostActions::mark_as_read(pool, &bot_post_read_form).await?;
|
||||
|
||||
// // Only read the post marked as read
|
||||
// let read_read_post_listing = PostQuery {
|
||||
// community_id: Some(data.community.id),
|
||||
// read_only: Some(true),
|
||||
// ..data.default_post_query()
|
||||
// }
|
||||
// .list(&data.site, pool)
|
||||
// .await?;
|
||||
let tag_post_read_form =
|
||||
PostReadForm::new(data.post_with_tags.id, data.tegan_local_user_view.person.id);
|
||||
PostActions::mark_as_read(pool, &tag_post_read_form).await?;
|
||||
|
||||
// // This should only include the bot post, not the one you created
|
||||
// assert_eq!(vec![POST_BY_BOT], names(&read_read_post_listing));
|
||||
let read_read_post_listing =
|
||||
PostView::list_read(pool, &data.tegan_local_user_view.person, None, None, None).await?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
// This should be ordered from most recently read
|
||||
assert_eq!(
|
||||
vec![POST_WITH_TAGS, POST_BY_BOT],
|
||||
names(&read_read_post_listing)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test_context(Data)]
|
||||
#[tokio::test]
|
||||
|
|
|
@ -32,6 +32,7 @@ use lemmy_api::{
|
|||
list_banned::list_banned_users,
|
||||
list_logins::list_logins,
|
||||
list_media::list_media,
|
||||
list_read::list_person_read,
|
||||
list_saved::list_person_saved,
|
||||
login::login,
|
||||
logout::logout,
|
||||
|
@ -367,6 +368,7 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) {
|
|||
.route("/instance", post().to(user_block_instance)),
|
||||
)
|
||||
.route("/saved", get().to(list_person_saved))
|
||||
.route("/read", get().to(list_person_read))
|
||||
.route("/settings/save", put().to(save_user_settings))
|
||||
// Account settings import / export have a strict rate limit
|
||||
.service(
|
||||
|
|
Loading…
Reference in a new issue