fix: duplicated posts in all timeline

This commit is contained in:
trisua 2025-07-04 17:41:58 -04:00
parent 1dc0611298
commit e5b6b5a4d4
9 changed files with 34 additions and 43 deletions

View file

@ -36,7 +36,7 @@
(text "{% set paged = user and user.settings.paged_timelines %}") (text "{% set paged = user and user.settings.paged_timelines %}")
(script (script
(text "setTimeout(() => { (text "setTimeout(() => {
trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=AllPosts&page=\", Number.parseInt(\"{{ page }}\") - 1, \"{{ paged }}\" === \"true\"]); trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=AllPosts&before=$1$&page=\", Number.parseInt(\"{{ page }}\") - 1, \"{{ paged }}\" === \"true\"]);
});")) });"))
(text "{% endblock %}") (text "{% endblock %}")

View file

@ -9,7 +9,7 @@
(datalist (datalist
("ui_ident" "list_posts_{{ page }}") ("ui_ident" "list_posts_{{ page }}")
(text "{% for post in list -%}") (text "{% for post in list -%}")
(option ("value" "{{ post[0].id }}")) (option ("value" "{{ post[0].id }}") ("data-created" "{{ post[0].created }}"))
(text "{%- endfor %}")) (text "{%- endfor %}"))
(text "{% if list|length == 0 -%}") (text "{% if list|length == 0 -%}")
(div (div

View file

@ -1212,6 +1212,7 @@ ${option.input_element_type === "textarea" ? `${option.value}</textarea>` : ""}
self.IO_HAS_LOADED_AT_LEAST_ONCE = false; self.IO_HAS_LOADED_AT_LEAST_ONCE = false;
self.IO_DATA_DISCONNECTED = false; self.IO_DATA_DISCONNECTED = false;
self.IO_DATA_DISABLE_RELOAD = false; self.IO_DATA_DISABLE_RELOAD = false;
self.IO_DATA_LOAD_BEFORE = 0;
if (!paginated_mode) { if (!paginated_mode) {
self.IO_DATA_OBSERVER.observe(self.IO_DATA_MARKER); self.IO_DATA_OBSERVER.observe(self.IO_DATA_MARKER);
@ -1256,7 +1257,9 @@ ${option.input_element_type === "textarea" ? `${option.value}</textarea>` : ""}
// ... // ...
const text = await ( const text = await (
await fetch(`${self.IO_DATA_TMPL}${self.IO_DATA_PAGE}`) await fetch(
`${self.IO_DATA_TMPL.replace("&before=$1$", `&before=${self.IO_DATA_LOAD_BEFORE}`)}${self.IO_DATA_PAGE}`,
)
).text(); ).text();
self.IO_DATA_WAITING = false; self.IO_DATA_WAITING = false;
@ -1291,34 +1294,6 @@ ${option.input_element_type === "textarea" ? `${option.value}</textarea>` : ""}
self.IO_DATA_ELEMENT.children.length - 1 self.IO_DATA_ELEMENT.children.length - 1
].after(self.IO_DATA_MARKER); ].after(self.IO_DATA_MARKER);
// remove posts we've already seen
function remove_elements(id, outer = false) {
let idx = 0;
for (const element of Array.from(
document.querySelectorAll(
`.post${outer ? "_outer" : ""}\\:${id}`,
),
)) {
if (element.getAttribute("is_repost") === true) {
continue;
}
if (idx === 0) {
idx += 1;
continue;
}
// everything that isn't the first element should be removed
element.remove();
console.log("removed duplicate post");
}
}
for (const id of self.IO_DATA_SEEN_IDS) {
remove_elements(id, false);
remove_elements(id, true); // scoop up questions
}
// push ids // push ids
for (const opt of Array.from( for (const opt of Array.from(
document.querySelectorAll( document.querySelectorAll(
@ -1330,6 +1305,8 @@ ${option.input_element_type === "textarea" ? `${option.value}</textarea>` : ""}
if (!self.IO_DATA_SEEN_IDS[v]) { if (!self.IO_DATA_SEEN_IDS[v]) {
self.IO_DATA_SEEN_IDS.push(v); self.IO_DATA_SEEN_IDS.push(v);
} }
self.IO_DATA_LOAD_BEFORE = opt.getAttribute("data-created");
} }
}, 150); }, 150);

View file

@ -838,7 +838,7 @@ pub async fn all_request(
}; };
match data match data
.get_latest_posts(12, props.page, &Some(user.clone())) .get_latest_posts(12, props.page, &Some(user.clone()), props.before)
.await .await
{ {
Ok(posts) => { Ok(posts) => {

View file

@ -631,6 +631,8 @@ pub struct TimelineQuery {
pub tag: String, pub tag: String,
#[serde(default)] #[serde(default)]
pub paginated: bool, pub paginated: bool,
#[serde(default)]
pub before: usize,
} }
/// `/_swiss_army_timeline` /// `/_swiss_army_timeline`
@ -688,7 +690,9 @@ pub async fn swiss_army_timeline_request(
// everything else // everything else
match req.tl { match req.tl {
DefaultTimelineChoice::AllPosts => { DefaultTimelineChoice::AllPosts => {
data.0.get_latest_posts(12, req.page, &user).await data.0
.get_latest_posts(12, req.page, &user, req.before)
.await
} }
DefaultTimelineChoice::PopularPosts => { DefaultTimelineChoice::PopularPosts => {
data.0.get_popular_posts(12, req.page, 604_800_000).await data.0.get_popular_posts(12, req.page, 604_800_000).await

View file

@ -157,6 +157,8 @@ pub async fn render_error(
pub struct PaginatedQuery { pub struct PaginatedQuery {
#[serde(default)] #[serde(default)]
pub page: usize, pub page: usize,
#[serde(default)]
pub before: usize,
} }
#[derive(Deserialize)] #[derive(Deserialize)]

View file

@ -725,14 +725,16 @@ impl DataManager {
self.cache_clear_user(&other_user).await; self.cache_clear_user(&other_user).await;
// create audit log entry // create audit log entry
self.create_audit_log_entry(AuditLogEntry::new( if user.id != other_user.id {
user.id, self.create_audit_log_entry(AuditLogEntry::new(
format!( user.id,
"invoked `update_user_purchased_status` with x value `{}` and y value `{}`", format!(
other_user.id, x "invoked `update_user_purchased_status` with x value `{}` and y value `{}`",
), other_user.id, x
)) ),
.await?; ))
.await?;
}
// ... // ...
Ok(()) Ok(())

View file

@ -1374,6 +1374,7 @@ impl DataManager {
batch: usize, batch: usize,
page: usize, page: usize,
as_user: &Option<User>, as_user: &Option<User>,
before_time: usize,
) -> Result<Vec<Post>> { ) -> Result<Vec<Post>> {
let hide_answers: bool = if let Some(user) = as_user { let hide_answers: bool = if let Some(user) = as_user {
user.settings.all_timeline_hide_answers user.settings.all_timeline_hide_answers
@ -1389,7 +1390,12 @@ impl DataManager {
let res = query_rows!( let res = query_rows!(
&conn, &conn,
&format!( &format!(
"SELECT * FROM posts WHERE replying_to = 0 AND NOT context LIKE '%\"is_nsfw\":true%'{} ORDER BY created DESC LIMIT $1 OFFSET $2", "SELECT * FROM posts WHERE replying_to = 0{} AND NOT context LIKE '%\"is_nsfw\":true%'{} ORDER BY created DESC LIMIT $1 OFFSET $2",
if before_time > 0 {
format!(" AND created < {before_time}")
} else {
String::new()
},
if hide_answers { if hide_answers {
" AND context::jsonb->>'answering' = '0'" " AND context::jsonb->>'answering' = '0'"
} else { } else {

View file

@ -56,7 +56,7 @@ impl DataManager {
match stack.sort { match stack.sort {
StackSort::Created => { StackSort::Created => {
self.fill_posts_with_community( self.fill_posts_with_community(
self.get_latest_posts(batch, page, &user).await?, self.get_latest_posts(batch, page, &user, 0).await?,
as_user_id, as_user_id,
&ignore_users, &ignore_users,
user, user,