mimick/api_client/
people.rs1use super::{ImmichApiClient, Person};
2
3#[derive(Debug, serde::Deserialize)]
4struct PersonStatistics {
5 assets: u64,
6}
7
8#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize)]
9#[serde(rename_all = "camelCase")]
10pub struct PersonUpdate {
11 #[serde(skip_serializing_if = "Option::is_none")]
12 pub name: Option<String>,
13 #[serde(skip_serializing_if = "Option::is_none")]
14 pub is_hidden: Option<bool>,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub birth_date: Option<Option<String>>,
17 #[serde(skip_serializing_if = "Option::is_none")]
18 pub is_favorite: Option<bool>,
19}
20
21impl ImmichApiClient {
22 pub async fn update_person(
23 &self,
24 person_id: &str,
25 update: &PersonUpdate,
26 ) -> Result<(), String> {
27 let body = serde_json::to_value(update).map_err(|err| err.to_string())?;
28 let path = format!("/api/people/{person_id}");
29 self.send_json(reqwest::Method::PUT, &path, Some(body))
30 .await
31 .map(|_| ())
32 }
33
34 pub async fn fetch_person(&self, person_id: &str) -> Result<Person, String> {
35 let path = format!("/api/people/{person_id}");
36 let resp = self.send_json(reqwest::Method::GET, &path, None).await?;
37 resp.json().await.map_err(|err| err.to_string())
38 }
39
40 pub async fn person_asset_count(&self, person_id: &str) -> Result<u64, String> {
41 let path = format!("/api/people/{person_id}/statistics");
42 let resp = self.send_json(reqwest::Method::GET, &path, None).await?;
43 let stats: PersonStatistics = resp.json().await.map_err(|err| err.to_string())?;
44 Ok(stats.assets)
45 }
46
47 pub async fn merge_people(&self, into_id: &str, merge_ids: &[String]) -> Result<(), String> {
48 let path = format!("/api/people/{into_id}/merge");
49 let body = serde_json::json!({ "ids": merge_ids });
50 self.send_json(reqwest::Method::POST, &path, Some(body))
51 .await
52 .map(|_| ())
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn update_sends_only_set_fields() {
62 let rename = PersonUpdate {
63 name: Some("Ana".into()),
64 ..PersonUpdate::default()
65 };
66 assert_eq!(
67 serde_json::to_value(&rename).unwrap(),
68 serde_json::json!({ "name": "Ana" })
69 );
70 }
71
72 #[test]
73 fn clearing_a_birthday_sends_null() {
74 let clear = PersonUpdate {
75 birth_date: Some(None),
76 ..PersonUpdate::default()
77 };
78 assert_eq!(
79 serde_json::to_value(&clear).unwrap(),
80 serde_json::json!({ "birthDate": null })
81 );
82 }
83
84 #[test]
85 fn favorite_update_sends_is_favorite() {
86 let favorite = PersonUpdate {
87 is_favorite: Some(true),
88 ..PersonUpdate::default()
89 };
90 assert_eq!(
91 serde_json::to_value(&favorite).unwrap(),
92 serde_json::json!({ "isFavorite": true })
93 );
94 }
95
96 #[test]
97 fn person_json_reads_birth_date() {
98 let person: super::super::Person = serde_json::from_value(serde_json::json!({
99 "id": "p1",
100 "name": "Ana",
101 "isHidden": true,
102 "birthDate": "1990-05-04"
103 }))
104 .unwrap();
105 assert!(person.is_hidden);
106 assert_eq!(person.birth_date.as_deref(), Some("1990-05-04"));
107 }
108}