nextcloud_passwords_client/
utils.rs1#[doc(hidden)]
2#[macro_export]
3macro_rules! create_details {
4 (
5 pub struct $struct:ident {
6 $(
7 pub $name:ident : bool
8 ),*
9 $(,)?
10 }) => {
11 #[derive(Default, Debug)]
13 pub struct $struct {
14 $(
15 pub $name: bool,
16 )*
17 }
18
19 impl $struct {
20 pub(crate) fn to_string(&self) -> String {
21 let mut s = "model".into();
22 $(
23 if self.$name {
24 s += concat!("+", stringify!($name));
25 }
26 )*
27 s
28 }
29
30 pub fn new() -> Self {
31 Default::default()
32 }
33
34 $(
35 pub fn $name(self) -> Self {
36 Self {
37 $name: true,
38 ..self
39 }
40 }
41 )*
42
43 }
44 };
45}
46
47#[derive(Debug)]
51pub struct SearchQuery<T: serde::Serialize> {
52 value: T,
53 query: QueryKind,
54}
55
56#[derive(Debug)]
57pub enum QueryKind {
58 Exact,
59 Equals,
60 NotEqual,
61 LessThan,
62 GreaterThan,
63 LessOrEqual,
64 GreaterOrEqual,
65}
66
67#[derive(serde::Serialize)]
68#[serde(untagged)]
69pub(crate) enum Criteria {
70 Value(serde_json::Value),
71 Search(&'static str, serde_json::Value),
72}
73
74impl<T: serde::Serialize> SearchQuery<T> {
75 pub(crate) fn to_criteria(&self) -> Result<Criteria, serde_json::Error> {
76 let value = serde_json::to_value(&self.value)?;
77 Ok(match self.query {
78 QueryKind::Exact => Criteria::Value(value),
79 QueryKind::Equals => Criteria::Search("eq", value),
80 QueryKind::NotEqual => Criteria::Search("ne", value),
81 QueryKind::LessThan => Criteria::Search("lt", value),
82 QueryKind::GreaterThan => Criteria::Search("gt", value),
83 QueryKind::LessOrEqual => Criteria::Search("le", value),
84 QueryKind::GreaterOrEqual => Criteria::Search("ge", value),
85 })
86 }
87}
88#[doc(hidden)]
123#[macro_export]
124macro_rules! create_calls {
125 (
126 $base:ident where
127 Endpoint = $endpoint:expr,
128 Details: $details:ty,
129 Type: $ty:ty,
130 Create: $create:ty,
131 Update: $update:ty,
132 Error: $err:ty,
133 Identifier: $ident:ty,
134 Trashed: $trashed:ty,
135 Criteria: $criteria:ty $(,)?
136 {
137 $(
138 List;
139 $(#[$meta_list:meta])*
140 pub async fn list(&self, details: Option<Details>) -> Result<Vec<Type>, Error>;
141 )?
142
143 $(
144 Get;
145 $(#[$meta_get:meta])*
146 pub async fn get(&self, details: Option<Details>, id: uuid::Uuid) -> Result<Type, Error>;
147 )?
148
149 $(
150 Find;
151 $(#[$meta_find:meta])*
152 pub async fn find(&self, criteria: Criteria, details: Option<Details>) -> Result<Vec<Type>, Error>;
153 )?
154
155 $(
156 Create;
157 $(#[$meta_create:meta])*
158 pub async fn create(&self, value: Create) -> Result<Identifier, Error>;
159 )?
160
161 $(
162 Update;
163 $(#[$meta_update:meta])*
164 pub async fn update(&self, value: Update) -> Result<Identifier, Error>;
165 )?
166
167 $(
168 Delete;
169 $(#[$meta_delete:meta])*
170 pub async fn delete(&self, id: uuid::Uuid, revision: Option<uuid::Uuid>) -> Result<Trashed, Error>;
171 )?
172
173 $(
174 Restore;
175 $(#[$meta_restore:meta])*
176 pub async fn restore(&self, id: uuid::Uuid, revision: Option<uuid::Uuid>) -> Result<Identifier, Error>;
177 )?
178 }
179 ) => {
180 ::doc_comment::doc_comment! { concat!("Actions on the ", stringify!($base), " API"),
181 pub struct $base<'a> {
182 pub(crate) api: &'a crate::AuthenticatedApi,
183 }}
184
185 impl<'a> $base<'a> {
186 $(
187 $(#[$meta_list])*
188 pub async fn list(&self, details: Option<$details>) -> Result<Vec<$ty>, $err> {
189 #[derive(serde::Serialize, serde::Deserialize)]
190 struct DetailsStr {
191 #[serde(skip_serializing_if = "Option::is_none")]
192 details: Option<String>,
193 }
194 self.api
195 .passwords_post(
196 concat!($endpoint, "/list"),
197 DetailsStr {
198 details: details.map(|d| d.to_string()),
199 },
200 )
201 .await
202 }
203 )?
204
205 $(
206 $(#[$meta_get])*
207 pub async fn get(&self, details: Option<$details>, id: uuid::Uuid) -> Result<$ty, $err> {
208 #[derive(Serialize, Deserialize)]
209 struct Show {
210 id: uuid::Uuid,
211 #[serde(skip_serializing_if = "Option::is_none")]
212 details: Option<String>,
213 }
214 let request = Show {
215 id,
216 details: details.map(|d| d.to_string()),
217 };
218 self.api
219 .passwords_post(concat!($endpoint, "/show"), request)
220 .await
221 }
222 )?
223
224 $(
225 $(#[$meta_find])*
226 pub async fn find(
227 &self,
228 criteria: $criteria,
229 details: Option<$details>,
230 ) -> Result<Vec<$ty>, $err> {
231 #[derive(Serialize)]
232 struct Request {
233 criteria: $criteria,
234 #[serde(skip_serializing_if = "Option::is_none")]
235 details: Option<String>,
236 }
237 let request = Request {
238 criteria,
239 details: details.map(|d| d.to_string()),
240 };
241 self.api
242 .passwords_post(concat!($endpoint, "/find"), request)
243 .await
244 }
245 )?
246
247 $(
248 $(#[$meta_create])*
249 pub async fn create(&self, value: $create) -> Result<$ident, $err> {
250 self.api
251 .passwords_post(concat!($endpoint, "/create"), value)
252 .await
253 }
254 )?
255
256 $(
257 $(#[$meta_update])*
258 pub async fn update(&self, folder: $update) -> Result<$ident, $err> {
259 self.api
260 .passwords_patch(concat!($endpoint, "/update"), folder)
261 .await
262 }
263 )?
264
265 $(
266 $(#[$meta_delete])*
267 pub async fn delete(&self, id: uuid::Uuid, revision: Option<uuid::Uuid>) -> Result<$trashed, $err> {
268 #[derive(Serialize)]
269 struct Request {
270 id: uuid::Uuid,
271 #[serde(skip_serializing_if = "Option::is_none")]
272 revision: Option<uuid::Uuid>,
273 }
274 self.api
275 .passwords_delete(concat!($endpoint, "/delete"), Request { id, revision })
276 .await
277 }
278 )?
279
280 $(
281 $(#[$meta_restore])*
282 pub async fn restore(
283 &self,
284 id: uuid::Uuid,
285 revision: Option<uuid::Uuid>,
286 ) -> Result<$ident, $err> {
287 #[derive(Serialize)]
288 struct Request {
289 id: uuid::Uuid,
290 #[serde(skip_serializing_if = "Option::is_none")]
291 revision: Option<uuid::Uuid>,
292 }
293 self.api
294 .passwords_patch(concat!($endpoint, "/restore"), Request { id, revision })
295 .await
296 }
297 )?
298 }
299 };
300}
301
302#[doc(hidden)]
303#[macro_export]
304macro_rules! create_binding {
305 (
306 $(#[$s_attr:meta])*
307 pub
308 struct $name:ident {
309 $(
310 $(#[$f_attr:meta])*
311 pub
312 $field:ident : $type:ty [$($tags:tt)*]
313 ),* $(,)?
314 }
315 ) => (
316 create_binding! {
317 @name $name
318 @meta ($($s_attr)*)
319 @create_new ()
320 @create ()
321 @update_new ()
322 @update ()
323 @search ()
324 @versioned ()
325 @not_versioned ()
326 $(
327 (
328 $(#[$f_attr])*
329 $field : $type
330 ) [$($tags)*]
331 )*
332 }
333 );
334
335 (
336 @name $name:ident
337 @meta (
338 $($s_attr:tt)*
339 )
340 @create_new (
341 $(
342 $(
343 (
344 $(#[$cn_attr:tt])*
345 $cn_field:ident : $cn_type:ty
346 )
347 )+
348 )?
349 )
350 @create (
351 $(
352 $(
353 (
354 $(#[$c_attr:tt])*
355 $c_field:ident : $c_type:ty
356 )
357 )+
358 )?
359 )
360 @update_new (
361 $(
362 (
363 $(#[$un_attr:tt])*
364 $un_field:ident : $un_type:ty
365 )
366 )*
367 )
368 @update (
369 $(
370 (
371 $(#[$u_attr:tt])*
372 $u_field:ident : $u_type:ty
373 )
374 )*
375 )
376 @search (
377 $(
378 $(
379 (
380 $(#[$se_attr:tt])*
381 $se_field:ident : $se_type:ty
382 )
383 )+)?
384 )
385 @versioned (
386 $(
387 (
388 $(#[$v_attr:tt])*
389 $v_field:ident : $v_type:ty
390 )
391 )*
392 )
393 @not_versioned (
394 $(
395 (
396 $(#[$n_attr:tt])*
397 $n_field:ident : $n_type:ty
398 )
399 )*
400 )
401 ) => (
403 ::paste::item! {
404 $(#[$s_attr])*
405 pub
406 struct $name {
407 $(
408 $(#[$n_attr])*
409 pub
410 $n_field : $n_type,
411 )*
412 #[serde(flatten)]
413 pub
414 versioned : [<Versioned $name>],
415 }
416 ::doc_comment::doc_comment! { concat!("versioned properties of [", stringify!($name), "]"),
417 $(#[$s_attr])*
418 pub
419 struct [<Versioned $name>] {
420 $(
421 $(#[$v_attr])*
422 pub
423 $v_field : $v_type,
424 )*
425 }
426 }
427
428 $(
429 ::doc_comment::doc_comment!{ concat!("Builder to create [", stringify!($name) , "], the values in the builder are optional values"),
430 #[derive(serde::Serialize, serde::Deserialize, Debug)]
431 pub
432 struct [<Create $name>] {
433 $(
434 $(#[$cn_attr])*
435 $cn_field: $cn_type,
436 )+
437 $(
438 $(#[$c_attr])*
439 pub
440 $c_field : Option<$c_type>,
441 )+
442 }
443 }
444
445 impl [<Create $name>] {
446 pub
447 fn new ($($cn_field: $cn_type,)*)
448 -> Self
449 {
450 Self {
451 $(
452 $cn_field,
453 )*
454 $(
455 $c_field: None,
456 )*
457 }
458 }
459
460 $(
461 pub
462 fn $c_field (self: Self, $c_field: $c_type)
463 -> Self
464 {
465 Self { $c_field: Some($c_field), ..self }
466 }
467 )*
468 }
469 )?
470
471 $(
472 ::doc_comment::doc_comment! {
473 "Builder to add search criterias (see the `find` method)",
474 #[derive(serde::Serialize, Default)]
475 pub struct [<$name Search>] {
476 $(
477 #[serde(skip_serializing_if = "Option::is_none")]
478 $(#[$se_attr])?
479 $se_field: Option<crate::utils::Criteria>,
480 )+
481 }
482 }
483 impl [<$name Search>] {
484 pub fn new() -> Self {
485 Default::default()
486 }
487 $(
488 pub fn [<and_ $se_field>](self, query: crate::utils::SearchQuery<$se_type>) -> Result<Self, crate::Error> {
489 Ok(Self {
490 $se_field: Some(query.to_criteria()?),
491 ..self
492 })
493 }
494 )+
495 }
496 )?
497
498 ::doc_comment::doc_comment! {
499 concat!("Builder to update [", stringify!($name), "], the values in the builder are optional values"),
500 $(#[$s_attr])*
501 pub
502 struct [<Update $name>] {
503 $(
504 $(#[$un_attr])*
505 $un_field: $un_type,
506 )*
507 $(
508 #[serde(skip_serializing_if = "Option::is_none")]
509 $(#[$u_attr])*
510 pub
511 $u_field : Option<$u_type>,
512 )*
513 }
514 }
515
516 impl [<Update $name>] {
517 pub
518 fn new ($($un_field: $un_type,)*)
519 -> Self
520 {
521 Self {
522 $(
523 $un_field,
524 )*
525 $(
526 $u_field: None,
527 )*
528 }
529 }
530
531 $(
532 pub
533 fn $u_field (self: Self, $u_field: $u_type)
534 -> Self
535 {
536 Self { $u_field: Some($u_field), ..self }
537 }
538 )*
539 }
540 }
541 );
542
543 (
545 @name $name:ident
546 @meta $meta:tt
547 @create_new ($($create_new:tt)*)
548 @create $create:tt
549 @update_new $update_new:tt
550 @update $update:tt
551 @search $search:tt
552 @versioned $versioned:tt
553 @not_versioned $not_versioned:tt
554 $current:tt [create(required) $($($tags:tt)+)?]
555 $($rest:tt)*
556 ) => (
557 create_binding! {
558 @name $name
559 @meta $meta
560 @create_new ( $($create_new)* $current )
561 @create $create
562 @update_new $update_new
563 @update $update
564 @search $search
565 @versioned $versioned
566 @not_versioned $not_versioned
567 $($current [$($tags)+])?
568 $($rest)*
569 }
570 );
571
572 (
574 @name $name:ident
575 @meta $meta:tt
576 @create_new $create_new:tt
577 @create ($($create:tt)*)
578 @update_new $update_new:tt
579 @update $update:tt
580 @search $search:tt
581 @versioned $versioned:tt
582 @not_versioned $not_versioned:tt
583 $current:tt [create(optional) $($($tags:tt)+)?]
584 $($rest:tt)*
585 ) => (
586 create_binding! {
587 @name $name
588 @meta $meta
589 @create_new $create_new
590 @create ($($create)* $current)
591 @update_new $update_new
592 @update $update
593 @search $search
594 @versioned $versioned
595 @not_versioned $not_versioned
596 $($current [$($tags)+])?
597 $($rest)*
598 }
599 );
600
601 (
603 @name $name:ident
604 @meta $meta:tt
605 @create_new $create_new:tt
606 @create $create:tt
607 @update_new ($($update_new:tt)*)
608 @update $update:tt
609 @search $search:tt
610 @versioned $versioned:tt
611 @not_versioned $not_versioned:tt
612 $current:tt [update(required) $($($tags:tt)+)?]
613 $($rest:tt)*
614 ) => (
615 create_binding! {
616 @name $name
617 @meta $meta
618 @create_new $create_new
619 @create $create
620 @update_new ($($update_new)* $current)
621 @update $update
622 @search $search
623 @versioned $versioned
624 @not_versioned $not_versioned
625 $($current [$($tags)+])?
626 $($rest)*
627 }
628 );
629
630 (
632 @name $name:ident
633 @meta $meta:tt
634 @create_new $create_new:tt
635 @create $create:tt
636 @update_new $update_new:tt
637 @update ($($update:tt)*)
638 @search $search:tt
639 @versioned $versioned:tt
640 @not_versioned $not_versioned:tt
641 $current:tt [update(optional) $($($tags:tt)+)?]
642 $($rest:tt)*
643 ) => (
644 create_binding! {
645 @name $name
646 @meta $meta
647 @create_new $create_new
648 @create $create
649 @update_new $update_new
650 @update ($($update)* $current)
651 @search $search
652 @versioned $versioned
653 @not_versioned $not_versioned
654 $($current [$($tags)+])?
655 $($rest)*
656 }
657 );
658
659 (
661 @name $name:ident
662 @meta $meta:tt
663 @create_new $create_new:tt
664 @create $create:tt
665 @update_new $update_new:tt
666 @update $update:tt
667 @search ($($search:tt)*)
668 @versioned $versioned:tt
669 @not_versioned $not_versioned:tt
670 $current:tt [search $($($tags:tt)+)?]
671 $($rest:tt)*
672 ) => (
673 create_binding! {
674 @name $name
675 @meta $meta
676 @create_new $create_new
677 @create $create
678 @update_new $update_new
679 @update $update
680 @search ($($search)* $current)
681 @versioned $versioned
682 @not_versioned $not_versioned
683 $($current [$($tags)+])?
684 $($rest)*
685 }
686 );
687
688 (
690 @name $name:ident
691 @meta $meta:tt
692 @create_new $create_new:tt
693 @create $create:tt
694 @update_new $update_new:tt
695 @update $update:tt
696 @search $search:tt
697 @versioned ( $($versioned:tt)* )
698 @not_versioned $not_versioned:tt
699 $current:tt [versioned(true) $($($tags:tt)+)?]
700 $($rest:tt)*
701 ) => (
702 create_binding! {
703 @name $name
704 @meta $meta
705 @create_new $create_new
706 @create $create
707 @update_new $update_new
708 @update $update
709 @search $search
710 @versioned ( $($versioned)* $current )
711 @not_versioned $not_versioned
712 $($current [$($tags)+])?
713 $($rest)*
714 }
715 );
716 (
718 @name $name:ident
719 @meta $meta:tt
720 @create_new $create_new:tt
721 @create $create:tt
722 @update_new $update_new:tt
723 @update $update:tt
724 @search $search:tt
725 @versioned $versioned:tt
726 @not_versioned ( $($not_versioned:tt)* )
727 $current:tt [versioned(false) $($($tags:tt)+)?]
728 $($rest:tt)*
729 ) => (
730 create_binding! {
731 @name $name
732 @meta $meta
733 @create_new $create_new
734 @create $create
735 @update_new $update_new
736 @update $update
737 @search $search
738 @versioned $versioned
739 @not_versioned ( $($not_versioned)* $current)
740 $($current [$($tags)+])?
741 $($rest)*
742 }
743 );
744
745
746 (
748 @name $name:ident
749 @meta $meta:tt
750 @create_new $create_new:tt
751 @create $create:tt
752 @update_new $update_new:tt
753 @update $update:tt
754 @search $search:tt
755 @versioned $versioned:tt
756 @not_versioned $not_versioned:tt
757 $current:tt []
758 $($rest:tt)*
759 ) => (
760 create_binding! {
761 @name $name
762 @meta $meta
763 @create_new $create_new
764 @create $create
765 @update_new $update_new
766 @update $update
767 @search $search
768 @versioned $versioned
769 @not_versioned $not_versioned
770 $($rest)*
771 }
772 );
773}