mimick/api_client/
features.rs1use serde_json::Value;
2
3use super::ImmichApiClient;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct LibraryFeatures {
7 pub trash: bool,
8 pub people: bool,
9 pub smart_search: bool,
10 pub ocr: bool,
11 pub places: bool,
12 pub search: bool,
13 pub tags: bool,
14 pub folders: bool,
15 pub shared_links: bool,
16 pub ratings: bool,
17}
18
19impl Default for LibraryFeatures {
20 fn default() -> Self {
21 Self::from_responses(None, None)
22 }
23}
24
25impl LibraryFeatures {
26 pub fn from_responses(server: Option<&Value>, preferences: Option<&Value>) -> Self {
27 let flag = |value: Option<&Value>, pointer: &str| {
28 value
29 .and_then(|value| value.pointer(pointer))
30 .and_then(Value::as_bool)
31 .unwrap_or(true)
32 };
33 let server_flag = |pointer| flag(server, pointer);
34 let preference = |pointer| flag(preferences, pointer);
35 Self {
36 trash: server_flag("/trash"),
37 people: server_flag("/facialRecognition") && preference("/people/enabled"),
38 smart_search: server_flag("/smartSearch"),
39 ocr: server_flag("/ocr"),
40 places: server_flag("/reverseGeocoding"),
41 search: server_flag("/search"),
42 tags: preference("/tags/enabled"),
43 folders: preference("/folders/enabled"),
44 shared_links: preference("/sharedLinks/enabled"),
45 ratings: preference("/ratings/enabled"),
46 }
47 }
48}
49
50impl ImmichApiClient {
51 pub async fn fetch_library_features(&self) -> LibraryFeatures {
52 let server = self.fetch_json("/api/server/features").await;
53 let preferences = self.fetch_json("/api/users/me/preferences").await;
54 LibraryFeatures::from_responses(server.as_ref(), preferences.as_ref())
55 }
56
57 async fn fetch_json(&self, path: &str) -> Option<Value> {
58 match self.send_json(reqwest::Method::GET, path, None).await {
59 Ok(resp) => resp.json().await.ok(),
60 Err(err) => {
61 log::debug!("Could not read {path}: {err}");
62 None
63 }
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn missing_responses_enable_everything() {
74 let features = LibraryFeatures::default();
75 assert!(features.trash && features.people && features.tags && features.ratings);
76 }
77
78 #[test]
79 fn server_and_account_flags_turn_features_off() {
80 let server = serde_json::json!({
81 "trash": false,
82 "facialRecognition": true,
83 "smartSearch": false,
84 "ocr": false,
85 "reverseGeocoding": true,
86 "search": true
87 });
88 let preferences = serde_json::json!({
89 "people": { "enabled": false, "sidebarWeb": true },
90 "tags": { "enabled": true, "sidebarWeb": false },
91 "ratings": { "enabled": false }
92 });
93 let features = LibraryFeatures::from_responses(Some(&server), Some(&preferences));
94 assert!(!features.trash);
95 assert!(!features.people);
96 assert!(!features.smart_search);
97 assert!(!features.ocr);
98 assert!(features.places);
99 assert!(features.tags);
100 assert!(features.folders);
101 assert!(!features.ratings);
102 }
103}