Skip to main content

news_flash/models/
article_filter.rs

1use std::collections::HashSet;
2
3use crate::models::{ArticleID, ArticleOrder, CategoryID, FeedID, Marked, OrderBy, Read, TagID};
4use chrono::{DateTime, Utc};
5
6use super::{CategoryMapping, FeedMapping};
7
8#[derive(Clone, Debug, Default)]
9pub struct ArticleFilter {
10    pub limit: Option<i64>,
11    pub offset: Option<i64>,
12    pub order: Option<ArticleOrder>,
13    pub order_by: Option<OrderBy>,
14    pub unread: Option<Read>,
15    pub marked: Option<Marked>,
16    pub feeds: Option<Vec<FeedID>>,
17    pub feed_blacklist: Option<Vec<FeedID>>,
18    pub categories: Option<Vec<CategoryID>>,
19    pub category_blacklist: Option<Vec<CategoryID>>,
20    pub tags: Option<Vec<TagID>>,
21    pub ids: Option<Vec<ArticleID>>,
22    pub newer_than: Option<DateTime<Utc>>,
23    pub older_than: Option<DateTime<Utc>>,
24    pub synced_before: Option<DateTime<Utc>>,
25    pub synced_after: Option<DateTime<Utc>>,
26    pub search_term: Option<String>,
27}
28
29impl ArticleFilter {
30    pub fn ids(article_ids: Vec<ArticleID>) -> Self {
31        Self {
32            ids: Some(article_ids),
33            ..Self::default()
34        }
35    }
36
37    pub fn read_ids(article_ids: Vec<ArticleID>, read: Read) -> Self {
38        Self {
39            unread: Some(read),
40            ids: Some(article_ids),
41            ..Self::default()
42        }
43    }
44
45    pub fn marked_ids(article_ids: Vec<ArticleID>, marked: Marked) -> Self {
46        Self {
47            marked: Some(marked),
48            ids: Some(article_ids),
49            ..Self::default()
50        }
51    }
52
53    pub fn feed_unread(feed_id: &FeedID) -> Self {
54        Self {
55            unread: Some(Read::Unread),
56            feeds: Some([feed_id.clone()].into()),
57            ..Self::default()
58        }
59    }
60
61    pub fn category_unread(category_id: &CategoryID) -> Self {
62        Self {
63            unread: Some(Read::Unread),
64            categories: Some([category_id.clone()].into()),
65            ..Self::default()
66        }
67    }
68
69    pub fn tag_unread(tag_id: &TagID) -> Self {
70        Self {
71            unread: Some(Read::Unread),
72            tags: Some([tag_id.clone()].into()),
73            ..Self::default()
74        }
75    }
76
77    pub fn all_unread() -> Self {
78        Self {
79            unread: Some(Read::Unread),
80            ..Self::default()
81        }
82    }
83
84    pub fn all_marked() -> Self {
85        Self {
86            marked: Some(Marked::Marked),
87            ..Self::default()
88        }
89    }
90
91    pub fn feeds_to_load(&self, category_mappings: &Vec<CategoryMapping>, feed_mappings: &Vec<FeedMapping>) -> HashSet<FeedID> {
92        let mut result = HashSet::new();
93
94        if let Some(feeds) = &self.feeds {
95            for feed_id in feeds {
96                result.insert(feed_id.clone());
97            }
98        }
99
100        if let Some(categories) = &self.categories {
101            for category_id in categories {
102                let feed_ids = Self::find_all_feeds(category_id, category_mappings, feed_mappings);
103                for feed_id in feed_ids {
104                    result.insert(feed_id);
105                }
106            }
107        }
108
109        result
110    }
111
112    pub fn feeds_to_blacklist(&self, category_mappings: &Vec<CategoryMapping>, feed_mappings: &Vec<FeedMapping>) -> HashSet<FeedID> {
113        let mut result = HashSet::new();
114
115        if let Some(feed_blacklist) = &self.feed_blacklist {
116            for feed_id in feed_blacklist {
117                result.insert(feed_id.clone());
118            }
119        }
120
121        if let Some(category_blacklist) = &self.category_blacklist {
122            for category_id in category_blacklist {
123                let feed_ids = Self::find_all_feeds(category_id, category_mappings, feed_mappings);
124                for feed_id in feed_ids {
125                    result.insert(feed_id);
126                }
127            }
128        }
129
130        result
131    }
132
133    fn find_all_feeds(category_id: &CategoryID, category_mappings: &Vec<CategoryMapping>, feed_mappings: &Vec<FeedMapping>) -> HashSet<FeedID> {
134        fn find_all_feeds_impl(
135            category_id: &CategoryID,
136            category_mappings: &Vec<CategoryMapping>,
137            feed_mappings: &Vec<FeedMapping>,
138            result: &mut HashSet<FeedID>,
139        ) {
140            for mapping in feed_mappings {
141                if &mapping.category_id == category_id {
142                    result.insert(mapping.feed_id.clone());
143                }
144            }
145
146            for mapping in category_mappings {
147                if &mapping.parent_id == category_id {
148                    find_all_feeds_impl(&mapping.category_id, category_mappings, feed_mappings, result);
149                }
150            }
151        }
152
153        let mut result = HashSet::new();
154        find_all_feeds_impl(category_id, category_mappings, feed_mappings, &mut result);
155        result
156    }
157}