mirror of
https://github.com/LemmyNet/lemmy.git
synced 2025-09-02 19:23:49 +00:00
Adding a variable time_range_limit, rather than having many post sorts like TopSixHours
(#5403)
* Adding a variable time_range_seconds. #4340 * Adding default_post_time_range_seconds columns to local_user and site. * Fixing ts-bindings. * Fixing API comments. * Update crates/db_schema/src/utils.rs Co-authored-by: dullbananas <dull.bananas0@gmail.com> * Add zero means override, to list_posts default time range. --------- Co-authored-by: dullbananas <dull.bananas0@gmail.com>
This commit is contained in:
parent
56ed92ca92
commit
16ba42c152
24 changed files with 303 additions and 54 deletions
|
@ -19,7 +19,7 @@ use lemmy_db_schema::{
|
|||
person::{Person, PersonUpdateForm},
|
||||
},
|
||||
traits::Crud,
|
||||
utils::diesel_string_update,
|
||||
utils::{diesel_opt_number_update, diesel_string_update},
|
||||
};
|
||||
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
||||
use lemmy_utils::{
|
||||
|
@ -90,6 +90,8 @@ pub async fn save_user_settings(
|
|||
let person_id = local_user_view.person.id;
|
||||
let default_listing_type = data.default_listing_type;
|
||||
let default_post_sort_type = data.default_post_sort_type;
|
||||
let default_post_time_range_seconds =
|
||||
diesel_opt_number_update(data.default_post_time_range_seconds);
|
||||
let default_comment_sort_type = data.default_comment_sort_type;
|
||||
|
||||
let person_form = PersonUpdateForm {
|
||||
|
@ -119,6 +121,7 @@ pub async fn save_user_settings(
|
|||
blur_nsfw: data.blur_nsfw,
|
||||
show_bot_accounts: data.show_bot_accounts,
|
||||
default_post_sort_type,
|
||||
default_post_time_range_seconds,
|
||||
default_comment_sort_type,
|
||||
default_listing_type,
|
||||
theme: data.theme.clone(),
|
||||
|
|
|
@ -117,6 +117,10 @@ pub struct GetComments {
|
|||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sort: Option<CommentSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
/// Filter to within a given time range, in seconds.
|
||||
/// IE 60 would give results for the past minute.
|
||||
pub time_range_seconds: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub max_depth: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
|
|
|
@ -97,6 +97,10 @@ pub struct ListCommunities {
|
|||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sort: Option<CommunitySortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
/// Filter to within a given time range, in seconds.
|
||||
/// IE 60 would give results for the past minute.
|
||||
pub time_range_seconds: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub show_nsfw: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
|
|
|
@ -120,6 +120,9 @@ pub struct SaveUserSettings {
|
|||
/// The default post sort, usually "active"
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_post_sort_type: Option<PostSortType>,
|
||||
/// A default time range limit to apply to post sorts, in seconds. 0 means none.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_post_time_range_seconds: Option<i32>,
|
||||
/// The default comment sort, usually "hot"
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_comment_sort_type: Option<CommentSortType>,
|
||||
|
|
|
@ -92,6 +92,11 @@ pub struct GetPosts {
|
|||
pub type_: Option<ListingType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sort: Option<PostSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
/// Filter to within a given time range, in seconds.
|
||||
/// IE 60 would give results for the past minute.
|
||||
/// Use Zero to override the local_site and local_user time_range.
|
||||
pub time_range_seconds: Option<i32>,
|
||||
/// DEPRECATED, use page_cursor
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
|
|
|
@ -69,6 +69,10 @@ pub struct Search {
|
|||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sort: Option<SearchSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
/// Filter to within a given time range, in seconds.
|
||||
/// IE 60 would give results for the past minute.
|
||||
pub time_range_seconds: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub listing_type: Option<ListingType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub title_only: Option<bool>,
|
||||
|
@ -189,6 +193,8 @@ pub struct CreateSite {
|
|||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_post_sort_type: Option<PostSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_post_time_range_seconds: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_comment_sort_type: Option<CommentSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub legal_information: Option<String>,
|
||||
|
@ -288,6 +294,9 @@ pub struct EditSite {
|
|||
/// The default post sort, usually "active"
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_post_sort_type: Option<PostSortType>,
|
||||
/// A default time range limit to apply to post sorts, in seconds. 0 means none.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_post_time_range_seconds: Option<i32>,
|
||||
/// The default comment sort, usually "hot"
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_comment_sort_type: Option<CommentSortType>,
|
||||
|
|
|
@ -24,15 +24,18 @@ pub async fn list_communities(
|
|||
check_private_instance(&local_user_view, &local_site.local_site)?;
|
||||
|
||||
let sort = data.sort;
|
||||
let time_range_seconds = data.time_range_seconds;
|
||||
let listing_type = data.type_;
|
||||
let show_nsfw = data.show_nsfw.unwrap_or_default();
|
||||
let page = data.page;
|
||||
let limit = data.limit;
|
||||
let local_user = local_user_view.map(|l| l.local_user);
|
||||
|
||||
let communities = CommunityQuery {
|
||||
listing_type,
|
||||
show_nsfw,
|
||||
sort,
|
||||
time_range_seconds,
|
||||
local_user: local_user.as_ref(),
|
||||
page,
|
||||
limit,
|
||||
|
|
|
@ -24,7 +24,7 @@ use lemmy_db_schema::{
|
|||
site::{Site, SiteUpdateForm},
|
||||
},
|
||||
traits::Crud,
|
||||
utils::diesel_string_update,
|
||||
utils::{diesel_opt_number_update, diesel_string_update},
|
||||
RegistrationMode,
|
||||
};
|
||||
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
||||
|
@ -68,6 +68,8 @@ pub async fn update_site(
|
|||
.await?
|
||||
.as_deref(),
|
||||
);
|
||||
let default_post_time_range_seconds =
|
||||
diesel_opt_number_update(data.default_post_time_range_seconds);
|
||||
|
||||
let site_form = SiteUpdateForm {
|
||||
name: data.name.clone(),
|
||||
|
@ -93,6 +95,7 @@ pub async fn update_site(
|
|||
default_theme: data.default_theme.clone(),
|
||||
default_post_listing_type: data.default_post_listing_type,
|
||||
default_post_sort_type: data.default_post_sort_type,
|
||||
default_post_time_range_seconds,
|
||||
default_comment_sort_type: data.default_comment_sort_type,
|
||||
legal_information: diesel_string_update(data.legal_information.as_deref()),
|
||||
application_email_admins: data.application_email_admins,
|
||||
|
|
|
@ -45,6 +45,7 @@ async fn list_comments_common(
|
|||
local_user_ref,
|
||||
&site_view.local_site,
|
||||
));
|
||||
let time_range_seconds = data.time_range_seconds;
|
||||
let max_depth = data.max_depth;
|
||||
|
||||
let liked_only = data.liked_only;
|
||||
|
@ -76,6 +77,7 @@ async fn list_comments_common(
|
|||
CommentQuery {
|
||||
listing_type,
|
||||
sort,
|
||||
time_range_seconds,
|
||||
max_depth,
|
||||
liked_only,
|
||||
disliked_only,
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
use crate::{
|
||||
api::{listing_type_with_default, post_sort_type_with_default},
|
||||
api::{
|
||||
listing_type_with_default,
|
||||
post_sort_type_with_default,
|
||||
post_time_range_seconds_with_default,
|
||||
},
|
||||
fetcher::resolve_ap_identifier,
|
||||
objects::community::ApubCommunity,
|
||||
};
|
||||
|
@ -25,9 +29,9 @@ pub async fn list_posts(
|
|||
context: Data<LemmyContext>,
|
||||
local_user_view: Option<LocalUserView>,
|
||||
) -> LemmyResult<Json<GetPostsResponse>> {
|
||||
let local_site = SiteView::read_local(&mut context.pool()).await?;
|
||||
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
||||
|
||||
check_private_instance(&local_user_view, &local_site.local_site)?;
|
||||
check_private_instance(&local_user_view, &site_view.local_site)?;
|
||||
|
||||
let page = data.page;
|
||||
let limit = data.limit;
|
||||
|
@ -55,15 +59,20 @@ pub async fn list_posts(
|
|||
let listing_type = Some(listing_type_with_default(
|
||||
data.type_,
|
||||
local_user,
|
||||
&local_site.local_site,
|
||||
&site_view.local_site,
|
||||
community_id,
|
||||
));
|
||||
|
||||
let sort = Some(post_sort_type_with_default(
|
||||
data.sort,
|
||||
local_user,
|
||||
&local_site.local_site,
|
||||
&site_view.local_site,
|
||||
));
|
||||
let time_range_seconds = post_time_range_seconds_with_default(
|
||||
data.time_range_seconds,
|
||||
local_user,
|
||||
&site_view.local_site,
|
||||
);
|
||||
|
||||
// parse pagination token
|
||||
let page_after = if let Some(pa) = &data.page_cursor {
|
||||
|
@ -76,6 +85,7 @@ pub async fn list_posts(
|
|||
local_user,
|
||||
listing_type,
|
||||
sort,
|
||||
time_range_seconds,
|
||||
community_id,
|
||||
read_only,
|
||||
liked_only,
|
||||
|
@ -90,7 +100,7 @@ pub async fn list_posts(
|
|||
no_comments_only,
|
||||
..Default::default()
|
||||
}
|
||||
.list(&local_site.site, &mut context.pool())
|
||||
.list(&site_view.site, &mut context.pool())
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntGetPosts)?;
|
||||
|
||||
|
|
|
@ -54,6 +54,26 @@ fn post_sort_type_with_default(
|
|||
)
|
||||
}
|
||||
|
||||
/// Returns a default post_time_range.
|
||||
/// Order is the given, then local user default, then site default.
|
||||
/// If zero is given, then the output is None.
|
||||
fn post_time_range_seconds_with_default(
|
||||
secs: Option<i32>,
|
||||
local_user: Option<&LocalUser>,
|
||||
local_site: &LocalSite,
|
||||
) -> Option<i32> {
|
||||
let out = secs
|
||||
.or(local_user.and_then(|u| u.default_post_time_range_seconds))
|
||||
.or(local_site.default_post_time_range_seconds);
|
||||
|
||||
// A zero is an override to None
|
||||
if out.is_some_and(|o| o == 0) {
|
||||
None
|
||||
} else {
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a default instance-level comment sort type, if none is given by the user.
|
||||
/// Order is type, local user default, then site default.
|
||||
fn comment_sort_type_with_default(
|
||||
|
|
|
@ -33,6 +33,7 @@ pub async fn search(
|
|||
data.community_id
|
||||
};
|
||||
let search_term = data.search_term.clone();
|
||||
let time_range_seconds = data.time_range_seconds;
|
||||
|
||||
// parse pagination token
|
||||
let page_after = if let Some(pa) = &data.page_cursor {
|
||||
|
@ -48,6 +49,7 @@ pub async fn search(
|
|||
creator_id: data.creator_id,
|
||||
type_: data.type_,
|
||||
sort: data.sort,
|
||||
time_range_seconds,
|
||||
listing_type: data.listing_type,
|
||||
title_only: data.title_only,
|
||||
post_url_only: data.post_url_only,
|
||||
|
|
|
@ -70,14 +70,14 @@ pub struct CommunityAggregates {
|
|||
pub users_active_month: i64,
|
||||
/// The number of users with any activity in the last year.
|
||||
pub users_active_half_year: i64,
|
||||
/// Number of any interactions over the last month.
|
||||
#[serde(skip)]
|
||||
pub interactions_month: i64,
|
||||
#[serde(skip)]
|
||||
pub hot_rank: f64,
|
||||
pub subscribers_local: i64,
|
||||
pub report_count: i16,
|
||||
pub unresolved_report_count: i16,
|
||||
/// Number of any interactions over the last month.
|
||||
#[serde(skip)]
|
||||
pub interactions_month: i64,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone, Default)]
|
||||
|
@ -99,6 +99,7 @@ pub struct PersonAggregates {
|
|||
pub comment_count: i64,
|
||||
#[serde(skip)]
|
||||
pub comment_score: i64,
|
||||
pub published: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
|
||||
|
|
|
@ -66,19 +66,9 @@ pub enum PostSortType {
|
|||
Hot,
|
||||
New,
|
||||
Old,
|
||||
TopDay,
|
||||
TopWeek,
|
||||
TopMonth,
|
||||
TopYear,
|
||||
TopAll,
|
||||
Top,
|
||||
MostComments,
|
||||
NewComments,
|
||||
TopHour,
|
||||
TopSixHour,
|
||||
TopTwelveHour,
|
||||
TopThreeMonths,
|
||||
TopSixMonths,
|
||||
TopNineMonths,
|
||||
Controversial,
|
||||
Scaled,
|
||||
}
|
||||
|
|
|
@ -252,11 +252,11 @@ diesel::table! {
|
|||
users_active_week -> Int8,
|
||||
users_active_month -> Int8,
|
||||
users_active_half_year -> Int8,
|
||||
interactions_month -> Int8,
|
||||
hot_rank -> Float8,
|
||||
subscribers_local -> Int8,
|
||||
report_count -> Int2,
|
||||
unresolved_report_count -> Int2,
|
||||
interactions_month -> Int8,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -445,6 +445,7 @@ diesel::table! {
|
|||
comment_upvotes -> FederationModeEnum,
|
||||
comment_downvotes -> FederationModeEnum,
|
||||
disable_donation_dialog -> Bool,
|
||||
default_post_time_range_seconds -> Nullable<Int4>,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -518,6 +519,7 @@ diesel::table! {
|
|||
auto_mark_fetched_posts_as_read -> Bool,
|
||||
last_donation_notification -> Timestamptz,
|
||||
hide_media -> Bool,
|
||||
default_post_time_range_seconds -> Nullable<Int4>,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -779,6 +781,7 @@ diesel::table! {
|
|||
post_score -> Int8,
|
||||
comment_count -> Int8,
|
||||
comment_score -> Int8,
|
||||
published -> Timestamptz,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -86,6 +86,9 @@ pub struct LocalSite {
|
|||
/// If this is true, users will never see the dialog asking to support Lemmy development with
|
||||
/// donations.
|
||||
pub disable_donation_dialog: bool,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
/// A default time range limit to apply to post sorts, in seconds.
|
||||
pub default_post_time_range_seconds: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, derive_new::new)]
|
||||
|
@ -147,6 +150,8 @@ pub struct LocalSiteInsertForm {
|
|||
pub comment_downvotes: Option<FederationMode>,
|
||||
#[new(default)]
|
||||
pub disable_donation_dialog: Option<bool>,
|
||||
#[new(default)]
|
||||
pub default_post_time_range_seconds: Option<Option<i32>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
|
@ -181,4 +186,5 @@ pub struct LocalSiteUpdateForm {
|
|||
pub comment_upvotes: Option<FederationMode>,
|
||||
pub comment_downvotes: Option<FederationMode>,
|
||||
pub disable_donation_dialog: Option<bool>,
|
||||
pub default_post_time_range_seconds: Option<Option<i32>>,
|
||||
}
|
||||
|
|
|
@ -76,6 +76,9 @@ pub struct LocalUser {
|
|||
pub last_donation_notification: DateTime<Utc>,
|
||||
/// Whether to hide posts containing images/videos
|
||||
pub hide_media: bool,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
/// A default time range limit to apply to post sorts, in seconds.
|
||||
pub default_post_time_range_seconds: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, derive_new::new)]
|
||||
|
@ -138,6 +141,8 @@ pub struct LocalUserInsertForm {
|
|||
pub last_donation_notification: Option<DateTime<Utc>>,
|
||||
#[new(default)]
|
||||
pub hide_media: Option<bool>,
|
||||
#[new(default)]
|
||||
pub default_post_time_range_seconds: Option<Option<i32>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
|
@ -172,4 +177,5 @@ pub struct LocalUserUpdateForm {
|
|||
pub auto_mark_fetched_posts_as_read: Option<bool>,
|
||||
pub last_donation_notification: Option<DateTime<Utc>>,
|
||||
pub hide_media: Option<bool>,
|
||||
pub default_post_time_range_seconds: Option<Option<i32>>,
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
pub mod uplete;
|
||||
|
||||
use crate::{newtypes::DbUrl, schema_setup, CommentSortType, PostSortType};
|
||||
use crate::{newtypes::DbUrl, schema_setup};
|
||||
use chrono::TimeDelta;
|
||||
use deadpool::Runtime;
|
||||
use diesel::{
|
||||
dsl,
|
||||
expression::AsExpression,
|
||||
helper_types::AsExprOf,
|
||||
pg::Pg,
|
||||
pg::{data_types::PgInterval, Pg},
|
||||
query_builder::{Query, QueryFragment},
|
||||
query_dsl::methods::LimitDsl,
|
||||
result::{
|
||||
|
@ -303,6 +303,16 @@ pub fn diesel_string_update(opt: Option<&str>) -> Option<Option<String>> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Takes an API optional number, and converts it to an optional diesel DB update. Zero means erase.
|
||||
pub fn diesel_opt_number_update(opt: Option<i32>) -> Option<Option<i32>> {
|
||||
match opt {
|
||||
// Zero is an erase
|
||||
Some(0) => Some(None),
|
||||
Some(num) => Some(Some(num)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes an API optional text input, and converts it to an optional diesel DB update (for non
|
||||
/// nullable properties).
|
||||
pub fn diesel_required_string_update(opt: Option<&str>) -> Option<String> {
|
||||
|
@ -495,18 +505,6 @@ pub fn build_db_pool_for_tests() -> ActualDbPool {
|
|||
build_db_pool().expect("db pool missing")
|
||||
}
|
||||
|
||||
pub fn post_to_comment_sort_type(sort: PostSortType) -> CommentSortType {
|
||||
use PostSortType::*;
|
||||
match sort {
|
||||
Active | Hot | Scaled => CommentSortType::Hot,
|
||||
New | NewComments | MostComments => CommentSortType::New,
|
||||
Old => CommentSortType::Old,
|
||||
Controversial => CommentSortType::Controversial,
|
||||
TopHour | TopSixHour | TopTwelveHour | TopDay | TopAll | TopWeek | TopYear | TopMonth
|
||||
| TopThreeMonths | TopSixMonths | TopNineMonths => CommentSortType::Top,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::expect_used)]
|
||||
static EMAIL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")
|
||||
|
@ -557,6 +555,10 @@ pub fn now() -> AsExprOf<diesel::dsl::now, diesel::sql_types::Timestamptz> {
|
|||
diesel::dsl::now.into_sql::<Timestamptz>()
|
||||
}
|
||||
|
||||
pub fn seconds_to_pg_interval(seconds: i32) -> PgInterval {
|
||||
PgInterval::from_microseconds(i64::from(seconds) * 1_000_000)
|
||||
}
|
||||
|
||||
/// Trait alias for a type that can be converted to an SQL tuple using `IntoSql::into_sql`
|
||||
pub trait AsRecord: Expression + AsExpression<sql_types::Record<Self::SqlType>>
|
||||
where
|
||||
|
|
|
@ -48,7 +48,15 @@ use lemmy_db_schema::{
|
|||
community::CommunityFollower,
|
||||
},
|
||||
traits::InternalToCombinedView,
|
||||
utils::{functions::coalesce, fuzzy_search, get_conn, DbPool, ReverseTimestampKey},
|
||||
utils::{
|
||||
functions::coalesce,
|
||||
fuzzy_search,
|
||||
get_conn,
|
||||
now,
|
||||
seconds_to_pg_interval,
|
||||
DbPool,
|
||||
ReverseTimestampKey,
|
||||
},
|
||||
ListingType,
|
||||
SearchSortType,
|
||||
SearchType,
|
||||
|
@ -216,6 +224,7 @@ pub struct SearchCombinedQuery {
|
|||
pub creator_id: Option<PersonId>,
|
||||
pub type_: Option<SearchType>,
|
||||
pub sort: Option<SearchSortType>,
|
||||
pub time_range_seconds: Option<i32>,
|
||||
pub listing_type: Option<ListingType>,
|
||||
pub title_only: Option<bool>,
|
||||
pub post_url_only: Option<bool>,
|
||||
|
@ -402,6 +411,13 @@ impl SearchCombinedQuery {
|
|||
Old => query.then_desc(ReverseTimestampKey(key::published)),
|
||||
Top => query.then_desc(key::score),
|
||||
};
|
||||
|
||||
// Filter by the time range
|
||||
if let Some(time_range_seconds) = self.time_range_seconds {
|
||||
query = query
|
||||
.filter(search_combined::published.gt(now() - seconds_to_pg_interval(time_range_seconds)));
|
||||
}
|
||||
|
||||
// finally use unique id as tie breaker
|
||||
query = query.then_desc(key::id);
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ use lemmy_db_schema::{
|
|||
post,
|
||||
},
|
||||
source::{community::CommunityFollowerState, local_user::LocalUser, site::Site},
|
||||
utils::{fuzzy_search, get_conn, limit_and_offset, DbPool},
|
||||
utils::{fuzzy_search, get_conn, limit_and_offset, now, seconds_to_pg_interval, DbPool},
|
||||
CommentSortType,
|
||||
CommunityVisibility,
|
||||
ListingType,
|
||||
|
@ -146,6 +146,7 @@ impl CommentView {
|
|||
pub struct CommentQuery<'a> {
|
||||
pub listing_type: Option<ListingType>,
|
||||
pub sort: Option<CommentSortType>,
|
||||
pub time_range_seconds: Option<i32>,
|
||||
pub community_id: Option<CommunityId>,
|
||||
pub post_id: Option<PostId>,
|
||||
pub parent_path: Option<Ltree>,
|
||||
|
@ -316,6 +317,13 @@ impl CommentQuery<'_> {
|
|||
CommentSortType::Top => query.then_order_by(comment_aggregates::score.desc()),
|
||||
};
|
||||
|
||||
// Filter by the time range
|
||||
if let Some(time_range_seconds) = o.time_range_seconds {
|
||||
query = query.filter(
|
||||
comment_aggregates::published.gt(now() - seconds_to_pg_interval(time_range_seconds)),
|
||||
);
|
||||
}
|
||||
|
||||
let res = query
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
|
|
|
@ -18,7 +18,7 @@ use lemmy_db_schema::{
|
|||
local_user::LocalUser,
|
||||
site::Site,
|
||||
},
|
||||
utils::{functions::lower, get_conn, limit_and_offset, DbPool},
|
||||
utils::{functions::lower, get_conn, limit_and_offset, now, seconds_to_pg_interval, DbPool},
|
||||
ListingType,
|
||||
};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
|
@ -107,6 +107,7 @@ impl CommunityView {
|
|||
pub struct CommunityQuery<'a> {
|
||||
pub listing_type: Option<ListingType>,
|
||||
pub sort: Option<CommunitySortType>,
|
||||
pub time_range_seconds: Option<i32>,
|
||||
pub local_user: Option<&'a LocalUser>,
|
||||
pub title_only: Option<bool>,
|
||||
pub is_mod_or_admin: bool,
|
||||
|
@ -176,6 +177,12 @@ impl CommunityQuery<'_> {
|
|||
NameAsc => query = query.order_by(lower(community::name).asc()),
|
||||
NameDesc => query = query.order_by(lower(community::name).desc()),
|
||||
};
|
||||
// Filter by the time range
|
||||
if let Some(time_range_seconds) = o.time_range_seconds {
|
||||
query = query.filter(
|
||||
community_aggregates::published.gt(now() - seconds_to_pg_interval(time_range_seconds)),
|
||||
);
|
||||
}
|
||||
|
||||
let (limit, offset) = limit_and_offset(o.page, o.limit)?;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::structs::{PaginationCursor, PostView};
|
||||
use diesel::{
|
||||
debug_query,
|
||||
dsl::{exists, not, IntervalDsl},
|
||||
dsl::{exists, not},
|
||||
pg::Pg,
|
||||
query_builder::AsQuery,
|
||||
result::Error,
|
||||
|
@ -48,6 +48,7 @@ use lemmy_db_schema::{
|
|||
limit_and_offset,
|
||||
now,
|
||||
paginate,
|
||||
seconds_to_pg_interval,
|
||||
Commented,
|
||||
DbPool,
|
||||
ReverseTimestampKey,
|
||||
|
@ -259,6 +260,7 @@ pub struct PaginationCursorData {
|
|||
pub struct PostQuery<'a> {
|
||||
pub listing_type: Option<ListingType>,
|
||||
pub sort: Option<PostSortType>,
|
||||
pub time_range_seconds: Option<i32>,
|
||||
pub creator_id: Option<PersonId>,
|
||||
pub community_id: Option<CommunityId>,
|
||||
// if true, the query should be handled as if community_id was not given except adding the
|
||||
|
@ -595,8 +597,6 @@ impl<'a> PostQuery<'a> {
|
|||
query.then_desc(key::featured_community)
|
||||
};
|
||||
|
||||
let time = |interval| post_aggregates::published.gt(now() - interval);
|
||||
|
||||
// then use the main sort
|
||||
query = match o.sort.unwrap_or(Hot) {
|
||||
Active => query.then_desc(key::hot_rank_active),
|
||||
|
@ -607,19 +607,16 @@ impl<'a> PostQuery<'a> {
|
|||
Old => query.then_desc(ReverseTimestampKey(key::published)),
|
||||
NewComments => query.then_desc(key::newest_comment_time),
|
||||
MostComments => query.then_desc(key::comments),
|
||||
TopAll => query.then_desc(key::score),
|
||||
TopYear => query.then_desc(key::score).filter(time(1.years())),
|
||||
TopMonth => query.then_desc(key::score).filter(time(1.months())),
|
||||
TopWeek => query.then_desc(key::score).filter(time(1.weeks())),
|
||||
TopDay => query.then_desc(key::score).filter(time(1.days())),
|
||||
TopHour => query.then_desc(key::score).filter(time(1.hours())),
|
||||
TopSixHour => query.then_desc(key::score).filter(time(6.hours())),
|
||||
TopTwelveHour => query.then_desc(key::score).filter(time(12.hours())),
|
||||
TopThreeMonths => query.then_desc(key::score).filter(time(3.months())),
|
||||
TopSixMonths => query.then_desc(key::score).filter(time(6.months())),
|
||||
TopNineMonths => query.then_desc(key::score).filter(time(9.months())),
|
||||
Top => query.then_desc(key::score),
|
||||
};
|
||||
|
||||
// Filter by the time range
|
||||
if let Some(time_range_seconds) = o.time_range_seconds {
|
||||
query = query.filter(
|
||||
post_aggregates::published.gt(now() - seconds_to_pg_interval(time_range_seconds)),
|
||||
);
|
||||
}
|
||||
|
||||
// use publish as fallback. especially useful for hot rank which reaches zero after some days.
|
||||
// necessary because old posts can be fetched over federation and inserted with high post id
|
||||
query = match o.sort.unwrap_or(Hot) {
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
-- This removes all the extra post_sort_type_enums,
|
||||
-- and adds a default_post_time_range_seconds field.
|
||||
-- Drop the defaults because of a postgres bug
|
||||
ALTER TABLE local_user
|
||||
ALTER default_post_sort_type DROP DEFAULT;
|
||||
|
||||
ALTER TABLE local_site
|
||||
ALTER default_post_sort_type DROP DEFAULT;
|
||||
|
||||
-- Change all the top variants to top in the two tables that use the enum
|
||||
UPDATE
|
||||
local_user
|
||||
SET
|
||||
default_post_sort_type = 'Active'
|
||||
WHERE
|
||||
default_post_sort_type = 'Top';
|
||||
|
||||
UPDATE
|
||||
local_site
|
||||
SET
|
||||
default_post_sort_type = 'Active'
|
||||
WHERE
|
||||
default_post_sort_type = 'Top';
|
||||
|
||||
-- rename the old enum to a tmp name
|
||||
ALTER TYPE post_sort_type_enum RENAME TO post_sort_type_enum__;
|
||||
|
||||
-- create the new enum
|
||||
CREATE TYPE post_sort_type_enum AS ENUM (
|
||||
'Active',
|
||||
'Hot',
|
||||
'New',
|
||||
'Old',
|
||||
'TopDay',
|
||||
'TopWeek',
|
||||
'TopMonth',
|
||||
'TopYear',
|
||||
'TopAll',
|
||||
'MostComments',
|
||||
'NewComments',
|
||||
'TopHour',
|
||||
'TopSixHour',
|
||||
'TopTwelveHour',
|
||||
'TopThreeMonths',
|
||||
'TopSixMonths',
|
||||
'TopNineMonths',
|
||||
'Controversial',
|
||||
'Scaled'
|
||||
);
|
||||
|
||||
-- alter all you enum columns
|
||||
ALTER TABLE local_user
|
||||
ALTER COLUMN default_post_sort_type TYPE post_sort_type_enum
|
||||
USING default_post_sort_type::text::post_sort_type_enum;
|
||||
|
||||
ALTER TABLE local_site
|
||||
ALTER COLUMN default_post_sort_type TYPE post_sort_type_enum
|
||||
USING default_post_sort_type::text::post_sort_type_enum;
|
||||
|
||||
-- drop the old enum
|
||||
DROP TYPE post_sort_type_enum__;
|
||||
|
||||
-- Add back in the default
|
||||
ALTER TABLE local_user
|
||||
ALTER default_post_sort_type SET DEFAULT 'Active';
|
||||
|
||||
ALTER TABLE local_site
|
||||
ALTER default_post_sort_type SET DEFAULT 'Active';
|
||||
|
||||
-- Drop the new columns
|
||||
ALTER TABLE local_user
|
||||
DROP COLUMN default_post_time_range_seconds;
|
||||
|
||||
ALTER TABLE local_site
|
||||
DROP COLUMN default_post_time_range_seconds;
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
-- This removes all the extra post_sort_type_enums,
|
||||
-- and adds a default_post_time_range_seconds field.
|
||||
-- Change all the top variants to top in the two tables that use the enum
|
||||
-- Because of a postgres bug, you can't assign this to a new enum value,
|
||||
-- unless you run an unsafe commit first. So just use active.
|
||||
-- https://dba.stackexchange.com/questions/280371/postgres-unsafe-use-of-new-value-of-enum-type
|
||||
UPDATE
|
||||
local_user
|
||||
SET
|
||||
default_post_sort_type = 'Active'
|
||||
WHERE
|
||||
default_post_sort_type IN ('TopDay', 'TopWeek', 'TopMonth', 'TopYear', 'TopAll', 'TopHour', 'TopSixHour', 'TopTwelveHour', 'TopThreeMonths', 'TopSixMonths', 'TopNineMonths');
|
||||
|
||||
UPDATE
|
||||
local_site
|
||||
SET
|
||||
default_post_sort_type = 'Active'
|
||||
WHERE
|
||||
default_post_sort_type IN ('TopDay', 'TopWeek', 'TopMonth', 'TopYear', 'TopAll', 'TopHour', 'TopSixHour', 'TopTwelveHour', 'TopThreeMonths', 'TopSixMonths', 'TopNineMonths');
|
||||
|
||||
-- Drop the defaults because of a postgres bug
|
||||
ALTER TABLE local_user
|
||||
ALTER default_post_sort_type DROP DEFAULT;
|
||||
|
||||
ALTER TABLE local_site
|
||||
ALTER default_post_sort_type DROP DEFAULT;
|
||||
|
||||
-- rename the old enum to a tmp name
|
||||
ALTER TYPE post_sort_type_enum RENAME TO post_sort_type_enum__;
|
||||
|
||||
-- create the new enum
|
||||
CREATE TYPE post_sort_type_enum AS ENUM (
|
||||
'Active',
|
||||
'Hot',
|
||||
'New',
|
||||
'Old',
|
||||
'Top',
|
||||
'MostComments',
|
||||
'NewComments',
|
||||
'Controversial',
|
||||
'Scaled'
|
||||
);
|
||||
|
||||
-- alter all you enum columns
|
||||
ALTER TABLE local_user
|
||||
ALTER COLUMN default_post_sort_type TYPE post_sort_type_enum
|
||||
USING default_post_sort_type::text::post_sort_type_enum;
|
||||
|
||||
ALTER TABLE local_site
|
||||
ALTER COLUMN default_post_sort_type TYPE post_sort_type_enum
|
||||
USING default_post_sort_type::text::post_sort_type_enum;
|
||||
|
||||
-- drop the old enum
|
||||
DROP TYPE post_sort_type_enum__;
|
||||
|
||||
-- Add back in the default
|
||||
ALTER TABLE local_user
|
||||
ALTER default_post_sort_type SET DEFAULT 'Active';
|
||||
|
||||
ALTER TABLE local_site
|
||||
ALTER default_post_sort_type SET DEFAULT 'Active';
|
||||
|
||||
-- Add the new column to both tables (null means no limit)
|
||||
ALTER TABLE local_user
|
||||
ADD COLUMN default_post_time_range_seconds INTEGER;
|
||||
|
||||
ALTER TABLE local_site
|
||||
ADD COLUMN default_post_time_range_seconds INTEGER;
|
||||
|
Loading…
Reference in a new issue