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