From 78f6d187519ff8740ba438e6e09ae2cd544955cd Mon Sep 17 00:00:00 2001 From: Kornel Date: Sat, 11 Apr 2020 19:27:17 +0100 Subject: Fix github wrapper --- github_info/src/lib_github.rs | 15 ++++++--------- github_v3/Cargo.toml | 2 +- github_v3/src/lib.rs | 31 ++++++++++++++++++++++++++++--- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/github_info/src/lib_github.rs b/github_info/src/lib_github.rs index d3b1cea..375153f 100644 --- a/github_info/src/lib_github.rs +++ b/github_info/src/lib_github.rs @@ -5,7 +5,6 @@ use std::path::Path; use github_v3::StatusCode; use serde::{Deserialize, Serialize}; -use urlencoding::encode; mod model; pub use crate::model::*; @@ -88,9 +87,9 @@ impl GitHub { return Ok(Some(vec![user])); } } - let enc_email = encode(email); self.get_cached(&self.emails, (email, ""), |client| client.get() - .path(&format!("search/users?q=in:email%20{}", enc_email)) + .path("search/users") + .query("q=in:email%20").arg(email) .send(), |res: SearchResults| { println!("Found {} = {:#?}", email, res.items); res.items @@ -128,9 +127,8 @@ impl GitHub { pub async fn releases(&self, repo: &SimpleRepo, as_of_version: &str) -> CResult>> { let key = format!("release/{}/{}", repo.owner, repo.repo); - let path = format!("repos/{}/{}/releases", repo.owner, repo.repo); self.get_cached(&self.releases, (&key, as_of_version), |client| client.get() - .path(&path) + .path("repos").arg(&repo.owner).arg(&repo.repo).path("releases") .send(), id).await.map_err(|e| e.context("releases")) } @@ -164,10 +162,9 @@ impl GitHub { pub async fn contributors(&self, repo: &SimpleRepo, as_of_version: &str) -> CResult>> { let path = format!("repos/{}/{}/stats/contributors", repo.owner, repo.repo); let key = (path.as_str(), as_of_version); - let callback = |client: &github_v3::Client| { - client.get().path(&path).send() - }; - self.get_cached(&self.contribs, key, callback, id).await + self.get_cached(&self.contribs, key, |client: &github_v3::Client| { + client.get().path("repos").arg(&repo.owner).arg(&repo.repo).path("stats/contributors").send() + }, id).await } async fn get_cached(&self, cache: &TempCache<(String, Option)>, key: (&str, &str), cb: F, postproc: P) -> CResult> diff --git a/github_v3/Cargo.toml b/github_v3/Cargo.toml index 5f5247c..5506603 100644 --- a/github_v3/Cargo.toml +++ b/github_v3/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "github_v3" description = "Async GitHub API v3 client" -version = "0.3.1" +version = "0.3.2" authors = ["Kornel "] keywords = ["github", "restful", "api", "async"] categories = ["web-programming", "web-programming::http-client"] diff --git a/github_v3/src/lib.rs b/github_v3/src/lib.rs index a5fc31a..79c5a06 100644 --- a/github_v3/src/lib.rs +++ b/github_v3/src/lib.rs @@ -61,29 +61,53 @@ impl Response { pub struct Builder { client: Arc, url: String, + query_string_started: bool, } impl Builder { /// Add a constant path to the request, e.g. `.path("users")` /// + /// Inner slashes are OK, but the string must not start or end with a slash. + /// + /// Panics if query string has been added. + /// /// It's appended raw, so must be URL-safe. pub fn path(mut self, url_part: &'static str) -> Self { debug_assert_eq!(url_part, url_part.trim_matches('/')); + assert!(!self.query_string_started); self.url.push('/'); self.url.push_str(url_part); self } - /// Add a user-supplied argument to the request path, e.g. `.path("users").arg(username)` + /// Add a user-supplied argument to the request path, e.g. `.path("users").arg(username)`, + /// or after a call to query(), starts adding fragments to the query string with no delimiters. /// /// The arg is URL-escaped, so it's safe to use any user-supplied data. pub fn arg(mut self, arg: &str) -> Self { - self.url.push('/'); + if !self.query_string_started { + self.url.push('/'); + } self.url.push_str(&urlencoding::encode(arg)); self } + /// Add a raw unescaped query string. The string must *not* start with `?` + /// + /// ```rust + /// # Client::new(None) + /// .get().path("search/users").query("q=").arg(somestring) + /// ``` + pub fn query(mut self, query_string: &str) -> Self { + debug_assert!(!query_string.starts_with('?')); + debug_assert!(!query_string.starts_with('&')); + self.url.push(if self.query_string_started {'&'} else {'?'}); + self.url.push_str(query_string); + self.query_string_started = true; + self + } + /// Make the request pub async fn send(self) -> Result { let res = self.client.raw_get(&self.url).await?; @@ -135,11 +159,12 @@ impl Client { /// Make a new request to the API. pub fn get(&self) -> Builder { - let mut url = String::with_capacity(60); + let mut url = String::with_capacity(100); url.push_str("https://api.github.com"); Builder { client: self.inner.clone(), url, + query_string_started: false, } } } -- cgit v1.2.3