1pub const TRASH_PARENT_ID: &str = "__trash__";
8
9use async_trait::async_trait;
10use serde::{Deserialize, Serialize};
11use serde_with::skip_serializing_none;
12use std::{cmp::Ordering, collections::HashMap, fmt::Debug};
13
14use crate::{
15 prelude::*,
16 types::{serialize_timestamp_iso, serialize_timestamp_iso_opt},
17};
18
19#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
22pub enum ProfileType {
23 #[serde(rename = "person")]
24 Person,
25 #[serde(rename = "community")]
26 Community,
27}
28
29#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
30pub enum ProfileStatus {
31 #[serde(rename = "A")]
32 Active,
33 #[serde(rename = "T")]
34 Trusted,
35 #[serde(rename = "B")]
36 Blocked,
37 #[serde(rename = "M")]
38 Muted,
39 #[serde(rename = "S")]
40 Suspended,
41 #[serde(rename = "X")]
42 Banned,
43}
44
45#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq)]
46pub enum ProfileConnectionStatus {
47 #[default]
48 Disconnected,
49 RequestPending,
50 Connected,
51}
52
53impl ProfileConnectionStatus {
54 pub fn is_connected(&self) -> bool {
55 matches!(self, ProfileConnectionStatus::Connected)
56 }
57}
58
59impl std::fmt::Display for ProfileConnectionStatus {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 match self {
62 ProfileConnectionStatus::Disconnected => write!(f, "disconnected"),
63 ProfileConnectionStatus::RequestPending => write!(f, "pending"),
64 ProfileConnectionStatus::Connected => write!(f, "connected"),
65 }
66 }
67}
68
69#[skip_serializing_none]
73#[derive(Debug, Clone, Serialize)]
74#[serde(rename_all = "camelCase")]
75pub struct RefData {
76 pub ref_id: Box<str>,
77 pub r#type: Box<str>,
78 pub description: Option<Box<str>>,
79 #[serde(serialize_with = "serialize_timestamp_iso")]
80 pub created_at: Timestamp,
81 #[serde(serialize_with = "serialize_timestamp_iso_opt")]
82 pub expires_at: Option<Timestamp>,
83 pub count: Option<u32>,
85 pub resource_id: Option<Box<str>>,
87 pub access_level: Option<char>,
89 pub params: Option<Box<str>>,
91}
92
93pub struct ListRefsOptions {
94 pub typ: Option<String>,
95 pub filter: Option<String>, pub resource_id: Option<String>,
98}
99
100#[derive(Default)]
101pub struct CreateRefOptions {
102 pub typ: String,
103 pub description: Option<String>,
104 pub expires_at: Option<Timestamp>,
105 pub count: Option<u32>,
106 pub resource_id: Option<String>,
108 pub access_level: Option<char>,
110 pub params: Option<String>,
112}
113
114#[skip_serializing_none]
115#[derive(Debug, Serialize)]
116#[serde(rename_all = "camelCase")]
117pub struct Tenant<S: AsRef<str>> {
118 #[serde(rename = "id")]
119 pub tn_id: TnId,
120 pub id_tag: S,
121 pub name: S,
122 #[serde(rename = "type")]
123 pub typ: ProfileType,
124 pub profile_pic: Option<S>,
125 pub cover_pic: Option<S>,
126 #[serde(serialize_with = "serialize_timestamp_iso")]
127 pub created_at: Timestamp,
128 pub x: HashMap<S, S>,
129}
130
131#[derive(Debug, Default)]
133pub struct ListTenantsMetaOptions {
134 pub limit: Option<u32>,
135 pub offset: Option<u32>,
136}
137
138#[skip_serializing_none]
140#[derive(Debug, Clone, Serialize)]
141#[serde(rename_all = "camelCase")]
142pub struct TenantListMeta {
143 pub tn_id: TnId,
144 pub id_tag: Box<str>,
145 pub name: Box<str>,
146 #[serde(rename = "type")]
147 pub typ: ProfileType,
148 pub profile_pic: Option<Box<str>>,
149 #[serde(serialize_with = "serialize_timestamp_iso")]
150 pub created_at: Timestamp,
151}
152
153#[derive(Debug, Default, Deserialize)]
154pub struct UpdateTenantData {
155 #[serde(rename = "idTag", default)]
156 pub id_tag: Patch<String>,
157 #[serde(default)]
158 pub name: Patch<String>,
159 #[serde(rename = "type", default)]
160 pub typ: Patch<ProfileType>,
161 #[serde(rename = "profilePic", default)]
162 pub profile_pic: Patch<String>,
163 #[serde(rename = "coverPic", default)]
164 pub cover_pic: Patch<String>,
165}
166
167#[derive(Debug)]
168pub struct Profile<S: AsRef<str>> {
169 pub id_tag: S,
170 pub name: S,
171 pub typ: ProfileType,
172 pub profile_pic: Option<S>,
173 pub following: bool,
174 pub connected: ProfileConnectionStatus,
175 pub roles: Option<Box<[Box<str>]>>,
176}
177
178#[derive(Debug, Default, Deserialize)]
179pub struct ListProfileOptions {
180 #[serde(rename = "type")]
181 pub typ: Option<ProfileType>,
182 pub status: Option<Box<[ProfileStatus]>>,
183 pub connected: Option<ProfileConnectionStatus>,
184 pub following: Option<bool>,
185 pub q: Option<String>,
186 pub id_tag: Option<String>,
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize)]
191#[serde(rename_all = "camelCase")]
192pub struct ProfileData {
193 pub id_tag: Box<str>,
194 pub name: Box<str>,
195 #[serde(rename = "type")]
196 pub r#type: Box<str>, pub profile_pic: Option<Box<str>>,
198 #[serde(serialize_with = "serialize_timestamp_iso")]
199 pub created_at: Timestamp,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
204pub struct ProfileList {
205 pub profiles: Vec<ProfileData>,
206 pub total: usize,
207 pub limit: usize,
208 pub offset: usize,
209}
210
211#[derive(Debug, Default, Deserialize)]
212pub struct UpdateProfileData {
213 #[serde(default)]
215 pub name: Patch<Box<str>>,
216 #[serde(default, rename = "profilePic")]
217 pub profile_pic: Patch<Option<Box<str>>>,
218 #[serde(default)]
219 pub roles: Patch<Option<Vec<Box<str>>>>,
220
221 #[serde(default)]
223 pub status: Patch<ProfileStatus>,
224
225 #[serde(default)]
227 pub synced: Patch<bool>,
228 #[serde(default)]
229 pub following: Patch<bool>,
230 #[serde(default)]
231 pub connected: Patch<ProfileConnectionStatus>,
232
233 #[serde(default)]
235 pub etag: Patch<Box<str>>,
236}
237
238#[derive(Debug, Clone)]
243pub struct ActionData {
244 pub subject: Option<Box<str>>,
245 pub reactions: Option<Box<str>>,
246 pub comments: Option<u32>,
247}
248
249#[derive(Debug, Clone, Default)]
251pub struct UpdateActionDataOptions {
252 pub subject: Patch<String>,
253 pub reactions: Patch<String>,
254 pub comments: Patch<u32>,
255 pub comments_read: Patch<u32>,
256 pub status: Patch<char>,
257 pub visibility: Patch<char>,
258 pub x: Patch<serde_json::Value>, pub content: Patch<String>,
260 pub attachments: Patch<String>, pub flags: Patch<String>,
262 pub created_at: Patch<Timestamp>,
263}
264
265#[derive(Debug, Clone, Default)]
267pub struct FinalizeActionOptions<'a> {
268 pub attachments: Option<&'a [&'a str]>,
269 pub subject: Option<&'a str>,
270 pub audience_tag: Option<&'a str>,
271 pub key: Option<&'a str>,
272}
273
274fn deserialize_split<'de, D>(deserializer: D) -> Result<Option<Vec<String>>, D::Error>
275where
276 D: serde::Deserializer<'de>,
277{
278 let s = String::deserialize(deserializer)?;
279 let values: Vec<String> =
280 s.split(',').map(|v| v.trim().to_string()).filter(|v| !v.is_empty()).collect();
281 if values.is_empty() {
282 Ok(None)
283 } else {
284 Ok(Some(values))
285 }
286}
287
288#[derive(Debug, Default, Deserialize)]
290#[serde(deny_unknown_fields)]
291pub struct ListActionOptions {
292 pub limit: Option<u32>,
294 pub cursor: Option<String>,
296 pub sort: Option<String>,
298 #[serde(rename = "sortDir")]
300 pub sort_dir: Option<String>,
301 #[serde(default, rename = "type", deserialize_with = "deserialize_split")]
302 pub typ: Option<Vec<String>>,
303 #[serde(default, deserialize_with = "deserialize_split")]
304 pub status: Option<Vec<String>>,
305 pub tag: Option<String>,
306 pub search: Option<String>,
307 pub visibility: Option<char>,
308 pub issuer: Option<String>,
309 pub audience: Option<String>,
310 pub involved: Option<String>,
311 #[serde(skip)]
313 pub viewer_id_tag: Option<String>,
314 #[serde(rename = "actionId")]
315 pub action_id: Option<String>,
316 #[serde(rename = "parentId")]
317 pub parent_id: Option<String>,
318 #[serde(rename = "rootId")]
319 pub root_id: Option<String>,
320 pub subject: Option<String>,
321 #[serde(rename = "createdAfter")]
322 pub created_after: Option<Timestamp>,
323}
324
325#[skip_serializing_none]
326#[derive(Debug, Clone, Serialize)]
327pub struct ProfileInfo {
328 #[serde(rename = "idTag")]
329 pub id_tag: Box<str>,
330 pub name: Box<str>,
331 #[serde(rename = "type")]
332 pub typ: ProfileType,
333 #[serde(rename = "profilePic")]
334 pub profile_pic: Option<Box<str>>,
335}
336
337pub struct Action<S: AsRef<str>> {
338 pub action_id: S,
339 pub typ: S,
340 pub sub_typ: Option<S>,
341 pub issuer_tag: S,
342 pub parent_id: Option<S>,
343 pub root_id: Option<S>,
344 pub audience_tag: Option<S>,
345 pub content: Option<S>,
346 pub attachments: Option<Vec<S>>,
347 pub subject: Option<S>,
348 pub created_at: Timestamp,
349 pub expires_at: Option<Timestamp>,
350 pub visibility: Option<char>, pub flags: Option<S>, pub x: Option<serde_json::Value>, }
354
355#[skip_serializing_none]
356#[derive(Debug, Clone, Serialize)]
357pub struct AttachmentView {
358 #[serde(rename = "fileId")]
359 pub file_id: Box<str>,
360 pub dim: Option<(u32, u32)>,
361 #[serde(rename = "localVariants")]
362 pub local_variants: Option<Vec<Box<str>>>,
363}
364
365#[skip_serializing_none]
366#[derive(Debug, Clone, Serialize)]
367#[serde(rename_all = "camelCase")]
368pub struct ActionView {
369 pub action_id: Box<str>,
370 #[serde(rename = "type")]
371 pub typ: Box<str>,
372 #[serde(rename = "subType")]
373 pub sub_typ: Option<Box<str>>,
374 pub parent_id: Option<Box<str>>,
375 pub root_id: Option<Box<str>>,
376 pub issuer: ProfileInfo,
377 pub audience: Option<ProfileInfo>,
378 pub content: Option<serde_json::Value>,
379 pub attachments: Option<Vec<AttachmentView>>,
380 pub subject: Option<Box<str>>,
381 #[serde(serialize_with = "serialize_timestamp_iso")]
382 pub created_at: Timestamp,
383 #[serde(serialize_with = "serialize_timestamp_iso_opt")]
384 pub expires_at: Option<Timestamp>,
385 pub status: Option<Box<str>>,
386 pub stat: Option<serde_json::Value>,
387 pub visibility: Option<char>,
388 pub flags: Option<Box<str>>, pub x: Option<serde_json::Value>, }
391
392#[derive(Debug)]
395pub enum FileId<S: AsRef<str>> {
396 FileId(S),
397 FId(u64),
398}
399
400pub enum ActionId<S: AsRef<str>> {
401 ActionId(S),
402 AId(u64),
403}
404
405#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
408pub enum FileStatus {
409 #[serde(rename = "A")]
410 Active,
411 #[serde(rename = "P")]
412 Pending,
413 #[serde(rename = "D")]
414 Deleted,
415}
416
417#[skip_serializing_none]
419#[derive(Debug, Clone, Default, Serialize)]
420#[serde(rename_all = "camelCase")]
421pub struct FileUserData {
422 #[serde(serialize_with = "serialize_timestamp_iso_opt")]
423 pub accessed_at: Option<Timestamp>,
424 #[serde(serialize_with = "serialize_timestamp_iso_opt")]
425 pub modified_at: Option<Timestamp>,
426 pub pinned: bool,
427 pub starred: bool,
428}
429
430#[skip_serializing_none]
431#[derive(Debug, Clone, Serialize)]
432#[serde(rename_all = "camelCase")]
433pub struct FileView {
434 pub file_id: Box<str>,
435 pub parent_id: Option<Box<str>>, pub root_id: Option<Box<str>>, pub owner: Option<ProfileInfo>,
438 pub creator: Option<ProfileInfo>,
439 pub preset: Option<Box<str>>,
440 pub content_type: Option<Box<str>>,
441 pub file_name: Box<str>,
442 pub file_tp: Option<Box<str>>, #[serde(serialize_with = "serialize_timestamp_iso")]
444 pub created_at: Timestamp,
445 #[serde(serialize_with = "crate::types::serialize_timestamp_iso_opt")]
446 pub accessed_at: Option<Timestamp>, #[serde(serialize_with = "crate::types::serialize_timestamp_iso_opt")]
448 pub modified_at: Option<Timestamp>, pub status: FileStatus,
450 pub tags: Option<Vec<Box<str>>>,
451 pub visibility: Option<char>, pub access_level: Option<crate::types::AccessLevel>, pub user_data: Option<FileUserData>, pub x: Option<serde_json::Value>, }
456
457#[skip_serializing_none]
458#[derive(Debug, Clone, Serialize)]
459pub struct FileVariant<S: AsRef<str> + Debug> {
460 #[serde(rename = "variantId")]
461 pub variant_id: S,
462 pub variant: S,
463 pub format: S,
464 pub size: u64,
465 pub resolution: (u32, u32),
466 pub available: bool,
467 pub duration: Option<f64>,
469 pub bitrate: Option<u32>,
471 #[serde(rename = "pageCount")]
473 pub page_count: Option<u32>,
474}
475
476impl<S: AsRef<str> + Debug> PartialEq for FileVariant<S> {
477 fn eq(&self, other: &Self) -> bool {
478 self.variant_id.as_ref() == other.variant_id.as_ref()
479 && self.variant.as_ref() == other.variant.as_ref()
480 && self.format.as_ref() == other.format.as_ref()
481 && self.size == other.size
482 && self.resolution == other.resolution
483 && self.available == other.available
484 && self.duration == other.duration
485 && self.bitrate == other.bitrate
486 && self.page_count == other.page_count
487 }
488}
489
490impl<S: AsRef<str> + Debug> Eq for FileVariant<S> {}
491
492impl<S: AsRef<str> + Debug + Ord> PartialOrd for FileVariant<S> {
493 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
494 Some(self.cmp(other))
495 }
496}
497
498impl<S: AsRef<str> + Debug + Ord> Ord for FileVariant<S> {
499 fn cmp(&self, other: &Self) -> Ordering {
500 self.size
502 .cmp(&other.size)
503 .then_with(|| self.resolution.0.cmp(&other.resolution.0))
504 .then_with(|| self.resolution.1.cmp(&other.resolution.1))
505 .then_with(|| self.size.cmp(&other.size))
506 }
507}
508
509#[derive(Debug, Default, Deserialize)]
514#[serde(deny_unknown_fields)]
515pub struct ListFileOptions {
516 pub limit: Option<u32>,
518 pub cursor: Option<String>,
520 #[serde(default, rename = "fileId", deserialize_with = "deserialize_split")]
521 pub file_id: Option<Vec<String>>,
522 #[serde(rename = "parentId")]
523 pub parent_id: Option<String>, #[serde(rename = "rootId")]
525 pub root_id: Option<String>, pub tag: Option<String>,
527 pub preset: Option<String>,
528 pub variant: Option<String>,
529 pub status: Option<FileStatus>,
531 #[serde(default, rename = "fileTp", deserialize_with = "deserialize_split")]
532 pub file_type: Option<Vec<String>>,
533 #[serde(default, rename = "contentType", deserialize_with = "deserialize_split")]
535 pub content_type: Option<Vec<String>>,
536 #[serde(rename = "fileName")]
538 pub file_name: Option<String>,
539 #[serde(rename = "ownerIdTag")]
541 pub owner_id_tag: Option<String>,
542 #[serde(rename = "notOwnerIdTag")]
544 pub not_owner_id_tag: Option<String>,
545 pub pinned: Option<bool>,
547 pub starred: Option<bool>,
549 pub sort: Option<String>,
551 #[serde(rename = "sortDir")]
553 pub sort_dir: Option<String>,
554 #[serde(skip)]
556 pub user_id_tag: Option<String>,
557 #[serde(skip)]
560 pub scope_file_id: Option<String>,
561 #[serde(skip)]
565 pub visible_levels: Option<Vec<char>>,
566}
567
568#[derive(Debug, Clone, Default)]
569pub struct CreateFile {
570 pub orig_variant_id: Option<Box<str>>,
571 pub file_id: Option<Box<str>>,
572 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>>,
577 pub content_type: Box<str>,
578 pub file_name: Box<str>,
579 pub file_tp: Option<Box<str>>, pub created_at: Option<Timestamp>,
581 pub tags: Option<Vec<Box<str>>>,
582 pub x: Option<serde_json::Value>,
583 pub visibility: Option<char>, pub status: Option<FileStatus>, }
586
587#[derive(Debug, Clone, Deserialize)]
588pub struct CreateFileVariant {
589 pub variant: Box<str>,
590 pub format: Box<str>,
591 pub resolution: (u32, u32),
592 pub size: u64,
593 pub available: bool,
594}
595
596#[derive(Debug, Clone, Default, Deserialize)]
598pub struct UpdateFileOptions {
599 #[serde(default, rename = "fileName")]
600 pub file_name: Patch<String>,
601 #[serde(default, rename = "parentId")]
602 pub parent_id: Patch<String>, #[serde(default)]
604 pub visibility: Patch<char>,
605 #[serde(default)]
606 pub status: Patch<char>,
607}
608
609#[skip_serializing_none]
613#[derive(Debug, Clone, Serialize)]
614#[serde(rename_all = "camelCase")]
615pub struct ShareEntry {
616 pub id: i64,
617 pub resource_type: char,
618 pub resource_id: Box<str>,
619 pub subject_type: char,
620 pub subject_id: Box<str>,
621 pub permission: char,
622 #[serde(serialize_with = "serialize_timestamp_iso_opt")]
623 pub expires_at: Option<Timestamp>,
624 pub created_by: Box<str>,
625 #[serde(serialize_with = "serialize_timestamp_iso")]
626 pub created_at: Timestamp,
627 pub subject_file_name: Option<Box<str>>,
629 pub subject_content_type: Option<Box<str>>,
630 pub subject_file_tp: Option<Box<str>>,
631}
632
633#[derive(Debug, Deserialize)]
634#[serde(rename_all = "camelCase")]
635pub struct CreateShareEntry {
636 pub subject_type: char,
637 pub subject_id: String,
638 pub permission: char,
639 pub expires_at: Option<Timestamp>,
640}
641
642#[skip_serializing_none]
647#[derive(Debug, Clone, Serialize, Deserialize)]
648pub struct PushSubscriptionData {
649 pub endpoint: String,
651 #[serde(rename = "expirationTime")]
653 pub expiration_time: Option<i64>,
654 pub keys: PushSubscriptionKeys,
656}
657
658#[derive(Debug, Clone, Serialize, Deserialize)]
660pub struct PushSubscriptionKeys {
661 pub p256dh: String,
663 pub auth: String,
665}
666
667#[derive(Debug, Clone, Serialize)]
669#[serde(rename_all = "camelCase")]
670pub struct PushSubscription {
671 pub id: u64,
673 pub subscription: PushSubscriptionData,
675 #[serde(serialize_with = "serialize_timestamp_iso")]
677 pub created_at: Timestamp,
678}
679
680pub struct Task {
683 pub task_id: u64,
684 pub tn_id: TnId,
685 pub kind: Box<str>,
686 pub status: char,
687 pub created_at: Timestamp,
688 pub next_at: Option<Timestamp>,
689 pub input: Box<str>,
690 pub output: Box<str>,
691 pub deps: Box<[u64]>,
692 pub retry: Option<Box<str>>,
693 pub cron: Option<Box<str>>,
694}
695
696#[derive(Debug, Default)]
697pub struct TaskPatch {
698 pub input: Patch<String>,
699 pub next_at: Patch<Timestamp>,
700 pub deps: Patch<Vec<u64>>,
701 pub retry: Patch<String>,
702 pub cron: Patch<String>,
703}
704
705#[derive(Debug, Default)]
706pub struct ListTaskOptions {}
707
708#[derive(Debug)]
713pub struct InstallApp {
714 pub app_name: Box<str>,
715 pub publisher_tag: Box<str>,
716 pub version: Box<str>,
717 pub action_id: Box<str>,
718 pub file_id: Box<str>,
719 pub blob_id: Box<str>,
720 pub capabilities: Option<Vec<Box<str>>>,
721}
722
723#[derive(Debug, Serialize)]
725#[serde(rename_all = "camelCase")]
726pub struct InstalledApp {
727 pub app_name: Box<str>,
728 pub publisher_tag: Box<str>,
729 pub version: Box<str>,
730 pub action_id: Box<str>,
731 pub file_id: Box<str>,
732 pub blob_id: Box<str>,
733 pub status: Box<str>,
734 pub capabilities: Option<Vec<Box<str>>>,
735 pub auto_update: bool,
736 #[serde(serialize_with = "serialize_timestamp_iso")]
737 pub installed_at: Timestamp,
738}
739
740#[async_trait]
741pub trait MetaAdapter: Debug + Send + Sync {
742 async fn read_tenant(&self, tn_id: TnId) -> ClResult<Tenant<Box<str>>>;
747
748 async fn create_tenant(&self, tn_id: TnId, id_tag: &str) -> ClResult<TnId>;
750
751 async fn update_tenant(&self, tn_id: TnId, tenant: &UpdateTenantData) -> ClResult<()>;
753
754 async fn delete_tenant(&self, tn_id: TnId) -> ClResult<()>;
756
757 async fn list_tenants(&self, opts: &ListTenantsMetaOptions) -> ClResult<Vec<TenantListMeta>>;
759
760 async fn list_profiles(
762 &self,
763 tn_id: TnId,
764 opts: &ListProfileOptions,
765 ) -> ClResult<Vec<Profile<Box<str>>>>;
766
767 async fn get_relationships(
774 &self,
775 tn_id: TnId,
776 target_id_tags: &[&str],
777 ) -> ClResult<HashMap<String, (bool, bool)>>;
778
779 async fn read_profile(
783 &self,
784 tn_id: TnId,
785 id_tag: &str,
786 ) -> ClResult<(Box<str>, Profile<Box<str>>)>;
787
788 async fn read_profile_roles(
790 &self,
791 tn_id: TnId,
792 id_tag: &str,
793 ) -> ClResult<Option<Box<[Box<str>]>>>;
794
795 async fn create_profile(
796 &self,
797 tn_id: TnId,
798 profile: &Profile<&str>,
799 etag: &str,
800 ) -> ClResult<()>;
801 async fn update_profile(
802 &self,
803 tn_id: TnId,
804 id_tag: &str,
805 profile: &UpdateProfileData,
806 ) -> ClResult<()>;
807
808 async fn read_profile_public_key(
812 &self,
813 id_tag: &str,
814 key_id: &str,
815 ) -> ClResult<(Box<str>, Timestamp)>;
816 async fn add_profile_public_key(
817 &self,
818 id_tag: &str,
819 key_id: &str,
820 public_key: &str,
821 ) -> ClResult<()>;
822 async fn process_profile_refresh<'a>(
828 &self,
829 callback: Box<dyn Fn(TnId, &'a str, Option<&'a str>) -> ClResult<()> + Send>,
830 );
831
832 async fn list_stale_profiles(
837 &self,
838 max_age_secs: i64,
839 limit: u32,
840 ) -> ClResult<Vec<(TnId, Box<str>, Option<Box<str>>)>>;
841
842 async fn get_action_id(&self, tn_id: TnId, a_id: u64) -> ClResult<Box<str>>;
845 async fn list_actions(
846 &self,
847 tn_id: TnId,
848 opts: &ListActionOptions,
849 ) -> ClResult<Vec<ActionView>>;
850 async fn list_action_tokens(
851 &self,
852 tn_id: TnId,
853 opts: &ListActionOptions,
854 ) -> ClResult<Box<[Box<str>]>>;
855
856 async fn create_action(
857 &self,
858 tn_id: TnId,
859 action: &Action<&str>,
860 key: Option<&str>,
861 ) -> ClResult<ActionId<Box<str>>>;
862
863 async fn finalize_action(
864 &self,
865 tn_id: TnId,
866 a_id: u64,
867 action_id: &str,
868 options: FinalizeActionOptions<'_>,
869 ) -> ClResult<()>;
870
871 async fn create_inbound_action(
872 &self,
873 tn_id: TnId,
874 action_id: &str,
875 token: &str,
876 ack_token: Option<&str>,
877 ) -> ClResult<()>;
878
879 async fn get_action_root_id(&self, tn_id: TnId, action_id: &str) -> ClResult<Box<str>>;
881
882 async fn get_action_data(&self, tn_id: TnId, action_id: &str) -> ClResult<Option<ActionData>>;
884
885 async fn get_action_by_key(
887 &self,
888 tn_id: TnId,
889 action_key: &str,
890 ) -> ClResult<Option<Action<Box<str>>>>;
891
892 async fn store_action_token(&self, tn_id: TnId, action_id: &str, token: &str) -> ClResult<()>;
894
895 async fn get_action_token(&self, tn_id: TnId, action_id: &str) -> ClResult<Option<Box<str>>>;
897
898 async fn update_action_data(
900 &self,
901 tn_id: TnId,
902 action_id: &str,
903 opts: &UpdateActionDataOptions,
904 ) -> ClResult<()>;
905
906 async fn update_inbound_action(
908 &self,
909 tn_id: TnId,
910 action_id: &str,
911 status: Option<char>,
912 ) -> ClResult<()>;
913
914 async fn get_related_action_tokens(
917 &self,
918 tn_id: TnId,
919 aprv_action_id: &str,
920 ) -> ClResult<Vec<(Box<str>, Box<str>)>>;
921
922 async fn get_file_id(&self, tn_id: TnId, f_id: u64) -> ClResult<Box<str>>;
925 async fn list_files(&self, tn_id: TnId, opts: &ListFileOptions) -> ClResult<Vec<FileView>>;
926 async fn list_file_variants(
927 &self,
928 tn_id: TnId,
929 file_id: FileId<&str>,
930 ) -> ClResult<Vec<FileVariant<Box<str>>>>;
931 async fn list_available_variants(&self, tn_id: TnId, file_id: &str) -> ClResult<Vec<Box<str>>>;
933 async fn read_file_variant(
934 &self,
935 tn_id: TnId,
936 variant_id: &str,
937 ) -> ClResult<FileVariant<Box<str>>>;
938 async fn read_file_id_by_variant(&self, tn_id: TnId, variant_id: &str) -> ClResult<Box<str>>;
940 async fn read_f_id_by_file_id(&self, tn_id: TnId, file_id: &str) -> ClResult<u64>;
942 async fn create_file(&self, tn_id: TnId, opts: CreateFile) -> ClResult<FileId<Box<str>>>;
943 async fn create_file_variant<'a>(
944 &'a self,
945 tn_id: TnId,
946 f_id: u64,
947 opts: FileVariant<&'a str>,
948 ) -> ClResult<&'a str>;
949 async fn update_file_id(&self, tn_id: TnId, f_id: u64, file_id: &str) -> ClResult<()>;
950
951 async fn finalize_file(&self, tn_id: TnId, f_id: u64, file_id: &str) -> ClResult<()>;
953
954 async fn list_tasks(&self, opts: ListTaskOptions) -> ClResult<Vec<Task>>;
957 async fn list_task_ids(&self, kind: &str, keys: &[Box<str>]) -> ClResult<Vec<u64>>;
958 async fn create_task(
959 &self,
960 kind: &'static str,
961 key: Option<&str>,
962 input: &str,
963 deps: &[u64],
964 ) -> ClResult<u64>;
965 async fn update_task_finished(&self, task_id: u64, output: &str) -> ClResult<()>;
966 async fn update_task_error(
967 &self,
968 task_id: u64,
969 output: &str,
970 next_at: Option<Timestamp>,
971 ) -> ClResult<()>;
972
973 async fn find_task_by_key(&self, key: &str) -> ClResult<Option<Task>>;
975
976 async fn update_task(&self, task_id: u64, patch: &TaskPatch) -> ClResult<()>;
978
979 async fn get_profile_info(&self, tn_id: TnId, id_tag: &str) -> ClResult<ProfileData>;
983
984 async fn get_action(&self, tn_id: TnId, action_id: &str) -> ClResult<Option<ActionView>>;
988
989 async fn update_action(
991 &self,
992 tn_id: TnId,
993 action_id: &str,
994 content: Option<&str>,
995 attachments: Option<&[&str]>,
996 ) -> ClResult<()>;
997
998 async fn delete_action(&self, tn_id: TnId, action_id: &str) -> ClResult<()>;
1000
1001 async fn count_reactions(&self, tn_id: TnId, subject_id: &str) -> ClResult<String>;
1004
1005 async fn delete_file(&self, tn_id: TnId, file_id: &str) -> ClResult<()>;
1009
1010 async fn list_children_by_root(&self, tn_id: TnId, root_id: &str) -> ClResult<Vec<Box<str>>>;
1012
1013 async fn list_settings(
1017 &self,
1018 tn_id: TnId,
1019 prefix: Option<&[String]>,
1020 ) -> ClResult<std::collections::HashMap<String, serde_json::Value>>;
1021
1022 async fn read_setting(&self, tn_id: TnId, name: &str) -> ClResult<Option<serde_json::Value>>;
1024
1025 async fn update_setting(
1027 &self,
1028 tn_id: TnId,
1029 name: &str,
1030 value: Option<serde_json::Value>,
1031 ) -> ClResult<()>;
1032
1033 async fn list_refs(&self, tn_id: TnId, opts: &ListRefsOptions) -> ClResult<Vec<RefData>>;
1037
1038 async fn get_ref(&self, tn_id: TnId, ref_id: &str) -> ClResult<Option<(Box<str>, Box<str>)>>;
1040
1041 async fn create_ref(
1043 &self,
1044 tn_id: TnId,
1045 ref_id: &str,
1046 opts: &CreateRefOptions,
1047 ) -> ClResult<RefData>;
1048
1049 async fn delete_ref(&self, tn_id: TnId, ref_id: &str) -> ClResult<()>;
1051
1052 async fn use_ref(
1055 &self,
1056 ref_id: &str,
1057 expected_types: &[&str],
1058 ) -> ClResult<(TnId, Box<str>, RefData)>;
1059
1060 async fn validate_ref(
1063 &self,
1064 ref_id: &str,
1065 expected_types: &[&str],
1066 ) -> ClResult<(TnId, Box<str>, RefData)>;
1067
1068 async fn list_tags(
1078 &self,
1079 tn_id: TnId,
1080 prefix: Option<&str>,
1081 with_counts: bool,
1082 limit: Option<u32>,
1083 ) -> ClResult<Vec<TagInfo>>;
1084
1085 async fn add_tag(&self, tn_id: TnId, file_id: &str, tag: &str) -> ClResult<Vec<String>>;
1087
1088 async fn remove_tag(&self, tn_id: TnId, file_id: &str, tag: &str) -> ClResult<Vec<String>>;
1090
1091 async fn update_file_data(
1095 &self,
1096 tn_id: TnId,
1097 file_id: &str,
1098 opts: &UpdateFileOptions,
1099 ) -> ClResult<()>;
1100
1101 async fn read_file(&self, tn_id: TnId, file_id: &str) -> ClResult<Option<FileView>>;
1103
1104 async fn record_file_access(&self, tn_id: TnId, id_tag: &str, file_id: &str) -> ClResult<()>;
1109
1110 async fn record_file_modification(
1112 &self,
1113 tn_id: TnId,
1114 id_tag: &str,
1115 file_id: &str,
1116 ) -> ClResult<()>;
1117
1118 async fn update_file_user_data(
1120 &self,
1121 tn_id: TnId,
1122 id_tag: &str,
1123 file_id: &str,
1124 pinned: Option<bool>,
1125 starred: Option<bool>,
1126 ) -> ClResult<FileUserData>;
1127
1128 async fn get_file_user_data(
1130 &self,
1131 tn_id: TnId,
1132 id_tag: &str,
1133 file_id: &str,
1134 ) -> ClResult<Option<FileUserData>>;
1135
1136 async fn list_push_subscriptions(&self, tn_id: TnId) -> ClResult<Vec<PushSubscription>>;
1144
1145 async fn create_push_subscription(
1151 &self,
1152 tn_id: TnId,
1153 subscription: &PushSubscriptionData,
1154 ) -> ClResult<u64>;
1155
1156 async fn delete_push_subscription(&self, tn_id: TnId, subscription_id: u64) -> ClResult<()>;
1161
1162 async fn create_share_entry(
1167 &self,
1168 tn_id: TnId,
1169 resource_type: char,
1170 resource_id: &str,
1171 created_by: &str,
1172 entry: &CreateShareEntry,
1173 ) -> ClResult<ShareEntry>;
1174
1175 async fn delete_share_entry(&self, tn_id: TnId, id: i64) -> ClResult<()>;
1177
1178 async fn list_share_entries(
1180 &self,
1181 tn_id: TnId,
1182 resource_type: char,
1183 resource_id: &str,
1184 ) -> ClResult<Vec<ShareEntry>>;
1185
1186 async fn list_share_entries_by_subject(
1189 &self,
1190 tn_id: TnId,
1191 subject_type: Option<char>,
1192 subject_id: &str,
1193 ) -> ClResult<Vec<ShareEntry>>;
1194
1195 async fn check_share_access(
1198 &self,
1199 tn_id: TnId,
1200 resource_type: char,
1201 resource_id: &str,
1202 subject_type: char,
1203 subject_id: &str,
1204 ) -> ClResult<Option<char>>;
1205
1206 async fn read_share_entry(&self, tn_id: TnId, id: i64) -> ClResult<Option<ShareEntry>>;
1208
1209 async fn install_app(&self, tn_id: TnId, install: &InstallApp) -> ClResult<()>;
1214
1215 async fn uninstall_app(&self, tn_id: TnId, app_name: &str, publisher_tag: &str)
1217 -> ClResult<()>;
1218
1219 async fn list_installed_apps(
1221 &self,
1222 tn_id: TnId,
1223 search: Option<&str>,
1224 ) -> ClResult<Vec<InstalledApp>>;
1225
1226 async fn get_installed_app(
1228 &self,
1229 tn_id: TnId,
1230 app_name: &str,
1231 publisher_tag: &str,
1232 ) -> ClResult<Option<InstalledApp>>;
1233}
1234
1235#[cfg(test)]
1236mod tests {
1237 use super::*;
1238 #[test]
1239 fn test_deserialize_list_action_options_with_multiple_statuses() {
1240 let query = "status=C,N&type=POST,REPLY";
1241 let opts: ListActionOptions =
1242 serde_urlencoded::from_str(query).expect("should deserialize");
1243
1244 assert!(opts.status.is_some());
1245 let statuses = opts.status.expect("status should be Some");
1246 assert_eq!(statuses.len(), 2);
1247 assert_eq!(statuses[0].as_str(), "C");
1248 assert_eq!(statuses[1].as_str(), "N");
1249
1250 assert!(opts.typ.is_some());
1251 let types = opts.typ.expect("type should be Some");
1252 assert_eq!(types.len(), 2);
1253 assert_eq!(types[0].as_str(), "POST");
1254 assert_eq!(types[1].as_str(), "REPLY");
1255 }
1256
1257 #[test]
1258 fn test_deserialize_list_action_options_without_status() {
1259 let query = "issuer=alice";
1260 let opts: ListActionOptions =
1261 serde_urlencoded::from_str(query).expect("should deserialize");
1262
1263 assert!(opts.status.is_none());
1264 assert!(opts.typ.is_none());
1265 assert_eq!(opts.issuer.as_deref(), Some("alice"));
1266 }
1267
1268 #[test]
1269 fn test_deserialize_list_action_options_single_status() {
1270 let query = "status=C";
1271 let opts: ListActionOptions =
1272 serde_urlencoded::from_str(query).expect("should deserialize");
1273
1274 assert!(opts.status.is_some());
1275 let statuses = opts.status.expect("status should be Some");
1276 assert_eq!(statuses.len(), 1);
1277 assert_eq!(statuses[0].as_str(), "C");
1278 }
1279}
1280
1281