Skip to content

Commit

Permalink
add usage
Browse files Browse the repository at this point in the history
  • Loading branch information
Kouhei Aoyagi committed Mar 26, 2024
1 parent 391d251 commit f5c1dfc
Show file tree
Hide file tree
Showing 9 changed files with 251 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub mod get_2_tweets_search_all;
pub mod get_2_tweets_search_recent;
pub mod get_2_tweets_search_stream;
pub mod get_2_tweets_search_stream_rules;
pub mod get_2_usage_tweets;
pub mod get_2_users;
pub mod get_2_users_by;
pub mod get_2_users_by_username_username;
Expand Down
127 changes: 127 additions & 0 deletions src/api/get_2_usage_tweets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use itertools::Itertools;
use std::collections::HashSet;
use serde::{Serialize, Deserialize};
use crate::fields::{usage_fields::UsageFields};
use crate::responses::{daily_client_app_usage::DailyClientAppUsage, daily_project_usage::DailyProjectUsage, errors::Errors, includes::Includes, meta::Meta};
use reqwest::RequestBuilder;
use crate::{error::Error, headers::Headers, api::{execute_twitter, Authentication, make_url}};

const URL: &str = "/2/usage/tweets";





#[derive(Debug, Clone, Default)]
pub struct Api {
usage_fields: Option<HashSet<UsageFields>>,
days: Option<usize>,
}

impl Api {
pub fn new() -> Self {
Self {
..Default::default()
}
}

pub fn all() -> Self {
Self {
usage_fields: Some(UsageFields::all()),
days: Some(90),
}
}

pub fn usage_fields(mut self, value: HashSet<UsageFields>) -> Self {
self.usage_fields = Some(value);
self
}

pub fn days(mut self, value: usize) -> Self {
self.days = Some(value);
self
}

pub fn build(self, authentication: &impl Authentication) -> RequestBuilder {
let mut query_parameters = vec![];
if let Some(usage_fields) = self.usage_fields {
query_parameters.push(("usage.fields", usage_fields.iter().join(",")));
}
if let Some(days) = self.days {
query_parameters.push(("days", days.to_string()));
}
let client = reqwest::Client::new();
let url = make_url(URL);
let builder = client
.get(&url)
.query(&query_parameters)
;
authentication.execute(builder, "GET", &url, &query_parameters.iter().map(|it| (it.0, it.1.as_str())).collect::<Vec<_>>())
}

pub async fn execute(self, authentication: &impl Authentication) -> Result<(Response, Headers), Error> {
execute_twitter(self.build(authentication)).await
}
}



#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct Response {
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<Data>,
#[serde(skip_serializing_if = "Option::is_none")]
pub errors: Option<Vec<Errors>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub includes: Option<Includes>,
#[serde(skip_serializing_if = "Option::is_none")]
pub meta: Option<Meta>,
#[serde(flatten)]
pub extra: std::collections::HashMap<String, serde_json::Value>,
}

impl Response {
pub fn is_empty_extra(&self) -> bool {
let res = self.extra.is_empty() &&
self.data.as_ref().map(|it| it.is_empty_extra()).unwrap_or(true) &&
self.errors.as_ref().map(|it| it.iter().all(|item| item.is_empty_extra())).unwrap_or(true) &&
self.includes.as_ref().map(|it| it.is_empty_extra()).unwrap_or(true) &&
self.meta.as_ref().map(|it| it.is_empty_extra()).unwrap_or(true);
if !res {
println!("Response {:?}", self.extra);
}
res
}
}



#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct Data {
#[serde(skip_serializing_if = "Option::is_none")]
pub cap_reset_day: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub daily_client_app_usage: Option<Vec<DailyClientAppUsage>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub daily_project_usage: Option<DailyProjectUsage>,
#[serde(skip_serializing_if = "Option::is_none")]
pub project_cap: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub project_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub project_usage: Option<String>,
#[serde(flatten)]
pub extra: std::collections::HashMap<String, serde_json::Value>,
}

impl Data {
pub fn is_empty_extra(&self) -> bool {
let res = self.extra.is_empty() &&
self.daily_client_app_usage.as_ref().map(|it| it.iter().all(|item| item.is_empty_extra())).unwrap_or(true) &&
self.daily_project_usage.as_ref().map(|it| it.is_empty_extra()).unwrap_or(true);
if !res {
println!("Data {:?}", self.extra);
}
res
}
}
1 change: 1 addition & 0 deletions src/fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ pub mod poll_fields;
pub mod space_fields;
pub mod topic_fields;
pub mod tweet_fields;
pub mod usage_fields;
pub mod user_fields;
32 changes: 32 additions & 0 deletions src/fields/usage_fields.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use serde::{Serialize, Deserialize};
use std::collections::HashSet;

#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Clone)]
pub enum UsageFields {
#[serde(rename = "daily_client_app_usage")]
DailyClientAppUsage,
#[serde(rename = "daily_project_usage")]
DailyProjectUsage,
}

impl UsageFields {
pub fn all() -> HashSet<Self> {
let mut result = HashSet::new();
result.insert(Self::DailyClientAppUsage);
result.insert(Self::DailyProjectUsage);
result
}
}

impl std::fmt::Display for UsageFields {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::DailyClientAppUsage => write!(f, "daily_client_app_usage"),
Self::DailyProjectUsage => write!(f, "daily_project_usage"),
}
}
}

impl Default for UsageFields {
fn default() -> Self { Self::DailyClientAppUsage }
}
3 changes: 3 additions & 0 deletions src/responses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ pub mod compliance_user;
pub mod context_annotations;
pub mod coordinates;
pub mod counts;
pub mod daily_client_app_usage;
pub mod daily_project_usage;
pub mod description;
pub mod dm_events;
pub mod edit_controls;
Expand Down Expand Up @@ -41,6 +43,7 @@ pub mod topics;
pub mod trends;
pub mod tweets;
pub mod urls;
pub mod usage;
pub mod user_entities;
pub mod user_url;
pub mod users;
Expand Down
25 changes: 25 additions & 0 deletions src/responses/daily_client_app_usage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use crate::responses::{usage::Usage};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct DailyClientAppUsage {
#[serde(skip_serializing_if = "Option::is_none")]
pub client_app_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub usage_result_count: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub usage: Option<Vec<Usage>>,
#[serde(flatten)]
pub extra: std::collections::HashMap<String, serde_json::Value>,
}

impl DailyClientAppUsage {
pub fn is_empty_extra(&self) -> bool {
let res = self.extra.is_empty() &&
self.usage.as_ref().map(|it| it.iter().all(|item| item.is_empty_extra())).unwrap_or(true);
if !res {
println!("DailyClientAppUsage {:?}", self.extra);
}
res
}
}
23 changes: 23 additions & 0 deletions src/responses/daily_project_usage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use crate::responses::{usage::Usage};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct DailyProjectUsage {
#[serde(skip_serializing_if = "Option::is_none")]
pub project_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub usage: Option<Vec<Usage>>,
#[serde(flatten)]
pub extra: std::collections::HashMap<String, serde_json::Value>,
}

impl DailyProjectUsage {
pub fn is_empty_extra(&self) -> bool {
let res = self.extra.is_empty() &&
self.usage.as_ref().map(|it| it.iter().all(|item| item.is_empty_extra())).unwrap_or(true);
if !res {
println!("DailyProjectUsage {:?}", self.extra);
}
res
}
}
21 changes: 21 additions & 0 deletions src/responses/usage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct Usage {
#[serde(skip_serializing_if = "Option::is_none")]
pub date: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub usage: Option<String>,
#[serde(flatten)]
pub extra: std::collections::HashMap<String, serde_json::Value>,
}

impl Usage {
pub fn is_empty_extra(&self) -> bool {
let res = self.extra.is_empty();
if !res {
println!("Usage {:?}", self.extra);
}
res
}
}
18 changes: 18 additions & 0 deletions tests/get_2_usage_tweets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use anyhow::Result;
use twapi_v2::api::{self, execute_twitter, get_2_usage_tweets, BearerAuthentication};

// BEARER_CODE=XXXX cargo test test_get_2_usage_tweets_oauth --all-features -- --nocapture --test-threads=1

#[tokio::test]
async fn test_get_2_usage_tweets_oauth() -> Result<()> {
api::clear_prefix_url();
let bearer_code = std::env::var("BEARER_CODE").unwrap_or_default();
let bearer_auth = BearerAuthentication::new(bearer_code);
let builder = get_2_usage_tweets::Api::all()
.build(&bearer_auth);
let (res, _) = execute_twitter::<serde_json::Value>(builder).await?;
println!("{}", serde_json::to_string(&res).unwrap());
let response = serde_json::from_value::<get_2_usage_tweets::Response>(res)?;
assert_eq!(response.is_empty_extra(), true);
Ok(())
}

0 comments on commit f5c1dfc

Please sign in to comment.