1use serde::{Deserialize, Serialize};
11use serde_json::{Map, Value};
12
13use crate::{
14 Kibana, Request, Scope, SortOrder,
15 http::{Method, Raw},
16 pagination::paginated,
17 request::endpoint,
18};
19
20#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
22#[serde(rename_all = "snake_case")]
23pub enum NamespaceType {
24 #[default]
25 Single,
26 Agnostic,
27}
28
29impl NamespaceType {
30 fn as_str(self) -> &'static str {
31 match self {
32 Self::Single => "single",
33 Self::Agnostic => "agnostic",
34 }
35 }
36}
37
38#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
39#[serde(rename_all = "lowercase")]
40#[non_exhaustive]
41pub enum OsType {
42 Linux,
43 Macos,
44 Windows,
45}
46
47#[derive(Clone, Debug, Deserialize, Serialize)]
49#[non_exhaustive]
50pub struct ListReference {
51 pub id: String,
52 pub list_id: String,
53 pub namespace_type: NamespaceType,
54 #[serde(rename = "type")]
55 pub list_type: String,
56}
57
58impl ListReference {
59 pub fn new(
60 id: impl Into<String>,
61 list_id: impl Into<String>,
62 namespace_type: NamespaceType,
63 list_type: impl Into<String>,
64 ) -> Self {
65 Self {
66 id: id.into(),
67 list_id: list_id.into(),
68 namespace_type,
69 list_type: list_type.into(),
70 }
71 }
72}
73
74#[derive(Clone, Debug, Deserialize, Serialize)]
76#[non_exhaustive]
77pub struct ExceptionList {
78 pub id: String,
80 pub list_id: String,
82 pub name: String,
83 pub description: String,
84 pub namespace_type: NamespaceType,
85 #[serde(rename = "type")]
86 pub list_type: String,
87 #[serde(rename = "_version", default)]
89 pub revision: Option<String>,
90 #[serde(default)]
91 pub tags: Vec<String>,
92 #[serde(default)]
93 pub os_types: Vec<OsType>,
94 #[serde(default)]
95 pub meta: Option<Map<String, Value>>,
96 #[serde(flatten)]
97 pub extra: Map<String, Value>,
98}
99
100impl ExceptionList {
101 pub fn reference(&self) -> ListReference {
102 ListReference::new(
103 &self.id,
104 &self.list_id,
105 self.namespace_type,
106 &self.list_type,
107 )
108 }
109
110 pub fn edit(&self) -> ListEdit {
126 ListEdit {
127 id: self.id.clone(),
128 revision: self.revision.clone(),
129 namespace_type: self.namespace_type,
130 list_type: self.list_type.clone(),
131 name: self.name.clone(),
132 description: self.description.clone(),
133 tags: self.tags.clone(),
134 os_types: self.os_types.clone(),
135 meta: self.meta.clone(),
136 version: None,
137 }
138 }
139}
140
141#[derive(Clone, Debug, Serialize)]
144pub struct NewList {
145 name: String,
146 description: String,
147 #[serde(rename = "type")]
148 list_type: String,
149 namespace_type: NamespaceType,
150 #[serde(skip_serializing_if = "Option::is_none")]
151 list_id: Option<String>,
152 tags: Vec<String>,
153 #[serde(skip_serializing_if = "Vec::is_empty")]
154 os_types: Vec<OsType>,
155 #[serde(skip_serializing_if = "Option::is_none")]
156 version: Option<u64>,
157 #[serde(skip_serializing_if = "Option::is_none")]
158 meta: Option<Map<String, Value>>,
159}
160
161impl NewList {
162 pub fn new(
164 name: impl Into<String>,
165 description: impl Into<String>,
166 list_type: impl Into<String>,
167 ) -> Self {
168 Self {
169 name: name.into(),
170 description: description.into(),
171 list_type: list_type.into(),
172 namespace_type: NamespaceType::Single,
173 list_id: None,
174 tags: Vec::new(),
175 os_types: Vec::new(),
176 version: None,
177 meta: None,
178 }
179 }
180
181 pub fn detection(name: impl Into<String>, description: impl Into<String>) -> Self {
183 Self::new(name, description, "detection")
184 }
185
186 pub fn namespace_type(mut self, namespace: NamespaceType) -> Self {
187 self.namespace_type = namespace;
188 self
189 }
190
191 pub fn list_id(mut self, list_id: impl Into<String>) -> Self {
193 self.list_id = Some(list_id.into());
194 self
195 }
196
197 pub fn tags<I: IntoIterator<Item = S>, S: Into<String>>(mut self, tags: I) -> Self {
198 self.tags = tags.into_iter().map(Into::into).collect();
199 self
200 }
201
202 pub fn os_types(mut self, os_types: Vec<OsType>) -> Self {
203 self.os_types = os_types;
204 self
205 }
206
207 pub fn version(mut self, version: u64) -> Self {
209 self.version = Some(version);
210 self
211 }
212
213 pub fn meta(mut self, meta: Map<String, Value>) -> Self {
214 self.meta = Some(meta);
215 self
216 }
217}
218
219#[derive(Clone, Debug, Serialize)]
226pub struct ListEdit {
227 id: String,
228 #[serde(rename = "_version", skip_serializing_if = "Option::is_none")]
229 revision: Option<String>,
230 namespace_type: NamespaceType,
231 #[serde(rename = "type")]
232 list_type: String,
233 name: String,
234 description: String,
235 tags: Vec<String>,
236 os_types: Vec<OsType>,
237 #[serde(skip_serializing_if = "Option::is_none")]
238 meta: Option<Map<String, Value>>,
239 #[serde(skip_serializing_if = "Option::is_none")]
240 version: Option<u64>,
241}
242
243impl ListEdit {
244 pub fn name(mut self, name: impl Into<String>) -> Self {
245 self.name = name.into();
246 self
247 }
248
249 pub fn description(mut self, description: impl Into<String>) -> Self {
250 self.description = description.into();
251 self
252 }
253
254 pub fn tags<I: IntoIterator<Item = S>, S: Into<String>>(mut self, tags: I) -> Self {
255 self.tags = tags.into_iter().map(Into::into).collect();
256 self
257 }
258
259 pub fn os_types(mut self, os_types: Vec<OsType>) -> Self {
260 self.os_types = os_types;
261 self
262 }
263
264 pub fn meta(mut self, meta: Map<String, Value>) -> Self {
265 self.meta = Some(meta);
266 self
267 }
268
269 pub fn version(mut self, version: u64) -> Self {
271 self.version = Some(version);
272 self
273 }
274}
275
276#[derive(Clone, Copy, Debug)]
277pub enum ListSelector<'a> {
278 Id(&'a str),
279 ListId(&'a str),
280}
281
282impl<'a> ListSelector<'a> {
283 fn pair(self) -> (&'static str, &'a str) {
284 match self {
285 Self::Id(id) => ("id", id),
286 Self::ListId(id) => ("list_id", id),
287 }
288 }
289}
290
291#[derive(Clone, Copy, Debug)]
297pub struct ListTarget<'a> {
298 selector: ListSelector<'a>,
299 namespace: Option<NamespaceType>,
300}
301
302impl<'a> ListTarget<'a> {
303 pub fn new(selector: ListSelector<'a>, namespace: NamespaceType) -> Self {
304 Self {
305 selector,
306 namespace: Some(namespace),
307 }
308 }
309
310 fn apply(self, request: Request<'_>) -> Request<'_> {
311 let request = request.selector(self.selector.pair());
312 match self.namespace {
313 Some(namespace) => request.param("namespace_type", namespace.as_str()),
314 None => request,
315 }
316 }
317}
318
319impl<'a> From<ListSelector<'a>> for ListTarget<'a> {
320 fn from(selector: ListSelector<'a>) -> Self {
321 Self {
322 selector,
323 namespace: None,
324 }
325 }
326}
327
328impl<'a> From<&'a ExceptionList> for ListTarget<'a> {
329 fn from(list: &'a ExceptionList) -> Self {
330 Self::new(ListSelector::Id(&list.id), list.namespace_type)
331 }
332}
333
334impl<'a> From<&'a ListReference> for ListTarget<'a> {
335 fn from(list: &'a ListReference) -> Self {
336 Self::new(ListSelector::Id(&list.id), list.namespace_type)
337 }
338}
339
340#[derive(Clone, Copy, Debug)]
343pub struct ItemsOf<'a> {
344 list_id: &'a str,
345 namespace: Option<NamespaceType>,
346}
347
348impl<'a> From<&'a str> for ItemsOf<'a> {
349 fn from(list_id: &'a str) -> Self {
350 Self {
351 list_id,
352 namespace: None,
353 }
354 }
355}
356
357impl<'a> From<&'a String> for ItemsOf<'a> {
358 fn from(list_id: &'a String) -> Self {
359 list_id.as_str().into()
360 }
361}
362
363impl<'a> From<&'a ExceptionList> for ItemsOf<'a> {
364 fn from(list: &'a ExceptionList) -> Self {
365 Self {
366 list_id: &list.list_id,
367 namespace: Some(list.namespace_type),
368 }
369 }
370}
371
372#[derive(Clone, Copy, Debug)]
373pub enum ItemSelector<'a> {
374 Id(&'a str),
375 ItemId(&'a str),
376}
377
378impl<'a> ItemSelector<'a> {
379 fn pair(self) -> (&'static str, &'a str) {
380 match self {
381 Self::Id(id) => ("id", id),
382 Self::ItemId(id) => ("item_id", id),
383 }
384 }
385}
386
387#[derive(Clone, Copy, Debug)]
389pub struct ItemTarget<'a> {
390 selector: ItemSelector<'a>,
391 namespace: Option<NamespaceType>,
392}
393
394impl<'a> ItemTarget<'a> {
395 pub fn new(selector: ItemSelector<'a>, namespace: NamespaceType) -> Self {
396 Self {
397 selector,
398 namespace: Some(namespace),
399 }
400 }
401
402 fn apply(self, request: Request<'_>) -> Request<'_> {
403 let request = request.selector(self.selector.pair());
404 match self.namespace {
405 Some(namespace) => request.param("namespace_type", namespace.as_str()),
406 None => request,
407 }
408 }
409}
410
411impl<'a> From<ItemSelector<'a>> for ItemTarget<'a> {
412 fn from(selector: ItemSelector<'a>) -> Self {
413 Self {
414 selector,
415 namespace: None,
416 }
417 }
418}
419
420impl<'a> From<&'a ExceptionItem> for ItemTarget<'a> {
421 fn from(item: &'a ExceptionItem) -> Self {
422 Self::new(ItemSelector::Id(&item.id), item.namespace_type)
423 }
424}
425
426#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
427#[serde(rename_all = "lowercase")]
428pub enum Operator {
429 Included,
430 Excluded,
431}
432
433#[derive(Clone, Debug, Serialize, Deserialize)]
435#[serde(tag = "type", rename_all = "snake_case")]
436#[non_exhaustive]
437pub enum NestedEntry {
438 Match {
439 field: String,
440 operator: Operator,
441 value: String,
442 },
443 MatchAny {
444 field: String,
445 operator: Operator,
446 value: Vec<String>,
447 },
448 Exists {
449 field: String,
450 operator: Operator,
451 },
452}
453
454#[derive(Clone, Debug, Serialize, Deserialize)]
456#[non_exhaustive]
457pub struct ValueListReference {
458 pub id: String,
459 #[serde(rename = "type")]
461 pub list_type: String,
462}
463
464impl ValueListReference {
465 pub fn new(id: impl Into<String>, list_type: impl Into<String>) -> Self {
466 Self {
467 id: id.into(),
468 list_type: list_type.into(),
469 }
470 }
471}
472
473#[derive(Clone, Debug, Serialize, Deserialize)]
475#[serde(tag = "type", rename_all = "snake_case")]
476#[non_exhaustive]
477pub enum Entry {
478 Match {
479 field: String,
480 operator: Operator,
481 value: String,
482 },
483 MatchAny {
484 field: String,
485 operator: Operator,
486 value: Vec<String>,
487 },
488 Exists {
489 field: String,
490 operator: Operator,
491 },
492 Wildcard {
493 field: String,
494 operator: Operator,
495 value: String,
496 },
497 List {
498 field: String,
499 operator: Operator,
500 list: ValueListReference,
501 },
502 Nested {
503 field: String,
504 entries: Vec<NestedEntry>,
505 },
506}
507
508#[derive(Clone, Debug, Serialize)]
510pub struct Comment {
511 comment: String,
512}
513
514impl Comment {
515 pub fn new(comment: impl Into<String>) -> Self {
516 Self {
517 comment: comment.into(),
518 }
519 }
520}
521
522#[derive(Clone, Debug, Deserialize, Serialize)]
524#[non_exhaustive]
525pub struct ItemComment {
526 pub id: String,
527 pub comment: String,
528 #[serde(default)]
529 pub created_at: Option<String>,
530 #[serde(default)]
531 pub created_by: Option<String>,
532 #[serde(flatten)]
533 pub extra: Map<String, Value>,
534}
535
536#[derive(Clone, Debug, Serialize)]
539pub struct NewItem {
540 name: String,
541 description: String,
542 list_id: String,
543 #[serde(skip_serializing_if = "Option::is_none")]
544 item_id: Option<String>,
545 #[serde(rename = "type")]
546 item_type: &'static str,
547 namespace_type: NamespaceType,
548 entries: Vec<Entry>,
549 tags: Vec<String>,
550 #[serde(skip_serializing_if = "Vec::is_empty")]
551 os_types: Vec<OsType>,
552 comments: Vec<Comment>,
553 #[serde(skip_serializing_if = "Option::is_none")]
554 expire_time: Option<String>,
555 #[serde(skip_serializing_if = "Option::is_none")]
556 meta: Option<Map<String, Value>>,
557}
558
559impl NewItem {
560 pub fn new(list: &ExceptionList, name: impl Into<String>, entries: Vec<Entry>) -> Self {
562 Self {
563 name: name.into(),
564 description: String::new(),
565 list_id: list.list_id.clone(),
566 item_id: None,
567 item_type: "simple",
568 namespace_type: list.namespace_type,
569 entries,
570 tags: Vec::new(),
571 os_types: Vec::new(),
572 comments: Vec::new(),
573 expire_time: None,
574 meta: None,
575 }
576 }
577
578 pub fn description(mut self, description: impl Into<String>) -> Self {
579 self.description = description.into();
580 self
581 }
582
583 pub fn item_id(mut self, item_id: impl Into<String>) -> Self {
585 self.item_id = Some(item_id.into());
586 self
587 }
588
589 pub fn tags<I: IntoIterator<Item = S>, S: Into<String>>(mut self, tags: I) -> Self {
590 self.tags = tags.into_iter().map(Into::into).collect();
591 self
592 }
593
594 pub fn os_types(mut self, os_types: Vec<OsType>) -> Self {
595 self.os_types = os_types;
596 self
597 }
598
599 pub fn comments(mut self, comments: Vec<Comment>) -> Self {
600 self.comments = comments;
601 self
602 }
603
604 pub fn expire_time(mut self, time: impl Into<String>) -> Self {
606 self.expire_time = Some(time.into());
607 self
608 }
609
610 pub fn meta(mut self, meta: Map<String, Value>) -> Self {
611 self.meta = Some(meta);
612 self
613 }
614}
615
616#[derive(Clone, Debug, Deserialize, Serialize)]
619#[non_exhaustive]
620pub struct ExceptionItem {
621 pub id: String,
623 pub item_id: String,
625 pub list_id: String,
626 pub name: String,
627 pub description: String,
628 pub namespace_type: NamespaceType,
629 #[serde(rename = "_version", default)]
631 pub revision: Option<String>,
632 #[serde(rename = "type", default = "simple")]
633 pub item_type: String,
634 pub entries: Vec<Value>,
636 #[serde(default)]
637 pub tags: Vec<String>,
638 #[serde(default)]
639 pub os_types: Vec<OsType>,
640 #[serde(default)]
641 pub comments: Vec<ItemComment>,
642 #[serde(default)]
643 pub expire_time: Option<String>,
644 #[serde(default)]
645 pub meta: Option<Map<String, Value>>,
646 #[serde(flatten)]
647 pub extra: Map<String, Value>,
648}
649
650fn simple() -> String {
651 "simple".into()
652}
653
654impl ExceptionItem {
655 pub fn edit(&self) -> ItemEdit {
678 ItemEdit {
679 id: self.id.clone(),
680 revision: self.revision.clone(),
681 namespace_type: self.namespace_type,
682 item_type: self.item_type.clone(),
683 name: self.name.clone(),
684 description: self.description.clone(),
685 entries: self.entries.clone(),
686 tags: self.tags.clone(),
687 os_types: self.os_types.clone(),
688 comments: Vec::new(),
689 expire_time: self.expire_time.clone(),
690 meta: self.meta.clone(),
691 }
692 }
693}
694
695#[derive(Clone, Debug, Serialize)]
704pub struct ItemEdit {
705 id: String,
706 #[serde(rename = "_version", skip_serializing_if = "Option::is_none")]
707 revision: Option<String>,
708 namespace_type: NamespaceType,
709 #[serde(rename = "type")]
710 item_type: String,
711 name: String,
712 description: String,
713 entries: Vec<Value>,
714 tags: Vec<String>,
715 os_types: Vec<OsType>,
716 comments: Vec<Comment>,
717 #[serde(skip_serializing_if = "Option::is_none")]
718 expire_time: Option<String>,
719 #[serde(skip_serializing_if = "Option::is_none")]
720 meta: Option<Map<String, Value>>,
721}
722
723impl ItemEdit {
724 pub fn name(mut self, name: impl Into<String>) -> Self {
725 self.name = name.into();
726 self
727 }
728
729 pub fn description(mut self, description: impl Into<String>) -> Self {
730 self.description = description.into();
731 self
732 }
733
734 pub fn entries(mut self, entries: impl IntoIterator<Item = Entry>) -> Self {
736 self.entries = entries
737 .into_iter()
738 .map(|entry| serde_json::to_value(&entry).expect("entries serialize as JSON"))
739 .collect();
740 self
741 }
742
743 pub fn tags<I: IntoIterator<Item = S>, S: Into<String>>(mut self, tags: I) -> Self {
744 self.tags = tags.into_iter().map(Into::into).collect();
745 self
746 }
747
748 pub fn os_types(mut self, os_types: Vec<OsType>) -> Self {
749 self.os_types = os_types;
750 self
751 }
752
753 pub fn add_comment(mut self, comment: impl Into<String>) -> Self {
755 self.comments.push(Comment::new(comment));
756 self
757 }
758
759 pub fn expire_time(mut self, time: impl Into<String>) -> Self {
761 self.expire_time = Some(time.into());
762 self
763 }
764
765 pub fn meta(mut self, meta: Map<String, Value>) -> Self {
766 self.meta = Some(meta);
767 self
768 }
769}
770
771#[derive(Clone, Debug, Deserialize, Serialize)]
772#[non_exhaustive]
773pub struct ExceptionPage<T> {
774 pub data: Vec<T>,
775 pub page: u32,
776 pub per_page: u32,
777 pub total: u64,
778 #[serde(flatten)]
779 pub extra: Map<String, Value>,
780}
781
782#[derive(Clone, Debug, Deserialize, Serialize)]
784#[non_exhaustive]
785pub struct ImportResult {
786 pub success: bool,
787 pub success_count: u64,
788 pub errors: Vec<crate::ImportFailure>,
789 #[serde(flatten)]
790 pub extra: Map<String, Value>,
791}
792
793#[derive(Clone, Copy, Debug)]
794pub struct Exceptions<'a>(pub(crate) &'a Kibana);
795
796impl<'a> Exceptions<'a> {
797 pub fn create_list<B: Serialize + ?Sized>(&self, list: &B) -> CreateList<'a> {
799 CreateList(
800 self.0
801 .request(Method::POST, Scope::Space, &["api", "exception_lists"])
802 .json(list),
803 )
804 }
805
806 pub fn get_list<'l>(&self, list: impl Into<ListTarget<'l>>) -> GetList<'a> {
808 GetList(
809 list.into().apply(self.0.request(
810 Method::GET,
811 Scope::Space,
812 &["api", "exception_lists"],
813 )),
814 )
815 }
816
817 pub fn update_list(&self, list: &ListEdit) -> UpdateList<'a> {
821 UpdateList(
822 self.0
823 .request(Method::PUT, Scope::Space, &["api", "exception_lists"])
824 .nonempty("_version", list.revision.as_deref().unwrap_or_default())
825 .json(list),
826 )
827 }
828
829 pub fn delete_list<'l>(&self, list: impl Into<ListTarget<'l>>) -> DeleteList<'a> {
831 DeleteList(list.into().apply(self.0.request(
832 Method::DELETE,
833 Scope::Space,
834 &["api", "exception_lists"],
835 )))
836 }
837
838 pub fn find_lists(&self) -> FindLists<'a> {
839 FindLists(self.0.request(
840 Method::GET,
841 Scope::Space,
842 &["api", "exception_lists", "_find"],
843 ))
844 }
845
846 pub fn create_item<B: Serialize + ?Sized>(&self, item: &B) -> CreateItem<'a> {
848 CreateItem(
849 self.0
850 .request(
851 Method::POST,
852 Scope::Space,
853 &["api", "exception_lists", "items"],
854 )
855 .json(item),
856 )
857 }
858
859 pub fn get_item<'i>(&self, item: impl Into<ItemTarget<'i>>) -> GetItem<'a> {
861 GetItem(item.into().apply(self.0.request(
862 Method::GET,
863 Scope::Space,
864 &["api", "exception_lists", "items"],
865 )))
866 }
867
868 pub fn update_item(&self, item: &ItemEdit) -> UpdateItem<'a> {
872 UpdateItem(
873 self.0
874 .request(
875 Method::PUT,
876 Scope::Space,
877 &["api", "exception_lists", "items"],
878 )
879 .nonempty("_version", item.revision.as_deref().unwrap_or_default())
880 .json(item),
881 )
882 }
883
884 pub fn delete_item<'i>(&self, item: impl Into<ItemTarget<'i>>) -> DeleteItem<'a> {
885 DeleteItem(item.into().apply(self.0.request(
886 Method::DELETE,
887 Scope::Space,
888 &["api", "exception_lists", "items"],
889 )))
890 }
891
892 pub fn find_items<'l>(&self, list: impl Into<ItemsOf<'l>>) -> FindItems<'a> {
898 let list = list.into();
899 let request = self
900 .0
901 .request(
902 Method::GET,
903 Scope::Space,
904 &["api", "exception_lists", "items", "_find"],
905 )
906 .selector(("list_id", list.list_id));
907 FindItems(match list.namespace {
908 Some(namespace) => request.param("namespace_type", namespace.as_str()),
909 None => request,
910 })
911 }
912
913 pub fn summary<'l>(&self, list: impl Into<ListTarget<'l>>) -> Summary<'a> {
916 Summary(list.into().apply(self.0.request(
917 Method::GET,
918 Scope::Space,
919 &["api", "exception_lists", "summary"],
920 )))
921 }
922
923 pub fn duplicate_list(
924 &self,
925 list_id: &str,
926 namespace: NamespaceType,
927 include_expired: bool,
928 ) -> DuplicateList<'a> {
929 DuplicateList(
930 self.0
931 .request(
932 Method::POST,
933 Scope::Space,
934 &["api", "exception_lists", "_duplicate"],
935 )
936 .selector(("list_id", list_id))
937 .param("namespace_type", namespace.as_str())
938 .param("include_expired_exceptions", include_expired),
939 )
940 }
941
942 pub fn export_list(&self, list: &ListReference, include_expired: bool) -> ExportList<'a> {
944 ExportList(
945 self.0
946 .request(
947 Method::POST,
948 Scope::Space,
949 &["api", "exception_lists", "_export"],
950 )
951 .param("id", &list.id)
952 .param("list_id", &list.list_id)
953 .param("namespace_type", list.namespace_type.as_str())
954 .param("include_expired_exceptions", include_expired),
955 )
956 }
957
958 pub fn import_lists(&self, ndjson: impl Into<Vec<u8>>) -> ImportLists<'a> {
961 ImportLists(
962 self.0
963 .request(
964 Method::POST,
965 Scope::Space,
966 &["api", "exception_lists", "_import"],
967 )
968 .file("exceptions.ndjson", "application/ndjson", ndjson.into()),
969 )
970 }
971}
972
973macro_rules! namespace_setter {
974 ($($name:ident),*) => {$(
975 impl $name<'_> {
976 pub fn namespace_type(self, namespace: NamespaceType) -> Self {
978 Self(self.0.param("namespace_type", namespace.as_str()))
979 }
980 }
981 )*};
982}
983
984macro_rules! find_setters {
985 ($($name:ident),*) => {$(
986 impl $name<'_> {
987 pub fn page(self, page: u32) -> Self {
989 Self(self.0.positive_param("page", page))
990 }
991
992 pub fn per_page(self, per_page: u32) -> Self {
993 Self(self.0.positive_param("per_page", per_page))
994 }
995
996 pub fn filter(self, filter: &str) -> Self {
998 Self(self.0.param("filter", filter))
999 }
1000
1001 pub fn sort_field(self, field: &str) -> Self {
1002 Self(self.0.param("sort_field", field))
1003 }
1004
1005 pub fn sort_order(self, order: SortOrder) -> Self {
1006 Self(self.0.param("sort_order", order.as_str()))
1007 }
1008 }
1009 )*};
1010}
1011
1012endpoint! {
1013 CreateList => ExceptionList
1015}
1016
1017endpoint! {
1018 GetList => ExceptionList
1020}
1021
1022endpoint! {
1023 UpdateList => ExceptionList
1025}
1026
1027endpoint! {
1028 DeleteList => ExceptionList
1030}
1031
1032endpoint! {
1033 FindLists => ExceptionPage<ExceptionList>
1035}
1036
1037endpoint! {
1038 CreateItem => ExceptionItem
1040}
1041
1042endpoint! {
1043 GetItem => ExceptionItem
1045}
1046
1047endpoint! {
1048 UpdateItem => ExceptionItem
1050}
1051
1052endpoint! {
1053 DeleteItem => ExceptionItem
1055}
1056
1057endpoint! {
1058 FindItems => ExceptionPage<ExceptionItem>
1060}
1061
1062impl FindItems<'_> {
1063 pub fn search(self, text: &str) -> Self {
1065 Self(self.0.param("search", text))
1066 }
1067}
1068
1069endpoint! {
1070 Summary => Value
1072}
1073
1074impl Summary<'_> {
1075 pub fn filter(self, filter: &str) -> Self {
1077 Self(self.0.param("filter", filter))
1078 }
1079}
1080
1081endpoint! {
1082 DuplicateList => ExceptionList
1084}
1085
1086endpoint! {
1087 ExportList => Raw
1089}
1090
1091endpoint! {
1092 ImportLists => ImportResult
1094}
1095
1096impl ImportLists<'_> {
1097 pub fn overwrite(self, overwrite: bool) -> Self {
1099 Self(self.0.param("overwrite", overwrite))
1100 }
1101
1102 pub fn as_new_list(self, enabled: bool) -> Self {
1104 Self(self.0.param("as_new_list", enabled))
1105 }
1106}
1107
1108namespace_setter!(
1109 GetList, DeleteList, FindLists, GetItem, DeleteItem, FindItems, Summary
1110);
1111find_setters!(FindLists, FindItems);
1112paginated!(
1113 FindLists => ExceptionPage<ExceptionList>,
1114 FindItems => ExceptionPage<ExceptionItem>,
1115);