diff --git a/examples/invitations.rs b/examples/invitations.rs new file mode 100644 index 00000000..87ce009a --- /dev/null +++ b/examples/invitations.rs @@ -0,0 +1,49 @@ +use std::env; +use std::fs::File; +use std::io::Read; + +use tokio::runtime::Runtime; + +use futures::stream::Stream; +use hubcaps::{Credentials, Github, InstallationTokenGenerator, JWTCredentials, Result}; + +fn var(name: &str) -> Result { + if let Some(v) = env::var(name).ok() { + Ok(v) + } else { + Err(format!("example missing {}", name).into()) + } +} + +const USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); + +fn main() -> Result<()> { + pretty_env_logger::init(); + let key_file = var("GH_APP_KEY")?; + let app_id = var("GH_APP_ID")?; + let installation_id = var("GH_INSTALL_ID")?; + + let mut rt = Runtime::new()?; + + let mut key = Vec::new(); + File::open(&key_file)?.read_to_end(&mut key)?; + let cred = JWTCredentials::new(app_id.parse().expect("Bad GH_APP_ID"), key)?; + + let mut github = Github::new(USER_AGENT, Credentials::JWT(cred.clone()))?; + github.set_credentials(Credentials::InstallationToken( + InstallationTokenGenerator::new(installation_id.parse().unwrap(), cred), + )); + + rt.block_on( + github + .org("NixOS") + .membership() + .invitations() + .for_each(|invite| { + println!("{:#?}", invite); + Ok(()) + }), + )?; + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index ef25ffe0..f3e69d39 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,6 +123,7 @@ pub mod hooks; pub mod issues; pub mod keys; pub mod labels; +pub mod membership; pub mod notifications; pub mod organizations; pub mod pull_commits; diff --git a/src/membership.rs b/src/membership.rs new file mode 100644 index 00000000..36fe03a9 --- /dev/null +++ b/src/membership.rs @@ -0,0 +1,54 @@ +//! Organization Membership interface +use serde::Deserialize; + +use crate::users::User; +use crate::{Github, Stream}; + +/// Provides access to membership operations available for an individual organization +pub struct OrgMembership { + github: Github, + org: String, +} + +impl OrgMembership { + #[doc(hidden)] + pub fn new(github: Github, org: O) -> Self + where + O: Into, + { + Self { + github, + org: org.into(), + } + } + + /// Return a stream of all invitations for this repository + /// + /// See the [github docs](https://developer.github.com/v3/orgs/members/) + /// for more information + pub fn invitations(&self) -> Stream { + self.github + .get_stream(&format!("/orgs/{}/invitations", self.org)) + } +} + +#[derive(Debug, Deserialize)] +pub struct Invitation { + pub id: u64, + pub login: Option, + pub email: Option, + pub role: InvitedRole, + pub created_at: String, // TODO: change to `DateTime`? + pub inviter: User, + pub team_count: Option, +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "snake_case")] +pub enum InvitedRole { + DirectMember, + Admin, + BillingManager, + HiringManager, + Reinstate, +} diff --git a/src/organizations.rs b/src/organizations.rs index 5e3bdd73..34dcb320 100644 --- a/src/organizations.rs +++ b/src/organizations.rs @@ -1,6 +1,7 @@ //! Organizations interface use serde::Deserialize; +use crate::membership::OrgMembership; use crate::repositories::OrgRepositories; use crate::teams::OrgTeams; use crate::{Future, Github}; @@ -23,6 +24,11 @@ impl Organization { } } + /// returns a reference to an interface for Organization invitations + pub fn membership(&self) -> OrgMembership { + OrgMembership::new(self.github.clone(), self.org.clone()) + } + /// returns a reference to an interface for team operations pub fn teams(&self) -> OrgTeams { OrgTeams::new(self.github.clone(), self.org.clone())