1pub const TRASH_PARENT_ID: &str = "__trash__";
8
9pub const MANAGED_PARENT_ID: &str = "__managed__";
13
14pub const ROOT_PARENT_ID: &str = "__root__";
19
20use async_trait::async_trait;
21use serde::{Deserialize, Serialize};
22use serde_with::skip_serializing_none;
23use std::{
24 cmp::Ordering,
25 collections::{HashMap, HashSet},
26 fmt::Debug,
27};
28
29use crate::{
30 prelude::*,
31 types::{serialize_timestamp_iso, serialize_timestamp_iso_opt},
32};
33
34#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq)]
37pub enum ProfileType {
38 #[default]
39 #[serde(rename = "person")]
40 Person,
41 #[serde(rename = "community")]
42 Community,
43}
44
45#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
46pub enum ProfileStatus {
47 #[serde(rename = "A")]
48 Active,
49 #[serde(rename = "B")]
50 Blocked,
51 #[serde(rename = "M")]
52 Muted,
53 #[serde(rename = "S")]
54 Suspended,
55 #[serde(rename = "X")]
56 Banned,
57}
58
59impl ProfileStatus {
60 pub fn as_str(&self) -> &'static str {
62 match self {
63 ProfileStatus::Active => "active",
64 ProfileStatus::Blocked => "blocked",
65 ProfileStatus::Muted => "muted",
66 ProfileStatus::Suspended => "suspended",
67 ProfileStatus::Banned => "banned",
68 }
69 }
70}
71
72#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
75#[serde(rename_all = "lowercase")]
76pub enum ProfileTrust {
77 Always,
79 Never,
81}
82
83#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq)]
84pub enum ProfileConnectionStatus {
85 #[default]
86 Disconnected,
87 RequestPending,
88 Connected,
89}
90
91impl ProfileConnectionStatus {
92 pub fn is_connected(&self) -> bool {
93 matches!(self, ProfileConnectionStatus::Connected)
94 }
95}
96
97impl std::fmt::Display for ProfileConnectionStatus {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 match self {
100 ProfileConnectionStatus::Disconnected => write!(f, "disconnected"),
101 ProfileConnectionStatus::RequestPending => write!(f, "pending"),
102 ProfileConnectionStatus::Connected => write!(f, "connected"),
103 }
104 }
105}
106
107pub const SHARE_FILE_REF_TYPE: &str = "share.file";
116pub const REGISTER_REF_TYPE: &str = "register";
118pub const PROFILE_INVITE_REF_TYPE: &str = "profile.invite";
120pub const PASSWORD_REF_TYPE: &str = "password";
122pub const WELCOME_REF_TYPE: &str = "welcome";
124pub const IDP_ACTIVATION_REF_TYPE: &str = "idp.activation";
126
127#[skip_serializing_none]
128#[derive(Debug, Clone, Serialize)]
129#[serde(rename_all = "camelCase")]
130pub struct RefData {
131 pub ref_id: Box<str>,
132 pub r#type: Box<str>,
133 pub description: Option<Box<str>>,
134 #[serde(serialize_with = "serialize_timestamp_iso")]
135 pub created_at: Timestamp,
136 #[serde(serialize_with = "serialize_timestamp_iso_opt")]
137 pub expires_at: Option<Timestamp>,
138 pub count: Option<u32>,
140 pub resource_id: Option<Box<str>>,
142 pub access_level: Option<char>,
145 pub params: Option<Box<str>>,
147}
148
149pub struct ListRefsOptions {
150 pub typ: Option<String>,
151 pub filter: Option<String>, pub resource_id: Option<String>,
154}
155
156#[derive(Default)]
157pub struct CreateRefOptions {
158 pub typ: String,
159 pub description: Option<String>,
160 pub expires_at: Option<Timestamp>,
161 pub count: Option<u32>,
162 pub resource_id: Option<String>,
164 pub access_level: Option<char>,
167 pub params: Option<String>,
169}
170
171#[derive(Debug, Default)]
177pub struct UpdateRefOptions {
178 pub description: Patch<String>,
179 pub expires_at: Patch<Timestamp>,
181 pub count: Patch<u32>,
183 pub access_level: Patch<char>,
185}
186
187#[skip_serializing_none]
188#[derive(Debug, Serialize)]
189#[serde(rename_all = "camelCase")]
190pub struct Tenant<S: AsRef<str>> {
191 #[serde(rename = "id")]
192 pub tn_id: TnId,
193 pub id_tag: S,
194 pub name: S,
195 #[serde(rename = "type")]
196 pub typ: ProfileType,
197 pub profile_pic: Option<S>,
198 pub cover_pic: Option<S>,
199 #[serde(serialize_with = "serialize_timestamp_iso")]
200 pub created_at: Timestamp,
201 #[serde(skip_serializing_if = "Option::is_none")]
203 pub last_seen_at: Option<Timestamp>,
204 #[serde(skip_serializing_if = "Option::is_none")]
206 pub notify_email_direct_at: Option<Timestamp>,
207 #[serde(skip_serializing_if = "Option::is_none")]
209 pub notify_email_engagement_at: Option<Timestamp>,
210 #[serde(skip_serializing_if = "Option::is_none")]
212 pub notify_email_social_at: Option<Timestamp>,
213 pub x: HashMap<S, S>,
214}
215
216#[derive(Debug, Default)]
218pub struct ListTenantsMetaOptions {
219 pub limit: Option<u32>,
220 pub offset: Option<u32>,
221}
222
223#[skip_serializing_none]
225#[derive(Debug, Clone, Serialize)]
226#[serde(rename_all = "camelCase")]
227pub struct TenantListMeta {
228 pub tn_id: TnId,
229 pub id_tag: Box<str>,
230 pub name: Box<str>,
231 #[serde(rename = "type")]
232 pub typ: ProfileType,
233 pub profile_pic: Option<Box<str>>,
234 #[serde(serialize_with = "serialize_timestamp_iso")]
235 pub created_at: Timestamp,
236}
237
238#[derive(Debug, Default, Deserialize)]
239pub struct UpdateTenantData {
240 #[serde(rename = "idTag", default)]
241 pub id_tag: Patch<String>,
242 #[serde(default)]
243 pub name: Patch<String>,
244 #[serde(rename = "type", default)]
245 pub typ: Patch<ProfileType>,
246 #[serde(rename = "profilePic", default)]
247 pub profile_pic: Patch<String>,
248 #[serde(rename = "coverPic", default)]
249 pub cover_pic: Patch<String>,
250 #[serde(default)]
252 pub x: Option<std::collections::HashMap<String, Option<String>>>,
253 #[serde(skip)]
256 pub last_seen_at: Patch<Timestamp>,
257 #[serde(skip)]
260 pub notify_email_direct_at: Patch<Timestamp>,
261 #[serde(skip)]
262 pub notify_email_engagement_at: Patch<Timestamp>,
263 #[serde(skip)]
264 pub notify_email_social_at: Patch<Timestamp>,
265}
266
267#[derive(Debug)]
268pub struct Profile<S: AsRef<str>> {
269 pub id_tag: S,
270 pub name: S,
271 pub typ: ProfileType,
272 pub profile_pic: Option<S>,
273 pub status: Option<ProfileStatus>,
274 pub synced_at: Option<Timestamp>,
275 pub following: bool,
276 pub follower: bool,
277 pub connected: ProfileConnectionStatus,
278 pub roles: Option<Box<[Box<str>]>>,
279 pub trust: Option<ProfileTrust>,
280 pub feed_read_at: Option<Timestamp>,
282 pub msg_read_at: Option<Timestamp>,
284 pub hidden_in_home: Option<bool>,
288}
289
290#[derive(Debug, Clone)]
296pub struct PublicProfileRow {
297 pub id_tag: Box<str>,
298 pub name: Box<str>,
299 pub typ: ProfileType,
300 pub profile_pic: Option<Box<str>>,
301}
302
303#[derive(Debug, Default, Deserialize)]
304pub struct ListProfileOptions {
305 #[serde(rename = "type")]
306 pub typ: Option<ProfileType>,
307 pub status: Option<Box<[ProfileStatus]>>,
308 pub connected: Option<ProfileConnectionStatus>,
309 pub following: Option<bool>,
310 pub follower: Option<bool>,
311 pub q: Option<String>,
312 pub id_tag: Option<String>,
313 pub trust_set: Option<bool>,
317 pub hidden_in_home: Option<bool>,
320 pub limit: Option<u32>,
324 pub after_id_tag: Option<String>,
326}
327
328#[derive(Debug, Clone, Serialize, Deserialize)]
330#[serde(rename_all = "camelCase")]
331pub struct ProfileData {
332 pub id_tag: Box<str>,
333 pub name: Box<str>,
334 #[serde(rename = "type")]
335 pub r#type: Box<str>, pub profile_pic: Option<Box<str>>,
337 #[serde(default, skip_serializing_if = "Option::is_none")]
339 pub status: Option<Box<str>>,
340 #[serde(serialize_with = "serialize_timestamp_iso")]
341 pub created_at: Timestamp,
342}
343
344#[derive(Debug, Clone, Serialize, Deserialize)]
346pub struct ProfileList {
347 pub profiles: Vec<ProfileData>,
348 pub total: usize,
349 pub limit: usize,
350 pub offset: usize,
351}
352
353#[derive(Debug, Default, Deserialize)]
354pub struct UpdateProfileData {
355 #[serde(default)]
357 pub name: Patch<Box<str>>,
358 #[serde(default, rename = "profilePic")]
359 pub profile_pic: Patch<Option<Box<str>>>,
360 #[serde(default)]
361 pub roles: Patch<Option<Vec<Box<str>>>>,
362
363 #[serde(default)]
365 pub status: Patch<ProfileStatus>,
366
367 #[serde(default)]
369 pub synced: Patch<bool>,
370 #[serde(default)]
371 pub trust: Patch<ProfileTrust>,
372 #[serde(default)]
375 pub hidden_in_home: Patch<bool>,
376
377 #[serde(default)]
379 pub etag: Patch<Box<str>>,
380}
381
382#[derive(Debug, Clone, Copy, PartialEq, Eq)]
384pub enum UpsertResult {
385 Created,
387 Updated,
389}
390
391#[derive(Default)]
412pub struct UpsertProfileFields {
413 pub name: Patch<Box<str>>,
414 pub typ: Patch<ProfileType>,
415 pub profile_pic: Patch<Option<Box<str>>>,
416 pub roles: Patch<Option<Vec<Box<str>>>>,
417 pub status: Patch<ProfileStatus>,
418 pub synced: Patch<bool>,
419 pub following: Patch<bool>,
420 pub follower: Patch<bool>,
421 pub connected: Patch<ProfileConnectionStatus>,
422 pub trust: Patch<ProfileTrust>,
423 pub hidden_in_home: Patch<bool>,
427 pub etag: Patch<Box<str>>,
428}
429
430impl UpsertProfileFields {
431 pub fn affects_search_index(&self) -> bool {
436 !matches!(self.name, Patch::Undefined)
437 }
438
439 pub fn from_update(update: UpdateProfileData) -> Self {
444 Self {
445 name: update.name,
446 typ: Patch::Undefined,
447 profile_pic: update.profile_pic,
448 roles: update.roles,
449 status: update.status,
450 synced: update.synced,
451 following: Patch::Undefined,
455 follower: Patch::Undefined,
456 connected: Patch::Undefined,
457 trust: update.trust,
458 hidden_in_home: update.hidden_in_home,
459 etag: update.etag,
460 }
461 }
462}
463
464#[derive(Debug, Clone)]
469pub struct ActionData {
470 pub subject: Option<Box<str>>,
471 pub reactions: Option<Box<str>>,
472 pub comments: Option<i64>,
474 pub comments_ts: Option<Timestamp>,
477 pub stat_at: Option<Timestamp>,
484}
485
486#[derive(Debug, Clone, Default)]
488pub struct UpdateActionDataOptions {
489 pub subject: Patch<String>,
490 pub reactions: Patch<String>,
491 pub comments: Patch<u32>,
493 pub comments_ts: Patch<Timestamp>,
495 pub reposts: Patch<u32>,
496 pub stat_at: Patch<Timestamp>,
498 pub status: Patch<char>,
499 pub visibility: Patch<char>,
500 pub x: Patch<serde_json::Value>, pub content: Patch<String>,
502 pub attachments: Patch<String>, pub flags: Patch<String>,
504 pub sub_level: Patch<char>,
506 pub sub_typ: Patch<String>,
507 pub created_at: Patch<Timestamp>,
514}
515
516impl UpdateActionDataOptions {
517 pub fn affects_search_index(&self) -> bool {
522 !matches!(
523 (&self.content, &self.status, &self.visibility, &self.sub_typ),
524 (Patch::Undefined, Patch::Undefined, Patch::Undefined, Patch::Undefined)
525 )
526 }
527}
528
529#[derive(Debug, Clone, Default)]
531pub struct FinalizeActionOptions<'a> {
532 pub attachments: Option<&'a [&'a str]>,
533 pub subject: Option<&'a str>,
534 pub audience_tag: Option<&'a str>,
535 pub key: Option<&'a str>,
536}
537
538fn deserialize_split<'de, D>(deserializer: D) -> Result<Option<Vec<String>>, D::Error>
539where
540 D: serde::Deserializer<'de>,
541{
542 let s = String::deserialize(deserializer)?;
543 let values: Vec<String> =
544 s.split(',').map(|v| v.trim().to_string()).filter(|v| !v.is_empty()).collect();
545 if values.is_empty() { Ok(None) } else { Ok(Some(values)) }
546}
547
548#[derive(Debug, Clone, Copy, Deserialize)]
554#[serde(rename_all = "lowercase")]
555pub enum AudienceType {
556 Personal,
557 Community,
558}
559
560#[derive(Debug, Clone, Copy)]
563pub enum ActionCountGroupBy {
564 SubType,
565}
566
567#[derive(Debug, Default, Deserialize)]
569#[serde(deny_unknown_fields)]
570pub struct ListActionOptions {
571 pub limit: Option<u32>,
573 pub cursor: Option<String>,
575 pub sort: Option<String>,
579 #[serde(rename = "sortDir")]
581 pub sort_dir: Option<String>,
582 #[serde(default, rename = "type", deserialize_with = "deserialize_split")]
583 pub typ: Option<Vec<String>>,
584 #[serde(default, deserialize_with = "deserialize_split")]
585 pub status: Option<Vec<String>>,
586 pub tag: Option<String>,
587 pub search: Option<String>,
588 #[serde(default, deserialize_with = "deserialize_split")]
589 pub visibility: Option<Vec<String>>,
590 pub issuer: Option<String>,
591 pub audience: Option<String>,
592 #[serde(rename = "audienceType")]
593 pub audience_type: Option<AudienceType>,
594 pub involved: Option<String>,
595 #[serde(skip)]
597 pub viewer_id_tag: Option<String>,
598 #[serde(rename = "actionId")]
599 pub action_id: Option<String>,
600 #[serde(rename = "parentId")]
601 pub parent_id: Option<String>,
602 #[serde(rename = "rootId")]
603 pub root_id: Option<String>,
604 #[serde(default, deserialize_with = "deserialize_split")]
605 pub subject: Option<Vec<String>>,
606 #[serde(rename = "createdAfter")]
607 pub created_after: Option<Timestamp>,
608 #[serde(rename = "createdBefore")]
609 pub created_before: Option<Timestamp>,
610 pub subscribed: Option<bool>,
613 #[serde(rename = "includeTokens")]
616 pub include_tokens: Option<bool>,
617 #[serde(rename = "includeSubject")]
623 pub include_subject: Option<bool>,
624 #[serde(skip)]
628 pub exclude_issuer_profile_status: Option<Box<[ProfileStatus]>>,
629 #[serde(skip)]
634 pub exclude_sub_typ: Option<Box<[Box<str>]>>,
635 #[serde(skip)]
640 pub exclude_audiences: Option<Box<[String]>>,
641 #[serde(rename = "excludeOwnIssuer")]
644 pub exclude_own_issuer: Option<bool>,
645 pub count: Option<bool>,
649 #[serde(skip)]
660 pub visibility_guard: Patch<String>,
661}
662
663#[skip_serializing_none]
664#[derive(Debug, Clone, Serialize, serde::Deserialize)]
665pub struct ProfileInfo {
666 #[serde(rename = "idTag")]
667 pub id_tag: Box<str>,
668 pub name: Box<str>,
669 #[serde(rename = "type")]
670 pub typ: ProfileType,
671 #[serde(rename = "profilePic")]
672 pub profile_pic: Option<Box<str>>,
673}
674
675#[derive(Default)]
676pub struct Action<S: AsRef<str>> {
677 pub action_id: S,
678 pub typ: S,
679 pub sub_typ: Option<S>,
680 pub issuer_tag: S,
681 pub parent_id: Option<S>,
682 pub root_id: Option<S>,
683 pub audience_tag: Option<S>,
684 pub content: Option<S>,
685 pub attachments: Option<Vec<S>>,
686 pub subject: Option<S>,
687 pub created_at: Timestamp,
688 pub expires_at: Option<Timestamp>,
689 pub visibility: Option<char>, pub flags: Option<S>, pub x: Option<serde_json::Value>, }
693
694#[skip_serializing_none]
695#[derive(Debug, Clone, Serialize)]
696pub struct AttachmentView {
697 #[serde(rename = "fileId")]
698 pub file_id: Box<str>,
699 pub dim: Option<(u32, u32)>,
700 #[serde(rename = "localVariants")]
701 pub local_variants: Option<Vec<Box<str>>>,
702}
703
704#[skip_serializing_none]
705#[derive(Debug, Clone, Serialize)]
706#[serde(rename_all = "camelCase")]
707pub struct ActionView {
708 pub action_id: Box<str>,
709 #[serde(rename = "type")]
710 pub typ: Box<str>,
711 #[serde(rename = "subType")]
712 pub sub_typ: Option<Box<str>>,
713 pub parent_id: Option<Box<str>>,
714 pub root_id: Option<Box<str>>,
715 pub issuer: ProfileInfo,
716 pub audience: Option<ProfileInfo>,
717 pub content: Option<serde_json::Value>,
718 pub attachments: Option<Vec<AttachmentView>>,
719 pub subject: Option<Box<str>>,
720 pub subject_profile: Option<ProfileInfo>,
721 #[serde(default, skip_serializing_if = "Option::is_none")]
726 pub subject_action: Option<Box<ActionView>>,
727 #[serde(serialize_with = "serialize_timestamp_iso")]
728 pub created_at: Timestamp,
729 #[serde(
735 serialize_with = "serialize_timestamp_iso_opt",
736 skip_serializing_if = "Option::is_none"
737 )]
738 pub received_at: Option<Timestamp>,
739 #[serde(serialize_with = "serialize_timestamp_iso_opt")]
740 pub expires_at: Option<Timestamp>,
741 pub status: Option<Box<str>>,
742 pub stat: Option<serde_json::Value>,
743 pub visibility: Option<char>,
744 pub flags: Option<Box<str>>, #[serde(rename = "subLevel", skip_serializing_if = "Option::is_none")]
747 pub sub_level: Option<Box<str>>,
748 pub x: Option<serde_json::Value>, #[serde(default, skip_serializing_if = "Option::is_none")]
752 pub token: Option<Box<str>>,
753}
754
755#[derive(Debug)]
758pub enum FileId<S: AsRef<str>> {
759 FileId(S),
760 FId(u64),
761}
762
763pub enum ActionId<S: AsRef<str>> {
764 ActionId(S),
765 AId(u64),
766}
767
768#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
771pub enum FileStatus {
772 #[serde(rename = "A")]
773 Active,
774 #[serde(rename = "P")]
775 Pending,
776 #[serde(rename = "D")]
777 Deleted,
778}
779
780#[skip_serializing_none]
782#[derive(Debug, Clone, Default, Serialize, serde::Deserialize)]
783#[serde(rename_all = "camelCase")]
784pub struct FileUserData {
785 #[serde(default, serialize_with = "serialize_timestamp_iso_opt")]
786 pub accessed_at: Option<Timestamp>,
787 #[serde(default, serialize_with = "serialize_timestamp_iso_opt")]
788 pub modified_at: Option<Timestamp>,
789 #[serde(default)]
790 pub pinned: bool,
791 #[serde(default)]
792 pub starred: bool,
793 #[serde(default)]
799 pub access_level: Option<crate::types::AccessLevel>,
800}
801
802#[skip_serializing_none]
803#[derive(Debug, Clone, Serialize, serde::Deserialize)]
804#[serde(rename_all = "camelCase")]
805pub struct FileView {
806 pub file_id: Box<str>,
807 #[serde(default)]
808 pub parent_id: Option<Box<str>>, #[serde(default)]
810 pub root_id: Option<Box<str>>, #[serde(default)]
812 pub owner: Option<ProfileInfo>,
813 #[serde(skip)]
821 pub owner_tag: Option<Box<str>>,
822 #[serde(default)]
823 pub creator: Option<ProfileInfo>,
824 #[serde(default)]
825 pub preset: Option<Box<str>>,
826 #[serde(default)]
827 pub content_type: Option<Box<str>>,
828 pub file_name: Box<str>,
829 #[serde(default)]
830 pub file_tp: Option<Box<str>>, #[serde(serialize_with = "serialize_timestamp_iso")]
832 pub created_at: Timestamp,
833 #[serde(default, serialize_with = "crate::types::serialize_timestamp_iso_opt")]
834 pub accessed_at: Option<Timestamp>, #[serde(default, serialize_with = "crate::types::serialize_timestamp_iso_opt")]
836 pub modified_at: Option<Timestamp>, pub status: FileStatus,
838 #[serde(default)]
839 pub tags: Option<Vec<Box<str>>>,
840 #[serde(default)]
841 pub visibility: Option<char>, #[serde(default)]
847 pub hidden: bool,
848 #[serde(default)]
849 pub access_level: Option<crate::types::AccessLevel>, #[serde(default)]
851 pub user_data: Option<FileUserData>, #[serde(default)]
853 pub x: Option<serde_json::Value>, #[serde(default)]
858 pub parent_name: Option<Box<str>>,
859 #[serde(default)]
863 pub path: Option<Vec<PathSegment>>,
864 #[serde(default, serialize_with = "crate::types::serialize_timestamp_iso_opt")]
871 pub broken_at: Option<Timestamp>,
872 #[serde(default)]
875 pub broken_reason: Option<BrokenReason>,
876}
877
878#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
884#[serde(rename_all = "lowercase")]
885pub enum BrokenReason {
886 Deleted,
888 Revoked,
890}
891
892impl BrokenReason {
893 pub fn as_str(&self) -> &'static str {
894 match self {
895 Self::Deleted => "deleted",
896 Self::Revoked => "revoked",
897 }
898 }
899}
900
901#[derive(Debug, Clone, Serialize, serde::Deserialize)]
903#[serde(rename_all = "camelCase")]
904pub struct PathSegment {
905 pub id: Box<str>,
906 pub name: Box<str>,
907}
908
909#[skip_serializing_none]
910#[derive(Debug, Clone, Serialize)]
911pub struct FileVariant<S: AsRef<str> + Debug> {
912 #[serde(rename = "variantId")]
913 pub variant_id: S,
914 pub variant: S,
915 pub format: S,
916 pub size: u64,
917 pub resolution: (u32, u32),
918 pub available: bool,
919 #[serde(skip_serializing_if = "std::ops::Not::not")]
921 pub global: bool,
922 pub duration: Option<f64>,
924 pub bitrate: Option<u32>,
926 #[serde(rename = "pageCount")]
928 pub page_count: Option<u32>,
929}
930
931impl<S: AsRef<str> + Debug> PartialEq for FileVariant<S> {
934 fn eq(&self, other: &Self) -> bool {
935 self.variant_id.as_ref() == other.variant_id.as_ref()
936 && self.variant.as_ref() == other.variant.as_ref()
937 && self.format.as_ref() == other.format.as_ref()
938 && self.size == other.size
939 && self.resolution == other.resolution
940 && self.available == other.available
941 && self.duration == other.duration
942 && self.bitrate == other.bitrate
943 && self.page_count == other.page_count
944 }
945}
946
947impl<S: AsRef<str> + Debug> Eq for FileVariant<S> {}
948
949impl<S: AsRef<str> + Debug + Ord> PartialOrd for FileVariant<S> {
950 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
951 Some(self.cmp(other))
952 }
953}
954
955impl<S: AsRef<str> + Debug + Ord> Ord for FileVariant<S> {
956 fn cmp(&self, other: &Self) -> Ordering {
957 self.size
958 .cmp(&other.size)
959 .then_with(|| self.resolution.0.cmp(&other.resolution.0))
960 .then_with(|| self.resolution.1.cmp(&other.resolution.1))
961 .then_with(|| self.variant.as_ref().cmp(other.variant.as_ref()))
962 }
963}
964
965#[derive(Debug, Default, Deserialize)]
970#[serde(deny_unknown_fields)]
971#[allow(clippy::struct_excessive_bools)]
972pub struct ListFileOptions {
973 pub limit: Option<u32>,
975 pub cursor: Option<String>,
977 #[serde(default, rename = "fileId", deserialize_with = "deserialize_split")]
978 pub file_id: Option<Vec<String>>,
979 #[serde(rename = "parentId")]
980 pub parent_id: Option<String>, #[serde(rename = "notParentId")]
985 pub not_parent_id: Option<String>,
986 #[serde(rename = "rootId")]
987 pub root_id: Option<String>, pub tag: Option<String>,
989 pub preset: Option<String>,
990 pub variant: Option<String>,
991 pub status: Option<FileStatus>,
993 #[serde(default, rename = "fileTp", deserialize_with = "deserialize_split")]
994 pub file_type: Option<Vec<String>>,
995 #[serde(default, rename = "contentType", deserialize_with = "deserialize_split")]
997 pub content_type: Option<Vec<String>>,
998 #[serde(default, rename = "includeFolders")]
1001 pub include_folders: bool,
1002 #[serde(rename = "fileName")]
1004 pub file_name: Option<String>,
1005 #[serde(rename = "ownerIdTag")]
1007 pub owner_id_tag: Option<String>,
1008 #[serde(rename = "notOwnerIdTag")]
1010 pub not_owner_id_tag: Option<String>,
1011 #[serde(default, rename = "localOnly")]
1016 pub local_only: bool,
1017 pub pinned: Option<bool>,
1019 pub starred: Option<bool>,
1021 pub hidden: Option<bool>,
1026 pub sort: Option<String>,
1028 #[serde(rename = "sortDir")]
1030 pub sort_dir: Option<String>,
1031 #[serde(skip)]
1033 pub user_id_tag: Option<String>,
1034 #[serde(skip)]
1037 pub scope_file_id: Option<String>,
1038 #[serde(skip)]
1042 pub visible_levels: Option<Vec<char>>,
1043 #[serde(skip)]
1048 pub include_tree_children: bool,
1049 #[serde(skip)]
1054 pub sweep_all: bool,
1055 #[serde(default, rename = "withParent")]
1059 pub with_parent: bool,
1060 #[serde(default, rename = "withPath")]
1063 pub with_path: bool,
1064}
1065
1066#[derive(Debug, Clone, Default)]
1067pub struct CreateFile {
1068 pub orig_variant_id: Option<Box<str>>,
1069 pub file_id: Option<Box<str>>,
1070 pub parent_id: Option<Box<str>>, pub root_id: Option<Box<str>>, pub owner_tag: Option<Box<str>>, pub creator_tag: Option<Box<str>>, pub preset: Option<Box<str>>,
1075 pub content_type: Box<str>,
1076 pub file_name: Box<str>,
1077 pub file_tp: Option<Box<str>>, pub created_at: Option<Timestamp>,
1079 pub tags: Option<Vec<Box<str>>>,
1080 pub x: Option<serde_json::Value>,
1081 pub visibility: Option<char>, pub hidden: bool,
1085 pub status: Option<FileStatus>, }
1087
1088#[derive(Debug, Clone, Deserialize)]
1089pub struct CreateFileVariant {
1090 pub variant: Box<str>,
1091 pub format: Box<str>,
1092 pub resolution: (u32, u32),
1093 pub size: u64,
1094 pub available: bool,
1095}
1096
1097#[derive(Debug, Clone, Default, Deserialize)]
1099pub struct UpdateFileOptions {
1100 #[serde(default, rename = "fileName")]
1101 pub file_name: Patch<String>,
1102 #[serde(default, rename = "parentId")]
1103 pub parent_id: Patch<String>, #[serde(default)]
1105 pub visibility: Patch<char>,
1106 #[serde(default)]
1107 pub status: Patch<char>,
1108 #[serde(default)]
1111 pub hidden: Patch<bool>,
1112 #[serde(default, rename = "contentType", skip_deserializing)]
1115 pub content_type: Patch<String>,
1116 #[serde(default, rename = "fileTp", skip_deserializing)]
1117 pub file_tp: Patch<String>,
1118 #[serde(default, skip_deserializing)]
1119 pub tags: Patch<Vec<String>>,
1120 #[serde(default, skip_deserializing)]
1121 pub preset: Patch<String>,
1122 #[serde(default, skip_deserializing)]
1123 pub x: Patch<serde_json::Value>,
1124 #[serde(default, skip_deserializing)]
1128 pub broken: Patch<BrokenReason>,
1129}
1130
1131impl UpdateFileOptions {
1132 pub fn affects_search_index(&self) -> bool {
1141 !matches!(
1142 (
1143 &self.file_name,
1144 &self.visibility,
1145 &self.status,
1146 &self.content_type,
1147 &self.tags,
1148 &self.parent_id,
1149 &self.hidden,
1150 ),
1151 (
1152 Patch::Undefined,
1153 Patch::Undefined,
1154 Patch::Undefined,
1155 Patch::Undefined,
1156 Patch::Undefined,
1157 Patch::Undefined,
1158 Patch::Undefined
1159 )
1160 )
1161 }
1162}
1163
1164#[derive(Debug, Clone, Default)]
1166pub struct DeleteFileResult {
1167 pub file_ids: Vec<Box<str>>,
1171 pub files_deleted: u64,
1174 pub refs_removed: u64,
1175 pub share_entries_removed: u64,
1176}
1177
1178#[skip_serializing_none]
1182#[derive(Debug, Clone, Serialize)]
1183#[serde(rename_all = "camelCase")]
1184pub struct ShareEntry {
1185 pub id: i64,
1186 pub resource_type: char,
1187 pub resource_id: Box<str>,
1188 pub subject_type: char,
1189 pub subject_id: Box<str>,
1190 pub permission: char,
1191 #[serde(serialize_with = "serialize_timestamp_iso_opt")]
1192 pub expires_at: Option<Timestamp>,
1193 pub created_by: Box<str>,
1194 #[serde(serialize_with = "serialize_timestamp_iso")]
1195 pub created_at: Timestamp,
1196 pub subject_file_name: Option<Box<str>>,
1198 pub subject_content_type: Option<Box<str>>,
1199 pub subject_file_tp: Option<Box<str>>,
1200}
1201
1202#[derive(Debug, Deserialize)]
1203#[serde(rename_all = "camelCase")]
1204pub struct CreateShareEntry {
1205 pub subject_type: char,
1206 pub subject_id: String,
1207 pub permission: char,
1208 pub expires_at: Option<Timestamp>,
1209}
1210
1211#[derive(Debug, Default)]
1218pub struct UpdateShareEntryOptions {
1219 pub permission: Patch<char>,
1222 pub expires_at: Patch<Timestamp>,
1224}
1225
1226#[skip_serializing_none]
1231#[derive(Debug, Clone, Serialize, Deserialize)]
1232pub struct PushSubscriptionData {
1233 pub endpoint: String,
1235 #[serde(rename = "expirationTime")]
1237 pub expiration_time: Option<i64>,
1238 pub keys: PushSubscriptionKeys,
1240}
1241
1242#[derive(Debug, Clone, Serialize, Deserialize)]
1244pub struct PushSubscriptionKeys {
1245 pub p256dh: String,
1247 pub auth: String,
1249}
1250
1251#[derive(Debug, Clone, Serialize)]
1253#[serde(rename_all = "camelCase")]
1254pub struct PushSubscription {
1255 pub id: u64,
1257 pub subscription: PushSubscriptionData,
1259 #[serde(serialize_with = "serialize_timestamp_iso")]
1261 pub created_at: Timestamp,
1262}
1263
1264pub struct Task {
1267 pub task_id: u64,
1268 pub tn_id: TnId,
1269 pub kind: Box<str>,
1270 pub status: char,
1271 pub created_at: Timestamp,
1272 pub next_at: Option<Timestamp>,
1273 pub input: Box<str>,
1274 pub output: Box<str>,
1275 pub deps: Box<[u64]>,
1276 pub retry: Option<Box<str>>,
1277 pub cron: Option<Box<str>>,
1278}
1279
1280#[derive(Debug, Default)]
1281pub struct TaskPatch {
1282 pub input: Patch<String>,
1283 pub next_at: Patch<Timestamp>,
1284 pub deps: Patch<Vec<u64>>,
1285 pub retry: Patch<String>,
1286 pub cron: Patch<String>,
1287}
1288
1289#[derive(Debug, Default)]
1290pub struct ListTaskOptions {}
1291
1292#[derive(Debug)]
1297pub struct InstallApp {
1298 pub app_name: Box<str>,
1299 pub publisher_tag: Box<str>,
1300 pub version: Box<str>,
1301 pub action_id: Box<str>,
1302 pub file_id: Box<str>,
1303 pub blob_id: Box<str>,
1304 pub capabilities: Option<Vec<Box<str>>>,
1305}
1306
1307#[derive(Debug, Serialize)]
1309#[serde(rename_all = "camelCase")]
1310pub struct InstalledApp {
1311 pub app_name: Box<str>,
1312 pub publisher_tag: Box<str>,
1313 pub version: Box<str>,
1314 pub action_id: Box<str>,
1315 pub file_id: Box<str>,
1316 pub blob_id: Box<str>,
1317 pub status: Box<str>,
1318 pub capabilities: Option<Vec<Box<str>>>,
1319 pub auto_update: bool,
1320 #[serde(serialize_with = "serialize_timestamp_iso")]
1321 pub installed_at: Timestamp,
1322}
1323
1324#[derive(Debug, Default)]
1333pub struct SearchPart<'a> {
1334 pub part_id: &'a str,
1336 pub part_kind: Option<&'a str>,
1338 pub parent_part: Option<&'a str>,
1340 pub anchor_id: Option<&'a str>,
1342 pub title: Option<&'a str>,
1343 pub body: Option<&'a str>,
1344 pub tags: Option<&'a str>,
1346}
1347
1348#[derive(Debug, Default)]
1352pub struct SearchObject<'a> {
1353 pub obj_tp: char,
1355 pub obj_id: &'a str,
1357 pub content_type: Option<&'a str>,
1358 pub owner_tag: Option<&'a str>,
1359 pub visibility: Option<char>,
1361 pub root_id: Option<&'a str>,
1362 pub created_at: Option<Timestamp>,
1363 pub fts_cl: bool,
1372}
1373
1374pub const SEARCH_MAX_LIMIT: u32 = 100;
1379pub const SEARCH_MAX_OFFSET: u32 = 1000;
1380
1381pub const SEARCH_MAX_TAGS: usize = 16;
1385pub const SEARCH_MAX_CONTENT_TYPES: usize = 16;
1386
1387#[derive(Debug, Default)]
1390pub struct SearchOptions {
1391 pub q: String,
1393 pub obj_tp: Option<Vec<char>>,
1394 pub file_id: Option<String>,
1396 pub content_type: Option<Vec<String>>,
1397 pub tags: Option<Vec<String>>,
1401 pub limit: u32,
1402 pub offset: u32,
1403
1404 pub visible_levels: Option<Vec<char>>,
1408 pub viewer_id_tag: Option<String>,
1409 pub scope_file_id: Option<String>,
1411 pub scope_grant_file_id: Option<Box<str>>,
1416 pub fts_cl: bool,
1421}
1422
1423#[derive(Debug, Clone, Copy, Serialize)]
1433pub struct SearchMatch {
1434 pub start: u32,
1435 pub end: u32,
1436}
1437
1438#[derive(Debug)]
1440pub struct SearchRow {
1441 pub s_id: i64,
1442 pub obj_tp: char,
1443 pub obj_id: Box<str>,
1444 pub part_id: Box<str>,
1445 pub part_kind: Option<Box<str>>,
1446 pub parent_part: Option<Box<str>>,
1447 pub anchor_id: Option<Box<str>>,
1448 pub title: Option<Box<str>>,
1449 pub tags: Option<Box<str>>,
1450 pub content_type: Option<Box<str>>,
1451 pub owner_tag: Option<Box<str>>,
1452 pub visibility: Option<char>,
1453 pub root_id: Option<Box<str>>,
1454 pub updated_at: Timestamp,
1455 pub snippet: Option<Box<str>>,
1466 pub snippet_matches: Option<Box<[SearchMatch]>>,
1469 pub score: f64,
1471}
1472
1473#[derive(Debug, Clone, Copy, Default)]
1483pub struct SpaceReport {
1484 pub page_size: i64,
1485 pub page_count: i64,
1486 pub freelist_count: i64,
1487 pub vacuumed: bool,
1490}
1491
1492#[derive(Debug, Clone, Serialize)]
1494#[serde(rename_all = "camelCase")]
1495pub struct DocFormat {
1496 pub content_type: Box<str>,
1497 pub publisher_tag: Box<str>,
1498 pub app_name: Box<str>,
1499 #[serde(skip_serializing_if = "Option::is_none")]
1503 pub format_version: Option<i64>,
1504 #[serde(skip_serializing_if = "Option::is_none")]
1506 pub store_tp: Option<Box<str>>,
1507 #[serde(skip_serializing_if = "Option::is_none")]
1509 pub nav_param: Option<Box<str>>,
1510 #[serde(skip_serializing_if = "Option::is_none")]
1512 pub search: Option<serde_json::Value>,
1513 #[serde(skip_serializing_if = "Option::is_none")]
1514 pub x: Option<serde_json::Value>,
1515 #[serde(serialize_with = "serialize_timestamp_iso")]
1516 pub updated_at: Timestamp,
1517}
1518
1519#[derive(Debug)]
1521pub struct UpsertDocFormat<'a> {
1522 pub content_type: &'a str,
1523 pub publisher_tag: &'a str,
1524 pub app_name: &'a str,
1525 pub format_version: Option<i64>,
1526 pub store_tp: Option<&'a str>,
1527 pub nav_param: Option<&'a str>,
1528 pub search: Option<&'a serde_json::Value>,
1529 pub x: Option<&'a serde_json::Value>,
1530}
1531
1532#[derive(Debug, Clone, Serialize)]
1537#[serde(rename_all = "camelCase")]
1538pub struct AddressBook {
1539 pub ab_id: u64,
1540 pub name: Box<str>,
1541 pub description: Option<Box<str>>,
1542 pub ctag: Box<str>,
1544 #[serde(serialize_with = "serialize_timestamp_iso")]
1545 pub created_at: Timestamp,
1546 #[serde(serialize_with = "serialize_timestamp_iso")]
1547 pub updated_at: Timestamp,
1548}
1549
1550#[derive(Debug, Default)]
1551pub struct UpdateAddressBookData {
1552 pub name: Patch<String>,
1553 pub description: Patch<String>,
1554}
1555
1556#[derive(Debug, Clone, Default)]
1560pub struct ContactExtracted {
1561 pub fn_name: Option<Box<str>>,
1562 pub given_name: Option<Box<str>>,
1563 pub family_name: Option<Box<str>>,
1564 pub email: Option<Box<str>>,
1565 pub emails: Option<Box<str>>,
1566 pub tel: Option<Box<str>>,
1567 pub tels: Option<Box<str>>,
1568 pub org: Option<Box<str>>,
1569 pub title: Option<Box<str>>,
1570 pub note: Option<Box<str>>,
1571 pub photo_uri: Option<Box<str>>,
1572 pub profile_id_tag: Option<Box<str>>,
1573}
1574
1575#[derive(Debug, Clone)]
1577pub struct Contact {
1578 pub c_id: u64,
1579 pub ab_id: u64,
1580 pub uid: Box<str>,
1581 pub etag: Box<str>,
1582 pub vcard: Box<str>,
1583 pub extracted: ContactExtracted,
1584 pub created_at: Timestamp,
1585 pub updated_at: Timestamp,
1586}
1587
1588#[derive(Debug, Clone)]
1591pub struct ContactView {
1592 pub c_id: u64,
1593 pub ab_id: u64,
1594 pub uid: Box<str>,
1595 pub etag: Box<str>,
1596 pub extracted: ContactExtracted,
1597 pub created_at: Timestamp,
1598 pub updated_at: Timestamp,
1599}
1600
1601#[derive(Debug, Clone)]
1604pub struct ContactSyncEntry {
1605 pub uid: Box<str>,
1606 pub etag: Box<str>,
1607 pub deleted: bool,
1608 pub updated_at: Timestamp,
1609}
1610
1611#[derive(Debug, Default)]
1612pub struct ListContactOptions {
1613 pub q: Option<String>,
1615 pub cursor: Option<String>,
1617 pub limit: Option<u32>,
1619}
1620
1621#[derive(Debug, Clone, Serialize)]
1626#[serde(rename_all = "camelCase")]
1627pub struct Calendar {
1628 pub cal_id: u64,
1629 pub name: Box<str>,
1630 pub description: Option<Box<str>>,
1631 pub color: Option<Box<str>>,
1633 pub timezone: Option<Box<str>>,
1635 pub components: Box<str>,
1637 pub ctag: Box<str>,
1639 #[serde(serialize_with = "serialize_timestamp_iso")]
1640 pub created_at: Timestamp,
1641 #[serde(serialize_with = "serialize_timestamp_iso")]
1642 pub updated_at: Timestamp,
1643}
1644
1645#[derive(Debug, Default)]
1646pub struct CreateCalendarData {
1647 pub name: String,
1648 pub description: Option<String>,
1649 pub color: Option<String>,
1650 pub timezone: Option<String>,
1651 pub components: Option<String>,
1653}
1654
1655#[derive(Debug, Default)]
1656pub struct UpdateCalendarData {
1657 pub name: Patch<String>,
1658 pub description: Patch<String>,
1659 pub color: Patch<String>,
1660 pub timezone: Patch<String>,
1661 pub components: Patch<String>,
1662}
1663
1664#[derive(Debug, Clone, Default)]
1667pub struct CalendarObjectExtracted {
1668 pub component: Box<str>,
1670 pub summary: Option<Box<str>>,
1671 pub location: Option<Box<str>>,
1672 pub description: Option<Box<str>>,
1673 pub dtstart: Option<Timestamp>,
1675 pub dtend: Option<Timestamp>,
1677 pub all_day: bool,
1679 pub status: Option<Box<str>>,
1681 pub priority: Option<u8>,
1683 pub organizer: Option<Box<str>>,
1684 pub rrule: Option<Box<str>>,
1686 pub exdate: Vec<Timestamp>,
1688 pub recurrence_id: Option<Timestamp>,
1690 pub sequence: i64,
1691}
1692
1693#[derive(Debug, Clone, Copy)]
1698pub struct CalendarObjectWrite<'a> {
1699 pub uid: &'a str,
1700 pub ical: &'a str,
1701 pub etag: &'a str,
1702 pub extracted: &'a CalendarObjectExtracted,
1703}
1704
1705#[derive(Debug, Clone)]
1707pub struct CalendarObject {
1708 pub co_id: u64,
1709 pub cal_id: u64,
1710 pub uid: Box<str>,
1711 pub etag: Box<str>,
1712 pub ical: Box<str>,
1713 pub extracted: CalendarObjectExtracted,
1714 pub created_at: Timestamp,
1715 pub updated_at: Timestamp,
1716}
1717
1718#[derive(Debug, Clone)]
1720pub struct CalendarObjectView {
1721 pub co_id: u64,
1722 pub cal_id: u64,
1723 pub uid: Box<str>,
1724 pub etag: Box<str>,
1725 pub extracted: CalendarObjectExtracted,
1726 pub created_at: Timestamp,
1727 pub updated_at: Timestamp,
1728}
1729
1730#[derive(Debug, Clone)]
1733pub struct CalendarObjectSyncEntry {
1734 pub uid: Box<str>,
1735 pub etag: Box<str>,
1736 pub deleted: bool,
1737 pub updated_at: Timestamp,
1738}
1739
1740#[derive(Debug, Default)]
1741pub struct ListCalendarObjectOptions {
1742 pub component: Option<String>,
1744 pub q: Option<String>,
1746 pub start: Option<Timestamp>,
1748 pub end: Option<Timestamp>,
1750 pub cursor: Option<String>,
1751 pub limit: Option<u32>,
1752 pub include_exceptions: bool,
1755}
1756
1757#[async_trait]
1758pub trait MetaAdapter: Debug + Send + Sync {
1759 async fn read_tenant(&self, tn_id: TnId) -> ClResult<Tenant<Box<str>>>;
1764
1765 async fn create_tenant(&self, tn_id: TnId, id_tag: &str) -> ClResult<TnId>;
1767
1768 async fn update_tenant(&self, tn_id: TnId, tenant: &UpdateTenantData) -> ClResult<()>;
1770
1771 async fn delete_tenant(&self, tn_id: TnId) -> ClResult<()>;
1773
1774 async fn list_tenants(&self, opts: &ListTenantsMetaOptions) -> ClResult<Vec<TenantListMeta>>;
1776
1777 async fn list_profiles(
1779 &self,
1780 tn_id: TnId,
1781 opts: &ListProfileOptions,
1782 ) -> ClResult<Vec<Profile<Box<str>>>>;
1783
1784 async fn list_follower_tags(&self, tn_id: TnId) -> ClResult<Vec<Box<str>>>;
1789
1790 async fn get_relationships(
1802 &self,
1803 tn_id: TnId,
1804 target_id_tags: &[&str],
1805 ) -> ClResult<HashMap<String, (bool, bool)>>;
1806
1807 async fn read_profile(
1811 &self,
1812 tn_id: TnId,
1813 id_tag: &str,
1814 ) -> ClResult<(Box<str>, Profile<Box<str>>)>;
1815
1816 async fn read_profiles(&self, tn_id: TnId, id_tags: &[&str])
1827 -> ClResult<Vec<PublicProfileRow>>;
1828
1829 async fn read_profile_roles(
1831 &self,
1832 tn_id: TnId,
1833 id_tag: &str,
1834 ) -> ClResult<Option<Box<[Box<str>]>>>;
1835
1836 async fn upsert_profile(
1843 &self,
1844 tn_id: TnId,
1845 id_tag: &str,
1846 fields: &UpsertProfileFields,
1847 ) -> ClResult<UpsertResult>;
1848
1849 async fn read_profile_public_key(
1853 &self,
1854 id_tag: &str,
1855 key_id: &str,
1856 ) -> ClResult<(Box<str>, Timestamp)>;
1857 async fn add_profile_public_key(
1863 &self,
1864 id_tag: &str,
1865 key_id: &str,
1866 public_key: &str,
1867 expires_at: Option<Timestamp>,
1868 ) -> ClResult<()>;
1869 async fn list_stale_profiles(
1880 &self,
1881 max_age_secs: i64,
1882 disable_after_secs: i64,
1883 limit: u32,
1884 ) -> ClResult<Vec<(TnId, Box<str>, Option<Box<str>>)>>;
1885
1886 async fn get_action_id(&self, tn_id: TnId, a_id: u64) -> ClResult<Box<str>>;
1889 async fn list_actions(
1890 &self,
1891 tn_id: TnId,
1892 opts: &ListActionOptions,
1893 ) -> ClResult<Vec<ActionView>>;
1894 async fn list_action_tokens(
1895 &self,
1896 tn_id: TnId,
1897 opts: &ListActionOptions,
1898 ) -> ClResult<Box<[Box<str>]>>;
1899
1900 async fn count_actions_grouped(
1904 &self,
1905 tn_id: TnId,
1906 opts: &ListActionOptions,
1907 group_by: ActionCountGroupBy,
1908 ) -> ClResult<Vec<(Option<String>, i64)>>;
1909
1910 async fn count_actions(&self, tn_id: TnId, opts: &ListActionOptions) -> ClResult<i64>;
1916
1917 async fn set_read_marker(
1924 &self,
1925 tn_id: TnId,
1926 scope: &str,
1927 key: &str,
1928 position: i64,
1929 ) -> ClResult<()>;
1930
1931 async fn auto_track_action(&self, tn_id: TnId, action_id: &str) -> ClResult<()>;
1935
1936 async fn create_action(
1937 &self,
1938 tn_id: TnId,
1939 action: &Action<&str>,
1940 key: Option<&str>,
1941 ) -> ClResult<ActionId<Box<str>>>;
1942
1943 async fn finalize_action(
1944 &self,
1945 tn_id: TnId,
1946 a_id: u64,
1947 action_id: &str,
1948 options: FinalizeActionOptions<'_>,
1949 ) -> ClResult<()>;
1950
1951 async fn create_inbound_action(
1952 &self,
1953 tn_id: TnId,
1954 action_id: &str,
1955 token: &str,
1956 ack_token: Option<&str>,
1957 ) -> ClResult<()>;
1958
1959 async fn get_action_root_id(&self, tn_id: TnId, action_id: &str) -> ClResult<Box<str>>;
1961
1962 async fn get_action_data(&self, tn_id: TnId, action_id: &str) -> ClResult<Option<ActionData>>;
1964
1965 async fn get_action_by_key(
1967 &self,
1968 tn_id: TnId,
1969 action_key: &str,
1970 ) -> ClResult<Option<Action<Box<str>>>>;
1971
1972 async fn store_action_token(&self, tn_id: TnId, action_id: &str, token: &str) -> ClResult<()>;
1974
1975 async fn get_action_token(&self, tn_id: TnId, action_id: &str) -> ClResult<Option<Box<str>>>;
1977
1978 async fn update_action_data(
1980 &self,
1981 tn_id: TnId,
1982 action_id: &str,
1983 opts: &UpdateActionDataOptions,
1984 ) -> ClResult<()>;
1985
1986 async fn update_inbound_action(
1988 &self,
1989 tn_id: TnId,
1990 action_id: &str,
1991 status: Option<char>,
1992 ) -> ClResult<()>;
1993
1994 async fn get_related_action_tokens(
1997 &self,
1998 tn_id: TnId,
1999 aprv_action_id: &str,
2000 ) -> ClResult<Vec<(Box<str>, Box<str>)>>;
2001
2002 async fn get_file_id(&self, tn_id: TnId, f_id: u64) -> ClResult<Box<str>>;
2005 async fn list_files(&self, tn_id: TnId, opts: &ListFileOptions) -> ClResult<Vec<FileView>>;
2006 async fn list_file_variants(
2007 &self,
2008 tn_id: TnId,
2009 file_id: FileId<&str>,
2010 ) -> ClResult<Vec<FileVariant<Box<str>>>>;
2011 async fn list_available_variants(&self, tn_id: TnId, file_id: &str) -> ClResult<Vec<Box<str>>>;
2013 async fn list_referenced_variant_ids(&self, tn_id: TnId) -> ClResult<Vec<Box<str>>>;
2018 async fn is_variant_referenced(&self, tn_id: TnId, variant_id: &str) -> ClResult<bool>;
2024 async fn read_file_variant(
2025 &self,
2026 tn_id: TnId,
2027 variant_id: &str,
2028 ) -> ClResult<FileVariant<Box<str>>>;
2029 async fn read_file_id_by_variant(&self, tn_id: TnId, variant_id: &str) -> ClResult<Box<str>>;
2031 async fn read_f_id_by_file_id(&self, tn_id: TnId, file_id: &str) -> ClResult<u64>;
2033 async fn create_file(&self, tn_id: TnId, opts: CreateFile) -> ClResult<FileId<Box<str>>>;
2034 async fn create_file_variant<'a>(
2035 &'a self,
2036 tn_id: TnId,
2037 f_id: u64,
2038 opts: FileVariant<&'a str>,
2039 ) -> ClResult<&'a str>;
2040 async fn update_file_id(&self, tn_id: TnId, f_id: u64, file_id: &str) -> ClResult<()>;
2041
2042 async fn finalize_file(&self, tn_id: TnId, f_id: u64, file_id: &str) -> ClResult<()>;
2044
2045 async fn list_files_by_parent(
2050 &self,
2051 tn_id: TnId,
2052 parent_id: &str,
2053 before: Timestamp,
2054 ) -> ClResult<Vec<u64>>;
2055
2056 async fn list_referenced_managed_fids(&self, tn_id: TnId) -> ClResult<HashSet<u64>>;
2078
2079 async fn hard_delete_file(&self, tn_id: TnId, f_id: u64) -> ClResult<Option<Box<str>>>;
2086
2087 async fn list_tasks(&self, opts: ListTaskOptions) -> ClResult<Vec<Task>>;
2090 async fn list_task_ids(&self, kind: &str, keys: &[Box<str>]) -> ClResult<Vec<u64>>;
2091 async fn create_task(
2092 &self,
2093 kind: &'static str,
2094 key: Option<&str>,
2095 input: &str,
2096 deps: &[u64],
2097 ) -> ClResult<u64>;
2098 async fn update_task_finished(&self, task_id: u64, output: &str) -> ClResult<()>;
2099 async fn update_task_error(
2100 &self,
2101 task_id: u64,
2102 output: &str,
2103 next_at: Option<Timestamp>,
2104 ) -> ClResult<()>;
2105
2106 async fn find_task_by_key(&self, key: &str) -> ClResult<Option<Task>>;
2108
2109 async fn update_task(&self, task_id: u64, patch: &TaskPatch) -> ClResult<()>;
2111
2112 async fn find_completed_deps(&self, deps: &[u64]) -> ClResult<Vec<u64>>;
2114
2115 async fn get_profile_info(&self, tn_id: TnId, id_tag: &str) -> ClResult<ProfileData>;
2119
2120 async fn get_action(&self, tn_id: TnId, action_id: &str) -> ClResult<Option<ActionView>>;
2124
2125 async fn get_action_type(&self, tn_id: TnId, action_id: &str) -> ClResult<Option<Box<str>>>;
2127
2128 async fn update_action(
2130 &self,
2131 tn_id: TnId,
2132 action_id: &str,
2133 content: Option<&str>,
2134 attachments: Option<&[&str]>,
2135 ) -> ClResult<()>;
2136
2137 async fn delete_action(&self, tn_id: TnId, action_id: &str) -> ClResult<()>;
2139
2140 async fn delete_file(&self, tn_id: TnId, file_id: &str) -> ClResult<DeleteFileResult>;
2153
2154 async fn list_settings(
2158 &self,
2159 tn_id: TnId,
2160 prefix: Option<&[String]>,
2161 ) -> ClResult<std::collections::HashMap<String, serde_json::Value>>;
2162
2163 async fn read_setting(&self, tn_id: TnId, name: &str) -> ClResult<Option<serde_json::Value>>;
2165
2166 async fn update_setting(
2168 &self,
2169 tn_id: TnId,
2170 name: &str,
2171 value: Option<serde_json::Value>,
2172 ) -> ClResult<()>;
2173
2174 async fn list_refs(&self, tn_id: TnId, opts: &ListRefsOptions) -> ClResult<Vec<RefData>>;
2178
2179 async fn get_ref(&self, tn_id: TnId, ref_id: &str) -> ClResult<Option<RefData>>;
2181
2182 async fn create_ref(
2184 &self,
2185 tn_id: TnId,
2186 ref_id: &str,
2187 opts: &CreateRefOptions,
2188 ) -> ClResult<RefData>;
2189
2190 async fn delete_ref(&self, tn_id: TnId, ref_id: &str) -> ClResult<()>;
2192
2193 async fn update_ref(
2195 &self,
2196 tn_id: TnId,
2197 ref_id: &str,
2198 opts: &UpdateRefOptions,
2199 ) -> ClResult<RefData>;
2200
2201 async fn use_ref(
2204 &self,
2205 ref_id: &str,
2206 expected_types: &[&str],
2207 ) -> ClResult<(TnId, Box<str>, RefData)>;
2208
2209 async fn validate_ref(
2212 &self,
2213 ref_id: &str,
2214 expected_types: &[&str],
2215 ) -> ClResult<(TnId, Box<str>, RefData)>;
2216
2217 async fn list_tags(
2227 &self,
2228 tn_id: TnId,
2229 prefix: Option<&str>,
2230 with_counts: bool,
2231 limit: Option<u32>,
2232 ) -> ClResult<Vec<TagInfo>>;
2233
2234 async fn add_tag(&self, tn_id: TnId, file_id: &str, tag: &str) -> ClResult<Vec<String>>;
2236
2237 async fn remove_tag(&self, tn_id: TnId, file_id: &str, tag: &str) -> ClResult<Vec<String>>;
2239
2240 async fn update_file_data(
2244 &self,
2245 tn_id: TnId,
2246 file_id: &str,
2247 opts: &UpdateFileOptions,
2248 ) -> ClResult<()>;
2249
2250 async fn read_file(&self, tn_id: TnId, file_id: &str) -> ClResult<Option<FileView>>;
2252
2253 async fn read_file_with_user_data(
2257 &self,
2258 tn_id: TnId,
2259 file_id: &str,
2260 id_tag: &str,
2261 ) -> ClResult<Option<FileView>>;
2262
2263 async fn record_file_access(&self, tn_id: TnId, id_tag: &str, file_id: &str) -> ClResult<()>;
2268
2269 async fn record_file_modification(
2271 &self,
2272 tn_id: TnId,
2273 id_tag: &str,
2274 file_id: &str,
2275 ) -> ClResult<()>;
2276
2277 async fn update_file_user_data(
2287 &self,
2288 tn_id: TnId,
2289 id_tag: &str,
2290 file_id: &str,
2291 pinned: crate::types::Patch<bool>,
2292 starred: crate::types::Patch<bool>,
2293 access_level: crate::types::Patch<char>,
2294 ) -> ClResult<FileUserData>;
2295
2296 async fn get_file_user_data(
2298 &self,
2299 tn_id: TnId,
2300 id_tag: &str,
2301 file_id: &str,
2302 ) -> ClResult<Option<FileUserData>>;
2303
2304 async fn list_push_subscriptions(&self, tn_id: TnId) -> ClResult<Vec<PushSubscription>>;
2312
2313 async fn create_push_subscription(
2319 &self,
2320 tn_id: TnId,
2321 subscription: &PushSubscriptionData,
2322 ) -> ClResult<u64>;
2323
2324 async fn delete_push_subscription(&self, tn_id: TnId, subscription_id: u64) -> ClResult<()>;
2329
2330 async fn create_share_entry(
2335 &self,
2336 tn_id: TnId,
2337 resource_type: char,
2338 resource_id: &str,
2339 created_by: &str,
2340 entry: &CreateShareEntry,
2341 ) -> ClResult<ShareEntry>;
2342
2343 async fn delete_share_entry(&self, tn_id: TnId, id: i64) -> ClResult<()>;
2345
2346 async fn update_share_entry(
2352 &self,
2353 tn_id: TnId,
2354 id: i64,
2355 resource_type: char,
2356 resource_id: &str,
2357 opts: &UpdateShareEntryOptions,
2358 ) -> ClResult<ShareEntry>;
2359
2360 async fn list_share_entries(
2362 &self,
2363 tn_id: TnId,
2364 resource_type: char,
2365 resource_id: &str,
2366 ) -> ClResult<Vec<ShareEntry>>;
2367
2368 async fn list_share_entries_by_subject(
2371 &self,
2372 tn_id: TnId,
2373 subject_type: Option<char>,
2374 subject_id: &str,
2375 ) -> ClResult<Vec<ShareEntry>>;
2376
2377 async fn check_share_access(
2380 &self,
2381 tn_id: TnId,
2382 resource_type: char,
2383 resource_id: &str,
2384 subject_type: char,
2385 subject_id: &str,
2386 ) -> ClResult<Option<char>>;
2387
2388 async fn read_share_entry(&self, tn_id: TnId, id: i64) -> ClResult<Option<ShareEntry>>;
2390
2391 async fn install_app(&self, tn_id: TnId, install: &InstallApp) -> ClResult<()>;
2396
2397 async fn uninstall_app(&self, tn_id: TnId, app_name: &str, publisher_tag: &str)
2399 -> ClResult<()>;
2400
2401 async fn list_installed_apps(
2403 &self,
2404 tn_id: TnId,
2405 search: Option<&str>,
2406 ) -> ClResult<Vec<InstalledApp>>;
2407
2408 async fn get_installed_app(
2410 &self,
2411 tn_id: TnId,
2412 app_name: &str,
2413 publisher_tag: &str,
2414 ) -> ClResult<Option<InstalledApp>>;
2415
2416 async fn replace_search_object(
2423 &self,
2424 tn_id: TnId,
2425 obj: &SearchObject<'_>,
2426 parts: &[SearchPart<'_>],
2427 ) -> ClResult<()>;
2428
2429 async fn replace_search_row(
2446 &self,
2447 tn_id: TnId,
2448 obj_tp: char,
2449 obj_id: &str,
2450 part: Option<&SearchPart<'_>>,
2451 fts_cl: bool,
2452 ) -> ClResult<()>;
2453
2454 async fn delete_search_object(&self, tn_id: TnId, obj_tp: char, obj_id: &str) -> ClResult<()>;
2456
2457 async fn delete_deep_search_by_content_type(
2465 &self,
2466 tn_id: TnId,
2467 content_type: &str,
2468 ) -> ClResult<()>;
2469
2470 async fn reap_search_orphans(&self, tn_id: TnId) -> ClResult<()>;
2477
2478 async fn optimize_search_index(&self, full: bool) -> ClResult<()> {
2485 let _ = full;
2486 Ok(())
2487 }
2488
2489 async fn reclaim_space(&self, min_free_pct: i64) -> ClResult<SpaceReport> {
2497 let _ = min_free_pct;
2498 Ok(SpaceReport::default())
2499 }
2500
2501 async fn search(&self, tn_id: TnId, opts: &SearchOptions) -> ClResult<Vec<SearchRow>>;
2504
2505 async fn count_search(&self, tn_id: TnId, opts: &SearchOptions) -> ClResult<i64>;
2512
2513 async fn read_tenant_data(&self, tn_id: TnId, name: &str) -> ClResult<Option<Box<str>>>;
2522
2523 async fn write_tenant_data(&self, tn_id: TnId, name: &str, value: Option<&str>)
2525 -> ClResult<()>;
2526
2527 async fn read_doc_format(&self, tn_id: TnId, content_type: &str)
2532 -> ClResult<Option<DocFormat>>;
2533
2534 async fn list_doc_formats(&self, tn_id: TnId) -> ClResult<Vec<DocFormat>>;
2536
2537 async fn upsert_doc_format(&self, tn_id: TnId, fmt: &UpsertDocFormat<'_>) -> ClResult<()>;
2539
2540 async fn delete_doc_format(&self, tn_id: TnId, content_type: &str) -> ClResult<()>;
2542
2543 async fn create_address_book(
2548 &self,
2549 tn_id: TnId,
2550 name: &str,
2551 description: Option<&str>,
2552 ) -> ClResult<AddressBook>;
2553
2554 async fn list_address_books(&self, tn_id: TnId) -> ClResult<Vec<AddressBook>>;
2556
2557 async fn get_address_book(&self, tn_id: TnId, ab_id: u64) -> ClResult<Option<AddressBook>>;
2559
2560 async fn get_address_book_by_name(
2562 &self,
2563 tn_id: TnId,
2564 name: &str,
2565 ) -> ClResult<Option<AddressBook>>;
2566
2567 async fn update_address_book(
2569 &self,
2570 tn_id: TnId,
2571 ab_id: u64,
2572 patch: &UpdateAddressBookData,
2573 ) -> ClResult<()>;
2574
2575 async fn delete_address_book(&self, tn_id: TnId, ab_id: u64) -> ClResult<()>;
2577
2578 async fn list_contacts(
2581 &self,
2582 tn_id: TnId,
2583 ab_id: Option<u64>,
2584 opts: &ListContactOptions,
2585 ) -> ClResult<Vec<ContactView>>;
2586
2587 async fn get_contact(&self, tn_id: TnId, ab_id: u64, uid: &str) -> ClResult<Option<Contact>>;
2589
2590 async fn upsert_contact(
2593 &self,
2594 tn_id: TnId,
2595 ab_id: u64,
2596 uid: &str,
2597 vcard: &str,
2598 etag: &str,
2599 extracted: &ContactExtracted,
2600 ) -> ClResult<Box<str>>;
2601
2602 async fn delete_contact(&self, tn_id: TnId, ab_id: u64, uid: &str) -> ClResult<()>;
2605
2606 async fn get_contacts_by_uids(
2608 &self,
2609 tn_id: TnId,
2610 ab_id: u64,
2611 uids: &[&str],
2612 ) -> ClResult<Vec<Contact>>;
2613
2614 async fn list_contacts_since(
2620 &self,
2621 tn_id: TnId,
2622 ab_id: u64,
2623 since: Option<Timestamp>,
2624 limit: Option<u32>,
2625 ) -> ClResult<Vec<ContactSyncEntry>>;
2626
2627 async fn list_contacts_by_profile(
2629 &self,
2630 tn_id: TnId,
2631 profile_id_tag: &str,
2632 ) -> ClResult<Vec<Contact>>;
2633
2634 async fn create_calendar(&self, tn_id: TnId, input: &CreateCalendarData) -> ClResult<Calendar>;
2639
2640 async fn list_calendars(&self, tn_id: TnId) -> ClResult<Vec<Calendar>>;
2642
2643 async fn get_calendar(&self, tn_id: TnId, cal_id: u64) -> ClResult<Option<Calendar>>;
2645
2646 async fn get_calendar_by_name(&self, tn_id: TnId, name: &str) -> ClResult<Option<Calendar>>;
2648
2649 async fn update_calendar(
2651 &self,
2652 tn_id: TnId,
2653 cal_id: u64,
2654 patch: &UpdateCalendarData,
2655 ) -> ClResult<()>;
2656
2657 async fn delete_calendar(&self, tn_id: TnId, cal_id: u64) -> ClResult<()>;
2659
2660 async fn list_calendar_objects(
2662 &self,
2663 tn_id: TnId,
2664 cal_id: u64,
2665 opts: &ListCalendarObjectOptions,
2666 ) -> ClResult<Vec<CalendarObjectView>>;
2667
2668 async fn get_calendar_object(
2672 &self,
2673 tn_id: TnId,
2674 cal_id: u64,
2675 uid: &str,
2676 ) -> ClResult<Option<CalendarObject>>;
2677
2678 async fn get_calendar_object_override(
2680 &self,
2681 tn_id: TnId,
2682 cal_id: u64,
2683 uid: &str,
2684 recurrence_id: Timestamp,
2685 ) -> ClResult<Option<CalendarObject>>;
2686
2687 async fn list_calendar_object_overrides(
2689 &self,
2690 tn_id: TnId,
2691 cal_id: u64,
2692 uid: &str,
2693 ) -> ClResult<Vec<CalendarObject>>;
2694
2695 async fn delete_calendar_object_override(
2697 &self,
2698 tn_id: TnId,
2699 cal_id: u64,
2700 uid: &str,
2701 recurrence_id: Timestamp,
2702 ) -> ClResult<()>;
2703
2704 async fn upsert_calendar_object(
2708 &self,
2709 tn_id: TnId,
2710 cal_id: u64,
2711 uid: &str,
2712 ical: &str,
2713 etag: &str,
2714 extracted: &CalendarObjectExtracted,
2715 ) -> ClResult<Box<str>>;
2716
2717 async fn delete_calendar_object(&self, tn_id: TnId, cal_id: u64, uid: &str) -> ClResult<()>;
2720
2721 async fn split_calendar_object_series(
2732 &self,
2733 tn_id: TnId,
2734 cal_id: u64,
2735 master: CalendarObjectWrite<'_>,
2736 tail: CalendarObjectWrite<'_>,
2737 split_at: Timestamp,
2738 ) -> ClResult<(Box<str>, Box<str>)>;
2739
2740 async fn get_calendar_objects_by_uids(
2742 &self,
2743 tn_id: TnId,
2744 cal_id: u64,
2745 uids: &[&str],
2746 ) -> ClResult<Vec<CalendarObject>>;
2747
2748 async fn list_calendar_objects_since(
2751 &self,
2752 tn_id: TnId,
2753 cal_id: u64,
2754 since: Option<Timestamp>,
2755 limit: Option<u32>,
2756 ) -> ClResult<Vec<CalendarObjectSyncEntry>>;
2757
2758 async fn query_calendar_objects_in_range(
2763 &self,
2764 tn_id: TnId,
2765 cal_id: u64,
2766 component: Option<&str>,
2767 start: Option<Timestamp>,
2768 end: Option<Timestamp>,
2769 ) -> ClResult<Vec<CalendarObject>>;
2770}
2771
2772#[cfg(test)]
2773mod tests {
2774 use super::*;
2775
2776 #[test]
2777 fn test_affects_search_index_hidden() {
2778 let opts = UpdateFileOptions { hidden: Patch::Value(true), ..Default::default() };
2779 assert!(opts.affects_search_index());
2780
2781 let opts = UpdateFileOptions::default();
2782 assert!(!opts.affects_search_index());
2783 }
2784
2785 #[test]
2786 fn test_deserialize_list_action_options_with_multiple_statuses() {
2787 let query = "status=C,N&type=POST,REPLY";
2788 let opts: ListActionOptions =
2789 serde_urlencoded::from_str(query).expect("should deserialize");
2790
2791 assert!(opts.status.is_some());
2792 let statuses = opts.status.expect("status should be Some");
2793 assert_eq!(statuses.len(), 2);
2794 assert_eq!(statuses[0].as_str(), "C");
2795 assert_eq!(statuses[1].as_str(), "N");
2796
2797 assert!(opts.typ.is_some());
2798 let types = opts.typ.expect("type should be Some");
2799 assert_eq!(types.len(), 2);
2800 assert_eq!(types[0].as_str(), "POST");
2801 assert_eq!(types[1].as_str(), "REPLY");
2802 }
2803
2804 #[test]
2805 fn test_deserialize_list_action_options_without_status() {
2806 let query = "issuer=alice";
2807 let opts: ListActionOptions =
2808 serde_urlencoded::from_str(query).expect("should deserialize");
2809
2810 assert!(opts.status.is_none());
2811 assert!(opts.typ.is_none());
2812 assert_eq!(opts.issuer.as_deref(), Some("alice"));
2813 }
2814
2815 #[test]
2816 fn test_deserialize_list_action_options_single_status() {
2817 let query = "status=C";
2818 let opts: ListActionOptions =
2819 serde_urlencoded::from_str(query).expect("should deserialize");
2820
2821 assert!(opts.status.is_some());
2822 let statuses = opts.status.expect("status should be Some");
2823 assert_eq!(statuses.len(), 1);
2824 assert_eq!(statuses[0].as_str(), "C");
2825 }
2826
2827 #[test]
2828 fn test_deserialize_list_action_options_audience_type() {
2829 let opts: ListActionOptions = serde_urlencoded::from_str("audienceType=personal")
2830 .expect("should deserialize personal");
2831 assert!(matches!(opts.audience_type, Some(AudienceType::Personal)));
2832
2833 let opts: ListActionOptions = serde_urlencoded::from_str("audienceType=community")
2834 .expect("should deserialize community");
2835 assert!(matches!(opts.audience_type, Some(AudienceType::Community)));
2836
2837 let opts: ListActionOptions =
2838 serde_urlencoded::from_str("issuer=alice").expect("should deserialize");
2839 assert!(opts.audience_type.is_none());
2840
2841 let res: Result<ListActionOptions, _> = serde_urlencoded::from_str("audienceType=garbage");
2842 assert!(res.is_err(), "garbage audienceType should error");
2843 }
2844
2845 #[test]
2846 fn test_deserialize_list_action_options_multi_visibility() {
2847 let opts: ListActionOptions =
2848 serde_urlencoded::from_str("visibility=F,C").expect("should deserialize");
2849 let v = opts.visibility.expect("visibility should be Some");
2850 assert_eq!(v.len(), 2);
2851 assert_eq!(v[0].as_str(), "F");
2852 assert_eq!(v[1].as_str(), "C");
2853
2854 let opts: ListActionOptions =
2855 serde_urlencoded::from_str("visibility=P").expect("should deserialize");
2856 let v = opts.visibility.expect("visibility should be Some");
2857 assert_eq!(v.len(), 1);
2858 assert_eq!(v[0].as_str(), "P");
2859
2860 let opts: ListActionOptions =
2861 serde_urlencoded::from_str("issuer=alice").expect("should deserialize");
2862 assert!(opts.visibility.is_none());
2863 }
2864
2865 #[test]
2866 fn test_deserialize_list_action_options_visibility_with_direct() {
2867 let opts: ListActionOptions =
2868 serde_urlencoded::from_str("visibility=D,F").expect("should deserialize");
2869 let v = opts.visibility.expect("visibility should be Some");
2870 assert_eq!(v.len(), 2);
2871 assert_eq!(v[0].as_str(), "D");
2872 assert_eq!(v[1].as_str(), "F");
2873 }
2874
2875 #[test]
2876 fn test_broken_reason_as_str_matches_serde() {
2877 for reason in [BrokenReason::Deleted, BrokenReason::Revoked] {
2878 let via_serde = serde_json::to_value(reason)
2879 .expect("serialize")
2880 .as_str()
2881 .expect("string variant")
2882 .to_string();
2883 assert_eq!(reason.as_str(), via_serde, "as_str diverged from serde for {:?}", reason);
2884 }
2885 }
2886}
2887
2888