use {
crate::*,
anyhow::*,
byo_graphql::{
Count,
GraphqlClient,
List,
},
chrono::{
DateTime,
Utc,
},
serde::Deserialize,
};
pub static GITHUB_API_TOKEN_KEY: &str = "github-api-token";
pub struct GithubClient {
gql_client: GraphqlClient,
}
impl GithubClient {
pub fn new(conf: &Conf) -> Result<Self> {
let github_api_token = conf.get(GITHUB_API_TOKEN_KEY).ok_or_else(|| {
anyhow!(
"You must first set a github API token with `starry set {} your-key`",
GITHUB_API_TOKEN_KEY
)
})?;
let mut gql_client = GraphqlClient::new("https://api.github.com/graphql")?;
gql_client.set_bearer_auth(github_api_token);
Ok(Self { gql_client })
}
pub async fn get_user(
&self,
user_id: UserId,
) -> Result<User> {
#[derive(Deserialize)]
pub struct GQUser {
pub name: String,
pub repositories: Count,
}
let query = format!(
"{{ {} {{ name {} }} }}",
user_id.graphql_selector(),
Count::query("repositories", "isFork: false"),
);
let gquser: GQUser = self.gql_client.get_first_item(query).await?;
Ok(User {
user_id,
name: gquser.name,
non_fork_repositories_count: gquser.repositories.into(),
})
}
pub async fn get_user_star_counts(
&self,
user_id: UserId,
now: DateTime<Utc>,
) -> Result<UserObs> {
#[derive(Deserialize)]
pub struct User {
pub repositories: Repositories,
}
#[derive(Debug, Deserialize)]
pub struct Repository {
pub name: String,
pub stargazers: Count,
}
let mut counts = Vec::new();
type Repositories = List<Repository>;
let page_size = 100;
let mut cursor: Option<String> = None;
loop {
let query = format!(
"{{ {} {{ repositories{}{} }} }}",
user_id.graphql_selector(),
Repositories::query_page_selector(
&cursor,
page_size,
"isFork: false, ownerAffiliations: OWNER",
),
Repositories::query_page_body("{ name, stargazers { totalCount } }"),
);
let mut user: User = self.gql_client.get_first_item(&query).await?;
for repo in user.repositories.nodes.drain(..) {
counts.push(RepoObs {
repo_name: repo.name,
stars: repo.stargazers.into(),
});
}
cursor = user.repositories.next_page_cursor();
if cursor.is_none() {
break;
}
}
Ok(UserObs {
user_id,
time: now,
counts,
})
}
}