added anyhow, improve hamburger menu, improve dw articles
This commit is contained in:
+34
-17
@@ -1,4 +1,5 @@
|
||||
use super::feeds;
|
||||
use crate::error::AppError;
|
||||
use crate::json_serialization::user::JsonUser;
|
||||
use crate::models::feed::rss_feed::Feed;
|
||||
use crate::models::feed_item::new_feed_item::NewFeedItem;
|
||||
@@ -60,8 +61,17 @@ fn enclosure_image_html(item: &Item) -> Option<String> {
|
||||
))
|
||||
}
|
||||
|
||||
fn create_feed_item(item: Item, feed: &Feed, connection: &mut PgConnection) {
|
||||
let item_title = item.title.clone().unwrap();
|
||||
fn create_feed_item(item: Item, feed: &Feed, connection: &mut PgConnection) -> anyhow::Result<()> {
|
||||
// Items without a title or link are malformed/unusable — skip them rather
|
||||
// than failing the whole sync over one bad entry from an external feed.
|
||||
let Some(item_title) = item.title.clone() else {
|
||||
log::warn!("Skipping feed item without a title.");
|
||||
return Ok(());
|
||||
};
|
||||
if item.link.is_none() {
|
||||
log::warn!("Skipping feed item without a link: {}", item_title);
|
||||
return Ok(());
|
||||
}
|
||||
log::info!("Create feed item: {}", item_title);
|
||||
|
||||
// Items without a pub_date are treated as current (inserted unconditionally)
|
||||
@@ -83,7 +93,7 @@ fn create_feed_item(item: Item, feed: &Feed, connection: &mut PgConnection) {
|
||||
let frag = Html::parse_fragment(base_content);
|
||||
let mut content = "".to_string();
|
||||
|
||||
let selector_img = Selector::parse("img").unwrap();
|
||||
let selector_img = Selector::parse("img").expect("\"img\" is a valid CSS selector");
|
||||
match frag.select(&selector_img).find(image_src_is_resolvable) {
|
||||
Some(image) => {
|
||||
content.push_str(&image.html());
|
||||
@@ -106,15 +116,14 @@ fn create_feed_item(item: Item, feed: &Feed, connection: &mut PgConnection) {
|
||||
let existing_item: Vec<FeedItem> = feed_item::table
|
||||
.filter(feed_id.eq(feed.id))
|
||||
.filter(title.eq(&item_title))
|
||||
.load(connection)
|
||||
.unwrap();
|
||||
.load(connection)?;
|
||||
|
||||
if existing_item.is_empty() {
|
||||
let new_feed_item = NewFeedItem::new(
|
||||
feed.id,
|
||||
content.clone(),
|
||||
item_title.clone(),
|
||||
item.link.unwrap(),
|
||||
item.link.expect("checked above"),
|
||||
Some(time),
|
||||
);
|
||||
let insert_result = diesel::insert_into(feed_item::table)
|
||||
@@ -125,17 +134,21 @@ fn create_feed_item(item: Item, feed: &Feed, connection: &mut PgConnection) {
|
||||
} else {
|
||||
log::info!("Item {} already exists.", item_title);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn sync(_req: HttpRequest, data: web::Json<JsonUser>) -> impl Responder {
|
||||
pub async fn sync(
|
||||
_req: HttpRequest,
|
||||
data: web::Json<JsonUser>,
|
||||
) -> Result<impl Responder, AppError> {
|
||||
let mut connection: diesel::PgConnection = establish_connection();
|
||||
|
||||
let req_user_id: i32 = data.user_id;
|
||||
|
||||
let feeds: Vec<Feed> = feed::table
|
||||
.filter(user_id.eq(req_user_id))
|
||||
.load::<Feed>(&mut connection)
|
||||
.unwrap();
|
||||
.load::<Feed>(&mut connection)?;
|
||||
|
||||
log::info!("Found {} feeds to sync.", feeds.len());
|
||||
|
||||
@@ -147,14 +160,16 @@ pub async fn sync(_req: HttpRequest, data: web::Json<JsonUser>) -> impl Responde
|
||||
Ok(channel) => {
|
||||
for item in channel.into_items() {
|
||||
log::info!("{:?}", item);
|
||||
create_feed_item(item, &feed, &mut connection);
|
||||
if let Err(e) = create_feed_item(item, &feed, &mut connection) {
|
||||
log::error!("Could not create feed item for {}: {:?}", feed.url, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => log::error!("Could not get channel {}. Error: {}", feed.url, e),
|
||||
}
|
||||
}
|
||||
|
||||
HttpResponse::Ok()
|
||||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -261,7 +276,8 @@ mod tests {
|
||||
format!("age_test_{suffix}"),
|
||||
format!("age_{suffix}@example.test"),
|
||||
"secret".to_string(),
|
||||
);
|
||||
)
|
||||
.unwrap();
|
||||
let user: User = diesel::insert_into(users::table)
|
||||
.values(&new_user)
|
||||
.get_result(&mut connection)
|
||||
@@ -295,8 +311,8 @@ mod tests {
|
||||
fresh_item.set_link(Some(format!("https://example.test/fresh/{suffix}")));
|
||||
fresh_item.set_content(Some("<p>fresh</p>".to_string()));
|
||||
|
||||
create_feed_item(old_item, &feed, &mut connection);
|
||||
create_feed_item(fresh_item, &feed, &mut connection);
|
||||
create_feed_item(old_item, &feed, &mut connection).unwrap();
|
||||
create_feed_item(fresh_item, &feed, &mut connection).unwrap();
|
||||
|
||||
let items: Vec<FeedItem> = feed_item::table
|
||||
.filter(feed_id.eq(feed.id))
|
||||
@@ -325,7 +341,8 @@ mod tests {
|
||||
format!("sync_test_{suffix}"),
|
||||
format!("sync_{suffix}@example.test"),
|
||||
"secret".to_string(),
|
||||
);
|
||||
)
|
||||
.unwrap();
|
||||
let user: User = diesel::insert_into(users::table)
|
||||
.values(&new_user)
|
||||
.get_result(&mut connection)
|
||||
@@ -346,8 +363,8 @@ mod tests {
|
||||
item.set_link(Some(format!("https://example.test/article/{suffix}")));
|
||||
item.set_content(Some("<p>Hello world</p>".to_string()));
|
||||
|
||||
create_feed_item(item.clone(), &feed, &mut connection);
|
||||
create_feed_item(item, &feed, &mut connection);
|
||||
create_feed_item(item.clone(), &feed, &mut connection).unwrap();
|
||||
create_feed_item(item, &feed, &mut connection).unwrap();
|
||||
|
||||
let items: Vec<FeedItem> = feed_item::table
|
||||
.filter(feed_id.eq(feed.id))
|
||||
|
||||
Reference in New Issue
Block a user