cleanup when syncing

This commit is contained in:
2026-06-08 17:31:10 +02:00
parent 83fdb464af
commit d826a8f3dc
+84 -1
View File
@@ -12,7 +12,7 @@ use crate::{
}, },
}; };
use actix_web::{web, HttpRequest, HttpResponse, Responder}; use actix_web::{web, HttpRequest, HttpResponse, Responder};
use chrono::{DateTime, Local, NaiveDateTime}; use chrono::{DateTime, Duration, Local, NaiveDateTime};
use dateparser::parse; use dateparser::parse;
use diesel::prelude::*; use diesel::prelude::*;
use rss::Item; use rss::Item;
@@ -124,9 +124,22 @@ fn create_feed_item(item: Item, feed: &Feed, connection: &mut PgConnection) {
} }
} }
// Items without a `created_ts` (e.g. ones inserted before this column existed,
// or whose feed didn't provide a publish date) are left alone — `lt` never
// matches NULL, so there's nothing to special-case here.
fn delete_old_feed_items(connection: &mut PgConnection) {
let cutoff = Local::now().naive_local() - Duration::days(14);
let result = diesel::delete(feed_item::table.filter(feed_item::created_ts.lt(cutoff)))
.execute(connection);
log::info!("Deleted old feed items (older than 2 weeks): {:?}", result);
}
pub async fn sync(_req: HttpRequest, data: web::Json<JsonUser>) -> impl Responder { pub async fn sync(_req: HttpRequest, data: web::Json<JsonUser>) -> impl Responder {
let mut connection: diesel::PgConnection = establish_connection(); let mut connection: diesel::PgConnection = establish_connection();
delete_old_feed_items(&mut connection);
let req_user_id: i32 = data.user_id; let req_user_id: i32 = data.user_id;
let feeds: Vec<Feed> = feed::table let feeds: Vec<Feed> = feed::table
@@ -248,6 +261,76 @@ mod tests {
); );
} }
#[actix_web::test]
async fn delete_old_feed_items_removes_items_older_than_two_weeks_but_keeps_recent_ones() {
let mut connection = establish_connection();
let suffix = unique_suffix();
let new_user = NewUser::new(
format!("cleanup_test_{suffix}"),
format!("cleanup_{suffix}@example.test"),
"secret".to_string(),
);
let user: User = diesel::insert_into(users::table)
.values(&new_user)
.get_result(&mut connection)
.unwrap();
let new_feed = NewFeed::new(
format!("Cleanup test feed {suffix}"),
format!("https://example.test/feed/{suffix}"),
user.id,
);
let feed: Feed = diesel::insert_into(feed::table)
.values(&new_feed)
.get_result(&mut connection)
.unwrap();
let now = Local::now().naive_local();
let old_item = NewFeedItem::new(
feed.id,
"old content".to_string(),
format!("Old article {suffix}"),
format!("https://example.test/article/old-{suffix}"),
Some(now - Duration::days(20)),
);
let recent_item = NewFeedItem::new(
feed.id,
"recent content".to_string(),
format!("Recent article {suffix}"),
format!("https://example.test/article/recent-{suffix}"),
Some(now - Duration::days(1)),
);
diesel::insert_into(feed_item::table)
.values(&old_item)
.execute(&mut connection)
.unwrap();
let recent: FeedItem = diesel::insert_into(feed_item::table)
.values(&recent_item)
.get_result(&mut connection)
.unwrap();
delete_old_feed_items(&mut connection);
let remaining: Vec<FeedItem> = feed_item::table
.filter(feed_id.eq(feed.id))
.load(&mut connection)
.unwrap();
assert_eq!(1, remaining.len(), "only the recent item should survive cleanup");
assert_eq!(recent.id, remaining[0].id);
diesel::delete(feed_item::table.filter(feed_id.eq(feed.id)))
.execute(&mut connection)
.ok();
diesel::delete(feed::table.filter(feed::id.eq(feed.id)))
.execute(&mut connection)
.ok();
diesel::delete(users::table.filter(users::id.eq(user.id)))
.execute(&mut connection)
.ok();
}
#[actix_web::test] #[actix_web::test]
async fn create_feed_item_does_not_duplicate_existing_items() { async fn create_feed_item_does_not_duplicate_existing_items() {
let mut connection = establish_connection(); let mut connection = establish_connection();