github-status/src/main.rs
2022-10-13 20:10:18 +02:00

140 lines
3.7 KiB
Rust

use clap::Parser;
use eyre::{Context, ContextCompat};
use graphql_client::{reqwest::post_graphql_blocking as post_graphql, GraphQLQuery};
use reqwest::blocking::Client;
#[derive(clap::ValueEnum, Clone, Debug)]
enum Availability {
Busy,
Free,
}
#[derive(Parser, Debug, Clone)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Emoji to set ':smile:'
#[arg(short, long)]
emoji: Option<String>,
/// Message to display
#[arg(short, long)]
message: Option<String>,
#[arg(value_enum)]
availability: Option<Availability>,
#[arg(long)]
expires_in_minutes: Option<i64>,
#[arg(short, long)]
organization_id: Option<String>,
#[clap(env, long)]
github_token: Option<String>,
#[clap(env, long)]
github_url: Option<String>,
}
struct Status {
emoji: Option<String>,
message: Option<String>,
availability: Availability,
expires: Option<chrono::DateTime<chrono::Utc>>,
organization_id: Option<String>,
}
fn main() -> eyre::Result<()> {
let args = Args::parse();
let status = get_status_input(args.clone())?;
let github_token = get_github_token(args.clone())?;
set_github_status(args.github_url, github_token, status)?;
Ok(())
}
fn get_status_input(args: Args) -> eyre::Result<Status> {
Ok(Status {
emoji: args.emoji,
message: args.message,
availability: match args.availability {
Some(av) => av,
None => Availability::Free,
},
expires: match args.expires_in_minutes {
Some(0) => None,
Some(min) => Some(chrono::offset::Utc::now() + chrono::Duration::minutes(min)),
None => None,
},
organization_id: args.organization_id,
})
}
fn get_github_token(args: Args) -> eyre::Result<String> {
match args.github_token {
Some(token) => Ok(token),
None => {
// Temporary maybe moved because this should support different providers
Err(eyre::anyhow!("could not find github_token variable"))
}
}
}
type DateTime = String;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "commands/schema/github.graphql",
query_path = "commands/mutations/setGithubStatus.graphql",
response_derives = "Debug"
)]
pub struct SetStatus;
fn set_github_status(
github_url: Option<String>,
github_token: String,
status: Status,
) -> eyre::Result<()> {
let client = Client::builder()
.user_agent("graphql-rust/0.10.0")
.default_headers(
std::iter::once((
reqwest::header::AUTHORIZATION,
reqwest::header::HeaderValue::from_str(&format!("Bearer {}", github_token))
.context("could not format bearer token")?,
))
.collect(),
)
.build()?;
let variables = set_status::Variables {
status: set_status::ChangeUserStatusInput {
client_mutation_id: None,
emoji: status.emoji,
expires_at: status
.expires
.map(|expires| expires.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)),
limited_availability: Some(match status.availability {
Availability::Busy => true,
Availability::Free => false,
}),
message: status.message,
organization_id: status.organization_id,
},
};
let response_body = post_graphql::<SetStatus, _>(
&client,
match github_url {
Some(url) => url,
None => "https://api.github.com/graphql".into(),
},
variables,
)
.unwrap();
let _: set_status::ResponseData = response_body.data.context("missing response data")?;
Ok(())
}