Skip to main content

paperless_api/
saved_view.rs

1//! Types related to saved views in the paperless UI.
2
3use derive_more::Display;
4use paperless_api_macros::{CreateDto, Item, ReprSerde, UpdateDto};
5use serde::{Deserialize, Serialize};
6
7use crate::metadata::permission::ItemPermissions;
8
9/// A saved view in the paperless UI.
10#[derive(Debug, Default, Clone, Deserialize, Serialize, CreateDto, UpdateDto, Item)]
11#[api_info(endpoint = "saved_views")]
12pub struct SavedView {
13    /// The ID of the saved view.
14    #[dto(skip)]
15    pub id: crate::id::SavedViewId,
16
17    /// The name of the saved view.
18    pub name: String,
19
20    /// Whether the saved view should be shown on the dashboard.
21    pub show_on_dashboard: bool,
22
23    /// Whether the saved view should be shown in the sidebar.
24    pub show_in_sidebar: bool,
25
26    /// The field to sort the view by.
27    pub sort_field: Option<String>,
28
29    /// Whether to sort the view in reverse order.
30    pub sort_reverse: Option<bool>,
31
32    /// The filter rules determining which documents are shown in the view.
33    pub filter_rules: Option<Vec<FilterRule>>,
34
35    /// The display mode of the view.
36    pub display_mode: Option<DisplayMode>,
37
38    /// The fields to display in the view.
39    pub display_fields: Option<Vec<String>>,
40
41    /// The number of documents to show per page.
42    pub page_size: Option<u32>,
43
44    /// The user who owns the saved view.
45    #[dto(skip)]
46    pub owner: Option<crate::id::UserId>,
47
48    /// Permissions for the saved view.
49    #[dto(skip)]
50    #[serde(flatten)]
51    pub permissions: ItemPermissions,
52}
53
54/// The display mode of a saved view.
55#[derive(Debug, Clone, Deserialize, Serialize)]
56#[serde(rename_all = "camelCase")]
57pub enum DisplayMode {
58    Table,
59    SmallCards,
60    LargeCards,
61}
62
63/// A filter rule for a saved view.
64#[derive(Debug, Clone, Deserialize, Serialize)]
65pub struct FilterRule {
66    /// The type of filter rule.
67    #[serde(rename = "rule_type")]
68    pub rule: FilterRuleType,
69
70    /// The value associated with the filter rule.
71    pub value: Option<String>,
72}
73
74/// The type of a filter rule.
75#[derive(Debug, Clone, Copy, Display, ReprSerde)]
76#[repr(u8)]
77pub enum FilterRuleType {
78    TitleContains = 0,
79    ContentContains = 1,
80    AsnIs = 2,
81    CorrespondentIs = 3,
82    DocumentTypeIs = 4,
83    IsInInbox = 5,
84    HasTag = 6,
85    HasAnyTag = 7,
86    CreatedBefore = 8,
87    CreatedAfter = 9,
88    CreatedInYear = 10,
89    CreatedInMonth = 11,
90    CreatedDayIs = 12,
91    AddedBefore = 13,
92    AddedAfter = 14,
93    ModifiedBefore = 15,
94    ModifiedAfter = 16,
95    DoesNotHaveTag = 17,
96    DocumentHasNoAsn = 18,
97    TitleOrContentContains = 19,
98    FullTextSearch = 20,
99    SimilarDocuments = 21,
100    HasTagsIn = 22,
101    AsnGreaterThan = 23,
102    AsnLessThan = 24,
103    StoragePathIs = 25,
104    HasCorrespondentIn = 26,
105    HasNoCorrespondentIn = 27,
106    HasDocumentTypeIn = 28,
107    HasNoDocumentTypeIn = 29,
108    HasStoragePathIn = 30,
109    HasNoStoragePathIn = 31,
110    OwnerIs = 32,
111    HasOwnerIn = 33,
112    HasNoOwner = 34,
113    HasNoOwnerIn = 35,
114    HasCustomFieldValue = 36,
115    IsSharedByMe = 37,
116    HasCustomFields = 38,
117    HasTheCustomFields = 39,
118    DoesNotHaveCustomFields = 40,
119    DoesNotHaveCustomField = 41,
120    CustomFieldQuery = 42,
121    CreateDto = 43,
122    CreatedBy = 44,
123    AddedTo = 45,
124    AddedBy = 46,
125    MimeTypeIs = 47,
126
127    Unknown(u8),
128}
129
130#[cfg(test)]
131mod tests {
132    use super::*;
133
134    #[test]
135    fn filter_rule_type_boundary_values() {
136        let zero: FilterRuleType = serde_json::from_str("0").unwrap();
137        assert!(matches!(zero, FilterRuleType::TitleContains));
138
139        let forty_seven: FilterRuleType = serde_json::from_str("47").unwrap();
140        assert!(matches!(forty_seven, FilterRuleType::MimeTypeIs));
141
142        let forty_seven: FilterRuleType = serde_json::from_str("48").unwrap();
143        assert!(matches!(forty_seven, FilterRuleType::Unknown(48)));
144    }
145
146    #[test]
147    fn filter_rule_type_unknown_value_roundtrip() {
148        let unknown: FilterRuleType = serde_json::from_str("200").unwrap();
149        assert!(matches!(unknown, FilterRuleType::Unknown(200)));
150
151        let serialized = serde_json::to_string(&unknown).unwrap();
152        assert_eq!(serialized, "200");
153    }
154
155    #[test]
156    fn filter_rule_roundtrip_with_value() {
157        let rule = FilterRule {
158            rule: FilterRuleType::FullTextSearch,
159            value: Some("created:[-3 month to now]".to_string()),
160        };
161
162        let json = serde_json::to_string(&rule).unwrap();
163        let deserialized: FilterRule = serde_json::from_str(&json).unwrap();
164
165        assert!(matches!(deserialized.rule, FilterRuleType::FullTextSearch));
166        assert_eq!(
167            deserialized.value,
168            Some("created:[-3 month to now]".to_string())
169        );
170    }
171}