-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Kouhei Aoyagi
committed
Mar 26, 2024
1 parent
391d251
commit f5c1dfc
Showing
9 changed files
with
251 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(()) | ||
} |