Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 0 additions & 36 deletions libft-api-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,6 @@
//! # Available Macros
//!
//! * `HasVector` - Derives the `HasVec` trait for structs that contain exactly one `Vec<T>` field
//!
//! # Example
//!
//! ```rust
//! use libft_api_derive::HasVector;
//! use libft_api::api::HasVec;
//!
//! #[derive(HasVector)]
//! struct FtApiUsersResponse {
//! users: Vec<String>,
//! }
//!
//! // This generates an implementation of the HasVec trait automatically:
//! // impl HasVec<String> for FtApiUsersResponse {
//! // fn get_vec(&self) -> &Vec<String> { &self.users }
//! // fn take_vec(self) -> Vec<String> { self.users }
//! // }
//! ```

extern crate proc_macro;

Expand All @@ -45,24 +27,6 @@ use syn::{
/// * The struct must have exactly one field of type `Vec<T>`
/// * The struct must have named fields (not tuple or unit structs)
/// * The field type must be exactly `Vec<T>`, not an alias or reference
///
/// # Example
///
/// ```rust
/// use libft_api_derive::HasVector;
/// use libft_api::api::HasVec;
///
/// #[derive(HasVector)]
/// struct FtApiUsersResponse {
/// users: Vec<String>,
/// }
///
/// // This generates:
/// // impl HasVec<String> for FtApiUsersResponse {
/// // fn get_vec(&self) -> &Vec<String> { &self.users }
/// // fn take_vec(self) -> Vec<String> { self.users }
/// // }
/// ```
#[proc_macro_derive(HasVector)]
pub fn has_vec_derive(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
Expand Down
4 changes: 4 additions & 0 deletions libft-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ exclude = ["src/main.rs"]
[lib]
path="src/lib.rs"

[[bin]]
name = "piscine_users"
path = "bin/piscine_users.rs"

[[example]]
name = "scroll"

Expand Down
50 changes: 50 additions & 0 deletions libft-api/bin/piscine_users.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use std::{io::Write, sync::Arc};

use futures::FutureExt;
use libft_api::{info::ft_campus_id::GYEONGSAN, prelude::*};
use tokio::task::JoinSet;

#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();
let client = Arc::new(FtClient::new(FtClientReqwestConnector::new()));

let req: ReqFn<_> = |session, page| {
async move {
session
.users(
FtApiUsersRequest::new()
.with_page(page)
.with_per_page(100)
.with_filter(vec![FtFilterOption::new(
FtFilterField::PrimaryCampusId,
vec![GYEONGSAN.to_string()],
)])
.with_range(vec![FtRangeOption::new(
FtRangeField::CreatedAt,
vec!["2025-09-01".to_owned(), "2025-10-20".to_owned()],
)]),
)
.await
}
.boxed()
};

let mut handles = JoinSet::new();
for i in 1..=8 {
let client = Arc::clone(&client);
handles.spawn(async move { scroller(&client, 8, i, req).await });
}

let mut result = Vec::new();
while let Some(res) = handles.join_next().await {
match res {
Ok(v) => result.extend(v),
Err(e) => tracing::error!("task failed: {e}"),
}
}

let mut file = std::fs::File::create("pisciner.json").unwrap();
file.write_all(serde_json::to_string_pretty(&result).unwrap().as_bytes())
.unwrap();
}
54 changes: 20 additions & 34 deletions libft-api/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,26 @@
//!
//! # Example
//!
//! ```rust
//! use libft_api::prelude::*;
//!
//! async fn example() -> ClientResult<()> {
//! let token = FtApiToken::try_get(AuthInfo::build_from_env().unwrap()).await?;
//! let client = FtClient::new(FtClientReqwestConnector::new());
//! let session = client.open_session(token);
//!
//! // Access user endpoint through the session
//! let user_response = session.users_id(FtUsersIdRequest::new(12345)).await?;
//! println!("User login: {}", user_response.login);
//!
//! Ok(())
//! }
//! ```
//! # Example
//! ```rust
//! use libft_api::{prelude::*, info::ft_campus_id::GYEONGSAN};
//!
//! # async fn run() -> ClientResult<()> {
//! let token = FtApiToken::try_get(AuthInfo::build_from_env()?).await?;
//! let client = FtClient::new(FtClientReqwestConnector::new());
//! let session = client.open_session(token);
//! let response = session
//! .campus_id_locations(
//! FtApiCampusIdLocationsRequest::new(FtCampusId::new(GYEONGSAN)).with_per_page(1),
//! )
//! .await?;
//! for location in response.location {
//! println!("{:?} @ {:?}", location.user.login, location.host);
//! }
//! # Ok(())
//! # }
//! # tokio::runtime::Runtime::new().unwrap().block_on(run()).unwrap();
//! ```

pub mod campus;
pub mod cursus;
Expand All @@ -47,25 +52,6 @@ pub mod prelude;
///
/// This trait simplifies access to vector fields in API response types.
///
/// # Example
///
/// ```rust
/// use libft_api::api::HasVec;
///
/// struct FtApiUsersResponse {
/// users: Vec<String>,
/// }
///
/// impl HasVec<String> for FtApiUsersResponse {
/// fn get_vec(&self) -> &Vec<String> {
/// &self.users
/// }
///
/// fn take_vec(self) -> Vec<String> {
/// self.users
/// }
/// }
/// ```
pub trait HasVec<T> {
/// Get a reference to the contained vector.
fn get_vec(&self) -> &Vec<T>;
Expand Down
24 changes: 0 additions & 24 deletions libft-api/src/api/campus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,6 @@
//! * **campus_id_users**: Get users associated with a specific campus
//! * **campus_id_journals**: Retrieve journal information for a specific campus
//! * **campus_users**: Get campus user associations
//!
//! # Example
//!
//! ```rust
//! use libft_api::prelude::*;
//!
//! async fn example() -> ClientResult<()> {
//! let token = FtApiToken::try_get(AuthInfo::build_from_env()?).await?;
//! let client = FtClient::new(FtClientReqwestConnector::new());
//! let session = client.open_session(token);
//!
//! // Get all campuses
//! let response = session.campus_id(FtApiCampusIdRequest::new()).await?;
//! println!("Retrieved {} campuses", response.campus.len());
//!
//! // Get specific campus (e.g., Paris campus)
//! let paris_response = session
//! .campus_id(FtApiCampusIdRequest::new().with_campus_id(FtCampusId::new(1)))
//! .await?;
//! println!("Paris campus: {:?}", paris_response.campus.first());
//!
//! Ok(())
//! }
//! ```

pub mod campus_id_journals;
pub use campus_id_journals::*;
Expand Down
36 changes: 7 additions & 29 deletions libft-api/src/api/campus/campus_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,8 @@ where
/// - `ClientResult<FtApiCampusIdResponse>`: Contains a vector of `FtCampus` objects
///
/// # Example
/// ```rust
/// use libft_api::prelude::*;
///
/// async fn example() -> ClientResult<()> {
/// let token = FtApiToken::try_get(AuthInfo::build_from_env()?).await?;
/// let client = FtClient::new(FtClientReqwestConnector::new());
/// let session = client.open_session(token);
///
/// // Get all campuses
/// let response = session.campus_id(FtApiCampusIdRequest::new()).await?;
/// println!("Total campuses: {}", response.campus.len());
///
/// // Get a specific campus (e.g., Paris campus with ID 1)
/// let paris_response = session
/// .campus_id(FtApiCampusIdRequest::new().with_campus_id(FtCampusId::new(1)))
/// .await?;
/// println!("Paris campus name: {:?}", paris_response.campus.first().unwrap().name);
///
/// Ok(())
/// }
/// ```
/// See Test code
pub async fn campus_id(
&self,
req: FtApiCampusIdRequest,
Expand Down Expand Up @@ -105,20 +86,17 @@ mod tests {
use super::*;

#[tokio::test]
async fn basic() {
let token = FtApiToken::try_get(AuthInfo::build_from_env().unwrap())
.await
.unwrap();

async fn basic() -> ClientResult<()> {
let token = FtApiToken::try_get(AuthInfo::build_from_env()?).await?;
let client = FtClient::new(FtClientReqwestConnector::with_connector(
reqwest::Client::new(),
));

let session = client.open_session(token);
let res = session

let _ = session
.campus_id(FtApiCampusIdRequest::new().with_per_page(1))
.await;
.await?;

assert!(res.is_ok());
Ok(())
}
}
2 changes: 1 addition & 1 deletion libft-api/src/api/campus/campus_id_locations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ where
/// use libft_api::prelude::*;
///
/// async fn example() -> ClientResult<()> {
/// let token = FtApiToken::try_get(AuthInfo::build_from_env()?).await?;
/// let token = FtApiToken::try_get(AuthInfo::build_from_env().unwrap()).await.unwrap();
/// let client = FtClient::new(FtClientReqwestConnector::new());
/// let session = client.open_session(token);
///
Expand Down
2 changes: 1 addition & 1 deletion libft-api/src/api/campus/campus_id_users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ where
/// use libft_api::prelude::*;
///
/// async fn example() -> ClientResult<()> {
/// let token = FtApiToken::try_get(AuthInfo::build_from_env()?).await?;
/// let token = FtApiToken::try_get(AuthInfo::build_from_env().unwrap()).await.unwrap();
/// let client = FtClient::new(FtClientReqwestConnector::new());
/// let session = client.open_session(token);
///
Expand Down
2 changes: 1 addition & 1 deletion libft-api/src/api/campus/campus_users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ where
/// use libft_api::prelude::*;
///
/// async fn example() -> ClientResult<()> {
/// let token = FtApiToken::try_get(AuthInfo::build_from_env()?).await?;
/// let token = FtApiToken::try_get(AuthInfo::build_from_env().unwrap()).await.unwrap();
/// let client = FtClient::new(FtClientReqwestConnector::new());
/// let session = client.open_session(token);
///
Expand Down
2 changes: 1 addition & 1 deletion libft-api/src/api/cursus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//! use libft_api::prelude::*;
//!
//! async fn example() -> ClientResult<()> {
//! let token = FtApiToken::try_get(AuthInfo::build_from_env()?).await?;
//! let token = FtApiToken::try_get(AuthInfo::build_from_env().unwrap()).await.unwrap();
//! let client = FtClient::new(FtClientReqwestConnector::new());
//! let session = client.open_session(token);
//!
Expand Down
43 changes: 24 additions & 19 deletions libft-api/src/api/cursus/cursus_id_projects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,25 +44,30 @@ where
/// - `ClientResult<FtApiCursusIdProjectsResponse>`: Contains a vector of `FtProject` objects
///
/// # Example
/// ```rust
/// use libft_api::prelude::*;
///
/// async fn example() -> ClientResult<()> {
/// let token = FtApiToken::try_get(AuthInfo::build_from_env()?).await?;
/// let client = FtClient::new(FtClientReqwestConnector::new());
/// let session = client.open_session(token);
///
/// // Get projects for the common core cursus
/// let projects = session
/// .cursus_id_projects(
/// FtApiCursusIdProjectsRequest::new(FtCursusId::new(FT_CURSUS_ID))
/// )
/// .await?;
/// println!("Found {} projects", projects.projects.len());
///
/// Ok(())
/// }
/// ```
/// ```rust
/// use libft_api::{prelude::*, info::ft_campus_id::GYEONGSAN};
///
/// # async fn run() -> ClientResult<()> {
/// let token = FtApiToken::try_get(AuthInfo::build_from_env().unwrap())
/// .await
/// .unwrap();
///
/// let client = FtClient::new(FtClientReqwestConnector::with_connector(
/// reqwest::Client::new(),
/// ));
///
/// let session = client.open_session(token);
/// let res = session
/// .cursus_id_projects(
/// FtApiCursusIdProjectsRequest::new(FtCursusId::new(FT_CURSUS_ID)).with_per_page(1),
/// )
/// .await;
///
/// # assert!(res.is_ok());
/// # Ok(())
/// # }
/// # tokio::runtime::Runtime::new().unwrap().block_on(run()).unwrap();
/// ```
pub async fn cursus_id_projects(
&self,
req: FtApiCursusIdProjectsRequest,
Expand Down
2 changes: 1 addition & 1 deletion libft-api/src/api/exam.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
//! use libft_api::prelude::*;
//!
//! async fn example() -> ClientResult<()> {
//! let token = FtApiToken::try_get(AuthInfo::build_from_env()?).await?;
//! let token = FtApiToken::try_get(AuthInfo::build_from_env().unwrap()).await.unwrap();
//! let client = FtClient::new(FtClientReqwestConnector::new());
//! let session = client.open_session(token);
//!
Expand Down
4 changes: 2 additions & 2 deletions libft-api/src/api/exam/exams.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ where
/// use libft_api::prelude::*;
///
/// async fn example() -> ClientResult<()> {
/// let token = FtApiToken::try_get(AuthInfo::build_from_env()?).await?;
/// let token = FtApiToken::try_get(AuthInfo::build_from_env().unwrap()).await.unwrap();
/// let client = FtClient::new(FtClientReqwestConnector::new());
/// let session = client.open_session(token);
///
Expand Down Expand Up @@ -125,7 +125,7 @@ where
/// use libft_api::prelude::*;
///
/// async fn example() -> ClientResult<()> {
/// let token = FtApiToken::try_get(AuthInfo::build_from_env()?).await?;
/// let token = FtApiToken::try_get(AuthInfo::build_from_env().unwrap()).await.unwrap();
/// let client = FtClient::new(FtClientReqwestConnector::new());
/// let session = client.open_session(token);
///
Expand Down
Loading
Loading