twapi_v2/api/
post_2_tweets_search_stream_rules.rs1use crate::responses::{errors::Errors, streams::Streams, summary::Summary};
2use crate::{
3 api::{Authentication, TwapiOptions, execute_twitter, make_url},
4 error::Error,
5 headers::Headers,
6};
7use chrono::prelude::*;
8use reqwest::RequestBuilder;
9use serde::{Deserialize, Serialize};
10
11const URL: &str = "/2/tweets/search/stream/rules";
12
13#[derive(Serialize, Deserialize, Debug, Default, Clone)]
14pub struct Add {
15 pub value: String,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub tag: Option<String>,
18}
19
20#[derive(Serialize, Deserialize, Debug, Default, Clone)]
21pub struct Delete {
22 pub ids: Vec<String>,
23}
24
25#[derive(Serialize, Deserialize, Debug, Default, Clone)]
26pub struct Body {
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub add: Option<Vec<Add>>,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub delete: Option<Delete>,
31}
32
33#[derive(Debug, Clone, Default)]
34pub struct Api {
35 dry_run: Option<bool>,
36 body: Body,
37 twapi_options: Option<TwapiOptions>,
38}
39
40impl Api {
41 pub fn new(body: Body) -> Self {
42 Self {
43 body,
44 ..Default::default()
45 }
46 }
47
48 pub fn dry_run(mut self, value: bool) -> Self {
49 self.dry_run = Some(value);
50 self
51 }
52
53 pub fn twapi_options(mut self, value: TwapiOptions) -> Self {
54 self.twapi_options = Some(value);
55 self
56 }
57
58 pub fn build(&self, authentication: &impl Authentication) -> RequestBuilder {
59 let mut query_parameters = vec![];
60 if let Some(dry_run) = self.dry_run.as_ref() {
61 query_parameters.push(("dry_run", dry_run.to_string()));
62 }
63 let client = reqwest::Client::new();
64 let url = make_url(&self.twapi_options, URL);
65 let builder = client.post(&url).query(&query_parameters).json(&self.body);
66 authentication.execute(
67 builder,
68 "POST",
69 &url,
70 &query_parameters
71 .iter()
72 .map(|it| (it.0, it.1.as_str()))
73 .collect::<Vec<_>>(),
74 )
75 }
76
77 pub async fn execute(
78 &self,
79 authentication: &impl Authentication,
80 ) -> Result<(Response, Headers), Error> {
81 execute_twitter(|| self.build(authentication), &self.twapi_options).await
82 }
83}
84
85#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
86pub struct Response {
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub data: Option<Vec<Streams>>,
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub errors: Option<Vec<Errors>>,
91 pub meta: Meta,
92 #[serde(flatten)]
93 pub extra: std::collections::HashMap<String, serde_json::Value>,
94}
95
96impl Response {
97 pub fn is_empty_extra(&self) -> bool {
98 let res = self.extra.is_empty()
99 && self
100 .data
101 .as_ref()
102 .map(|it| it.iter().all(|item| item.is_empty_extra()))
103 .unwrap_or(true)
104 && self
105 .errors
106 .as_ref()
107 .map(|it| it.iter().all(|item| item.is_empty_extra()))
108 .unwrap_or(true)
109 && self.meta.is_empty_extra();
110 if !res {
111 println!("Response {:?}", self.extra);
112 }
113 res
114 }
115}
116
117#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
118pub struct Meta {
119 pub sent: DateTime<Utc>,
120 pub summary: Summary,
121 #[serde(flatten)]
122 pub extra: std::collections::HashMap<String, serde_json::Value>,
123}
124
125impl Meta {
126 pub fn is_empty_extra(&self) -> bool {
127 let res = self.extra.is_empty() && self.summary.is_empty_extra();
128 if !res {
129 println!("Meta {:?}", self.extra);
130 }
131 res
132 }
133}