From d1855810f2f8656db06500440555a2df70c0476b Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Sun, 14 May 2017 15:14:51 -0700 Subject: [PATCH 01/22] begin work on Projects Signed-off-by: Hunar Roop Kahlon --- src/lib.rs | 3 ++ src/project/category_impl.rs | 86 ++++++++++++++++++++++++++++++ src/project/mod.rs | 100 +++++++++++++++++++++++++++++++++++ src/serialize.rs | 30 +++++++++++ 4 files changed, 219 insertions(+) create mode 100644 src/project/category_impl.rs create mode 100644 src/project/mod.rs create mode 100644 src/serialize.rs diff --git a/src/lib.rs b/src/lib.rs index ccd9e94..793250c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,8 +15,11 @@ extern crate serde; extern crate serde_derive; extern crate serde_json; +pub mod project; pub mod query; +mod serialize; + mod api; mod types; diff --git a/src/project/category_impl.rs b/src/project/category_impl.rs new file mode 100644 index 0000000..6f7b1f1 --- /dev/null +++ b/src/project/category_impl.rs @@ -0,0 +1,86 @@ +/* + Crate: ore + File: /project/category_impl.rs + Module: ::project::category_impl + Visibility: private + */ + +// TODO: documentation + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde::de::{Error as SerdeError, MapAccess, Visitor}; +use std::error::Error as StdError; +use std::fmt::{Formatter, Result as FmtResult}; +use super::{Category}; + +struct CategoryVisitor; + +impl<'a> Visitor<'a> for CategoryVisitor { + type Value = Category; + + fn expecting(&self, formatter: &mut Formatter) -> FmtResult { + write!(formatter, + r#"an integer between 0 and 10 or an object with a string value "category""#) + } + + fn visit_u8(self, value: u8) -> Result + where E: StdError + { + Ok(match value { + 0 => Category::AdminTools, + 1 => Category::Chat, + 2 => Category::DeveloperTools, + 3 => Category::Economy, + 4 => Category::Gameplay, + 5 => Category::Games, + 6 => Category::Protection, + 7 => Category::RolePlaying, + 8 => Category::WorldManagement, + 9 => Category::Miscellaneous, + _ => Category::Undefined, + }) + } + + fn visit_map(self, mut map: A) -> Result + where A: MapAccess<'a> + { + let mut category = None; + + while let Ok(Some((key, value))) = map.next_entry::() { + if key == "title" { + category = Some(match value.as_str() { + "Admin Tools" => Category::AdminTools, + "Chat" => Category::Chat, + "Developer Tools" => Category::DeveloperTools, + "Economy" => Category::Economy, + "Gameplay" => Category::Gameplay, + "Games" => Category::Games, + "Protection" => Category::Protection, + "Role Playing" => Category::RolePlaying, + "World Management" => Category::WorldManagement, + "Miscellaneous" => Category::Miscellaneous, + _ => Category::Undefined, + }); + } + } + category.ok_or(SerdeDeError::custom(r#"Invalid value "category""#)) + } +} + +#[doc(hidden)] +impl Serialize for Category { + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + serializer.serialize_u8(*self as u8) + } +} + +#[doc(hidden)] +impl<'a> Deserialize<'a> for Category { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'a> + { + deserializer.deserialize_any(CategoryVisitor) + } +} \ No newline at end of file diff --git a/src/project/mod.rs b/src/project/mod.rs new file mode 100644 index 0000000..633f1d6 --- /dev/null +++ b/src/project/mod.rs @@ -0,0 +1,100 @@ +/* + Crate: ore + File: /project/mod.rs + Module: ::project + Visibility: private + */ + +// TODO: documentation + +use chrono::{DateTime, UTC}; +use serialize::{deserialize_datetime, serialize_datetime}; + +// TODO: documentation +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Channel<'a> { + color: &'a str, + name: &'a str, +} + +// TODO: documentation +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Dependency<'a> { + plugin_id: &'a str, + version: &'a str, +} + +// TODO: documentation +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Member<'a> { + head_role: Role, + name: &'a str, + roles: Vec, + user_id: u32, +} + +// TODO: documentation +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Project<'a> { + category: Category, + channels: Vec>, + #[serde(serialize_with = "serialize_datetime", deserialize_with = + "deserialize_datetime")] + created_at: DateTime, + description: &'a str, + downloads: u32, + href: &'a str, + members: Vec>, + name: &'a str, + owner: &'a str, + plugin_id: &'a str, + recommended: Version<'a>, + stars: u32, + views: u32, +} + +// TODO: documentation +#[repr(u8)] +#[derive(Clone, Copy, Debug)] +pub enum Category { + AdminTools = 0, + Chat, + DeveloperTools, + Economy, + Gameplay, + Games, + Protection, + RolePlaying, + WorldManagement, + Miscellaneous, + Undefined, +} + +// TODO: documentation +#[repr(u8)] +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum Role { + Admin, + Developer, + Editor, + Owner, + Support, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Version<'a> { + channel: Channel<'a>, + #[serde(serialize_with = "serialize_datetime", deserialize_with = "deserialize_datetime")] + created_at: DateTime, + file_size: u32, + dependencies: Vec>, + name: &'a str, + staff_approved: bool, +} + +mod category_impl; diff --git a/src/serialize.rs b/src/serialize.rs new file mode 100644 index 0000000..b34acaa --- /dev/null +++ b/src/serialize.rs @@ -0,0 +1,30 @@ +/* + Crate: ore + File: /serialize.rs + Module: ::serialize + Visibility: private + */ + +// TODO: documentation + +use chrono::{DateTime, TimeZone, UTC}; +use serde::{Deserialize, Deserializer, Serializer}; +use serde::de::Error as SerdeError; + +const DATE_TIME_FMT: &'static str = "%F %T%.3f"; + +// TODO: documentation +pub fn serialize_datetime(datetime: &DateTime, serializer: S) -> Result + where S: Serializer +{ + serializer.serialize_str(&format!("{}", datetime.format(DATE_TIME_FMT))) +} + +// TODO: documentation +pub fn deserialize_datetime<'a, D>(deserializer: D) -> Result, D::Error> + where D: Deserializer<'a> +{ + let de = String::deserialize(deserializer)?; + UTC.datetime_from_str(&de, DATE_TIME_FMT) + .map_err(SerdeError::custom) +} From 203eba62eecedb2cbedaa30dfa2c559ad95048e2 Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Sun, 14 May 2017 15:19:18 -0700 Subject: [PATCH 02/22] woops Signed-off-by: Hunar Roop Kahlon --- src/project/category_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project/category_impl.rs b/src/project/category_impl.rs index 6f7b1f1..3761da6 100644 --- a/src/project/category_impl.rs +++ b/src/project/category_impl.rs @@ -63,7 +63,7 @@ impl<'a> Visitor<'a> for CategoryVisitor { }); } } - category.ok_or(SerdeDeError::custom(r#"Invalid value "category""#)) + category.ok_or(SerdeError::custom(r#"Invalid value "category""#)) } } From 8ae9f570e276619304031cffeebf3daeaa31eac1 Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Mon, 22 May 2017 12:52:45 -0700 Subject: [PATCH 03/22] first steps on the projects complete Signed-off-by: Hunar Roop Kahlon --- src/project/category.rs | 135 +++++++++++++++++++++++++++++++++++ src/project/category_impl.rs | 86 ---------------------- src/project/channel.rs | 125 ++++++++++++++++++++++++++++++++ src/project/member.rs | 29 ++++++++ src/project/mod.rs | 86 ++++------------------ src/project/version.rs | 43 +++++++++++ 6 files changed, 346 insertions(+), 158 deletions(-) create mode 100644 src/project/category.rs delete mode 100644 src/project/category_impl.rs create mode 100644 src/project/channel.rs create mode 100644 src/project/member.rs create mode 100644 src/project/version.rs diff --git a/src/project/category.rs b/src/project/category.rs new file mode 100644 index 0000000..1935e67 --- /dev/null +++ b/src/project/category.rs @@ -0,0 +1,135 @@ +/* + Crate: ore + File: /project/category.rs + Module: ::project + Visibility: public + */ + +// TODO: documentation + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde::de::{Error as DeserializeError, MapAccess, Visitor}; +use std::fmt::{Display, Formatter, Result as FmtResult}; +use std::result::Result as StdResult; + +// TODO: documentation +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +pub enum Category { + AdminTools, + Chat, + DeveloperTools, + Economy, + Gameplay, + Games, + Protection, + RolePlaying, + WorldManagement, + Miscellaneous, + Undefined, +} + +impl Default for Category { + fn default() -> Self { + Category::Undefined + } +} + +#[doc(hidden)] +impl<'a> Deserialize<'a> for Category { + fn deserialize(deserializer: D) -> StdResult + where D: Deserializer<'a> + { + deserializer.deserialize_any(CategoryVisitor) + } +} + +impl Display for Category { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + write!(f, + "{}", + match *self { + Category::AdminTools => "Admin Tools", + Category::Chat => "Chat", + Category::DeveloperTools => "Developer Tools", + Category::Economy => "Economy", + Category::Gameplay => "Gameplay", + Category::Games => "Games", + Category::Protection => "Protection", + Category::RolePlaying => "Role Playing", + Category::WorldManagement => "World Management", + Category::Miscellaneous => "Miscellaneous", + Category::Undefined => "Undefined", + }) + } +} + +#[doc(hidden)] +impl Serialize for Category { + fn serialize(&self, serializer: S) -> StdResult + where S: Serializer + { + serializer.serialize_u64(*self as u64) + } +} + +struct CategoryVisitor; + +impl<'a> Visitor<'a> for CategoryVisitor { + type Value = Category; + + fn expecting(&self, f: &mut Formatter) -> FmtResult { + write!(f, + r#"an integer between 0 and 9 or an object with a string value "category""#) + } + + fn visit_map(self, mut map: A) -> StdResult + where A: MapAccess<'a> + { + let mut category = None; + + while let Ok(Some((key, value))) = map.next_entry::<&str, &str>() { + if key == "title" { + category = Some(match value { + "Admin Tools" => Category::AdminTools, + "Chat" => Category::Chat, + "Developer Tools" => Category::DeveloperTools, + "Economy" => Category::Economy, + "Gameplay" => Category::Gameplay, + "Games" => Category::Games, + "Protection" => Category::Protection, + "Role Playing" => Category::RolePlaying, + "World Management" => Category::WorldManagement, + "Miscellaneous" => Category::Miscellaneous, + _ => Category::Undefined, + }) + } + } + + category.ok_or(DeserializeError::custom(r#"invalid value "category""#)) + } + + fn visit_u8(self, v: u8) -> StdResult + where E: DeserializeError + { + Ok(match v { + 0 => Category::AdminTools, + 1 => Category::Chat, + 2 => Category::DeveloperTools, + 3 => Category::Economy, + 4 => Category::Gameplay, + 5 => Category::Games, + 6 => Category::Protection, + 7 => Category::RolePlaying, + 8 => Category::WorldManagement, + 9 => Category::Miscellaneous, + _ => Category::default(), + }) + } + + fn visit_u64(self, v: u64) -> StdResult + where E: DeserializeError + { + Self::visit_u8(self, v as u8) + } +} diff --git a/src/project/category_impl.rs b/src/project/category_impl.rs deleted file mode 100644 index 3761da6..0000000 --- a/src/project/category_impl.rs +++ /dev/null @@ -1,86 +0,0 @@ -/* - Crate: ore - File: /project/category_impl.rs - Module: ::project::category_impl - Visibility: private - */ - -// TODO: documentation - -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use serde::de::{Error as SerdeError, MapAccess, Visitor}; -use std::error::Error as StdError; -use std::fmt::{Formatter, Result as FmtResult}; -use super::{Category}; - -struct CategoryVisitor; - -impl<'a> Visitor<'a> for CategoryVisitor { - type Value = Category; - - fn expecting(&self, formatter: &mut Formatter) -> FmtResult { - write!(formatter, - r#"an integer between 0 and 10 or an object with a string value "category""#) - } - - fn visit_u8(self, value: u8) -> Result - where E: StdError - { - Ok(match value { - 0 => Category::AdminTools, - 1 => Category::Chat, - 2 => Category::DeveloperTools, - 3 => Category::Economy, - 4 => Category::Gameplay, - 5 => Category::Games, - 6 => Category::Protection, - 7 => Category::RolePlaying, - 8 => Category::WorldManagement, - 9 => Category::Miscellaneous, - _ => Category::Undefined, - }) - } - - fn visit_map(self, mut map: A) -> Result - where A: MapAccess<'a> - { - let mut category = None; - - while let Ok(Some((key, value))) = map.next_entry::() { - if key == "title" { - category = Some(match value.as_str() { - "Admin Tools" => Category::AdminTools, - "Chat" => Category::Chat, - "Developer Tools" => Category::DeveloperTools, - "Economy" => Category::Economy, - "Gameplay" => Category::Gameplay, - "Games" => Category::Games, - "Protection" => Category::Protection, - "Role Playing" => Category::RolePlaying, - "World Management" => Category::WorldManagement, - "Miscellaneous" => Category::Miscellaneous, - _ => Category::Undefined, - }); - } - } - category.ok_or(SerdeError::custom(r#"Invalid value "category""#)) - } -} - -#[doc(hidden)] -impl Serialize for Category { - fn serialize(&self, serializer: S) -> Result - where S: Serializer - { - serializer.serialize_u8(*self as u8) - } -} - -#[doc(hidden)] -impl<'a> Deserialize<'a> for Category { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'a> - { - deserializer.deserialize_any(CategoryVisitor) - } -} \ No newline at end of file diff --git a/src/project/channel.rs b/src/project/channel.rs new file mode 100644 index 0000000..f8f190b --- /dev/null +++ b/src/project/channel.rs @@ -0,0 +1,125 @@ +/* + Crate: ore + File: /project/category.rs + Module: ::project + Visibility: public + */ + +// TODO: documentation + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde::de::{Error as DeserializeError, Visitor}; +use std::fmt::{Display, Formatter, Result as FmtResult}; +use std::result::Result as StdResult; + +// TODO documentation +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Channel<'a> { + color: Color, + name: &'a str, +} + +// TODO documentation +#[derive(Clone, Copy, Debug)] +pub enum Color { + RGB(u8, u8, u8), + Transparent, +} + +#[doc(hidden)] +impl<'a> Deserialize<'a> for Color { + + fn deserialize(deserializer: D) -> StdResult + where D: Deserializer<'a> + { + deserializer.deserialize_str(ColorVisitor) + } +} + +impl Display for Color { + + fn fmt(&self, f: &mut Formatter) -> FmtResult { + match *self { + Color::Transparent => write!(f, "transparent"), + Color::RGB(ref r, ref g, ref b) => write!(f, "#{:x}{:x}{:x}", r, g, b), + } + } +} + +#[doc(hidden)] +impl Serialize for Color { + + fn serialize(&self, serializer: S) -> StdResult + where S: Serializer + { + serializer.serialize_str(format!("{}", match *self { + Color::RGB(ref r, ref g, ref b) => format!("#{:x}{:x}{:x}", r, g, b), + Color::Transparent => "transparent".to_string(), + }).as_str()) + } +} + +// TODO: documentation +struct ColorVisitor; + +impl<'a> Visitor<'a> for ColorVisitor { + type Value = Color; + + fn expecting(&self, f: &mut Formatter) -> FmtResult { + write!(f, "\"transparent\" or a color code like \"#xxxxxx\"") + } + + fn visit_str(self, c: &str) -> Result + where E: DeserializeError + { + match c { + "transparent" => Ok(Color::Transparent), + ref s => { + if s.len() != 7 { + Err(DeserializeError::custom("color code has to be 7 characters long")) + } else { + if !s.starts_with("#") { + return Err( + DeserializeError::custom("color code needs to start with a \"#\"")) + } + + let mut rgb: (u8, u8, u8) = (0, 0, 0); + let mut chars = s.chars(); + let mut buf = String::new(); + + buf.push(chars.nth(1).unwrap()); + buf.push(chars.nth(2).unwrap()); + + match buf.as_str().parse::() { + Ok(x) => rgb.0 = x, + Err(..) => return Err(DeserializeError::custom( + r#""red" component of the color code is incorrect"#)) + } + + buf.clear(); + buf.push(chars.nth(3).unwrap()); + buf.push(chars.nth(4).unwrap()); + + match buf.as_str().parse::() { + Ok(x) => rgb.1 = x, + Err(..) => return Err(DeserializeError::custom( + r#""green" component of the color code is incorrect"#)) + } + + buf.clear(); + buf.push(chars.nth(5).unwrap()); + buf.push(chars.nth(6).unwrap()); + + match buf.as_str().parse::() { + Ok(x) => rgb.2 = x, + Err(..) => return Err(DeserializeError::custom( + r#""blue" component of the color code is incorrect"#)) + } + + Ok(Color::RGB(rgb.0, rgb.1, rgb.2)) + } + } + } + } +} diff --git a/src/project/member.rs b/src/project/member.rs new file mode 100644 index 0000000..5112dcf --- /dev/null +++ b/src/project/member.rs @@ -0,0 +1,29 @@ +/* + Crate: ore + File: /project/member.rs + Module: ::project::member + Visibility: public + */ + +// TODO: documentation + +// TODO: documentation +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Member<'a> { + head_role: Role, + name: &'a str, + roles: Vec, + user_id: u32, +} + +// TODO: documentation +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[repr(u8)] +pub enum Role { + Admin, + Developer, + Editor, + Owner, + Support, +} diff --git a/src/project/mod.rs b/src/project/mod.rs index 633f1d6..70ce601 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -7,43 +7,27 @@ // TODO: documentation +pub mod category; +pub mod channel; +pub mod member; +pub mod version; + use chrono::{DateTime, UTC}; +use self::category::Category; +use self::channel::Channel; +use self::member::Member; +use self::version::Version; use serialize::{deserialize_datetime, serialize_datetime}; +use std::fmt::{Display, Formatter, Result as FmtResult}; +use std::result::Result as StdResult; -// TODO: documentation -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Channel<'a> { - color: &'a str, - name: &'a str, -} - -// TODO: documentation -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Dependency<'a> { - plugin_id: &'a str, - version: &'a str, -} - -// TODO: documentation -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Member<'a> { - head_role: Role, - name: &'a str, - roles: Vec, - user_id: u32, -} - -// TODO: documentation -#[derive(Clone, Debug, Deserialize, Serialize)] +// // TODO: documentation +#[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Project<'a> { category: Category, channels: Vec>, - #[serde(serialize_with = "serialize_datetime", deserialize_with = - "deserialize_datetime")] + #[serde(serialize_with = "serialize_datetime", deserialize_with = "deserialize_datetime")] created_at: DateTime, description: &'a str, downloads: u32, @@ -56,45 +40,3 @@ pub struct Project<'a> { stars: u32, views: u32, } - -// TODO: documentation -#[repr(u8)] -#[derive(Clone, Copy, Debug)] -pub enum Category { - AdminTools = 0, - Chat, - DeveloperTools, - Economy, - Gameplay, - Games, - Protection, - RolePlaying, - WorldManagement, - Miscellaneous, - Undefined, -} - -// TODO: documentation -#[repr(u8)] -#[derive(Clone, Debug, Deserialize, Serialize)] -pub enum Role { - Admin, - Developer, - Editor, - Owner, - Support, -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Version<'a> { - channel: Channel<'a>, - #[serde(serialize_with = "serialize_datetime", deserialize_with = "deserialize_datetime")] - created_at: DateTime, - file_size: u32, - dependencies: Vec>, - name: &'a str, - staff_approved: bool, -} - -mod category_impl; diff --git a/src/project/version.rs b/src/project/version.rs new file mode 100644 index 0000000..e816199 --- /dev/null +++ b/src/project/version.rs @@ -0,0 +1,43 @@ +/* + Crate: ore + File: /project/version.rs + Module: ::project::version + Visibility: public + */ + +// TODO: documentation + +use chrono::{DateTime, UTC}; +use project::channel::Channel; +use serialize::{deserialize_datetime, serialize_datetime}; +use std::fmt::{Display, Formatter, Result as FmtResult}; + +// TODO: documentation +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Version<'a> { + channel: Channel<'a>, + #[serde(serialize_with = "serialize_datetime", deserialize_with = "deserialize_datetime")] + created_at: DateTime, + dependencies: Vec>, + file_size: u32, + id: u32, + name: &'a str, + plugin_id: &'a str, + staff_approved: bool, +} + +// TODO: documentation +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Dependency<'a> { + plugin_id: &'a str, + version: &'a str, +} + +impl<'a> Display for Dependency<'a> { + + fn fmt(&self, f: &mut Formatter) -> FmtResult { + write!(f, "{}@{}", self.plugin_id, self.version) + } +} From 58bd54de676e30abfeca1ddc9f31c0bdc60ff2cd Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Mon, 22 May 2017 13:36:58 -0700 Subject: [PATCH 04/22] lets try fixing cargo registry Signed-off-by: Hunar Roop Kahlon --- Cargo.toml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 06ab8f6..65d4b6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,10 @@ [dependencies] -chrono = "0.3.1" -hyper = "0.10.9" -hyper-rustls = "0.3.3" -serde = "1.0.2" -serde_derive = "1.0.2" -serde_json = "1.0.1" - -[dependencies.derive_builder] -features = ["private_fields"] -version = "0.4.7" +chrono = "0.3" +hyper = "0.10" +hyper-rustls = "0.3" +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" [package] authors = [ From dcb826843ad104b14f47c79842eca1a6bd0ac71f Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Mon, 22 May 2017 13:49:28 -0700 Subject: [PATCH 05/22] fix the webpki error + remove the derive_builder errors Signed-off-by: Hunar Roop Kahlon --- Cargo.toml | 1 + src/lib.rs | 2 - src/query/error_impl.rs | 78 ------------------------------ src/query/mod.rs | 80 ------------------------------- src/query/plugins_query_impl.rs | 85 --------------------------------- 5 files changed, 1 insertion(+), 245 deletions(-) delete mode 100644 src/query/error_impl.rs delete mode 100644 src/query/plugins_query_impl.rs diff --git a/Cargo.toml b/Cargo.toml index 65d4b6c..5d0a67e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ chrono = "0.3" hyper = "0.10" hyper-rustls = "0.3" +webpki = "0.12.0" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" diff --git a/src/lib.rs b/src/lib.rs index 793250c..5a6182f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,6 @@ */ extern crate chrono; -#[macro_use] -extern crate derive_builder; extern crate hyper; extern crate hyper_rustls; extern crate serde; diff --git a/src/query/error_impl.rs b/src/query/error_impl.rs deleted file mode 100644 index b3ec123..0000000 --- a/src/query/error_impl.rs +++ /dev/null @@ -1,78 +0,0 @@ -/* - Crate: ore - File: /query/error_impl.rs - Module: ::query::error_impl - Visibility: private - */ - -// TODO: documentation - -use hyper::Error as HttpError; -use hyper::error::ParseError as UriParseError; -use serde_json::Error as JsonError; -use std::error::Error as StdError; -use std::fmt::{Formatter, Display, Result as FmtResult}; -use std::io::Error as IoError; -use super::Error; - -// TODO: documentation -#[inline] -pub fn error_cause(error: &Error) -> Option<&StdError> { - match *error { - Error::Http(ref why) => Some(why), - Error::Io(ref why) => Some(why), - Error::Json(ref why) => Some(why), - _ => None, - } -} - -// TODO: documentation -#[inline] -pub fn error_description(error: &Error) -> &str { - match *error { - Error::Http(ref why) => why.description(), - Error::InvalidId(ref why) => "Invalid project id", - Error::Io(ref why) => why.description(), - Error::Json(ref why) => why.description(), - } -} - - -// TODO: documentation -#[inline] -pub fn fmt_display(error: &Error, f: &mut Formatter) -> FmtResult { - match *error { - Error::Http(ref why) => Display::fmt(why, f), - Error::Io(ref why) => Display::fmt(why, f), - Error::InvalidId(ref why) => write!(f, "Invalid plugin id '{id}'", id = why.as_str()), - Error::Json(ref why) => Display::fmt(why, f), - } -} - -#[doc(hidden)] -impl From for Error { - fn from(error: HttpError) -> Self { - Error::Http(error) - } -} - -#[doc(hidden)] -impl From for Error { - fn from(error: IoError) -> Self { - Error::Io(error) - } -} - -#[doc(hidden)] -impl From for Error { - fn from(error: JsonError) -> Self { - Error::Json(error) - } -} - -#[doc(hidden)] -impl From for Error { - fn from(error: UriParseError) -> Self { - Error::Http(HttpError::from(error)) - } -} diff --git a/src/query/mod.rs b/src/query/mod.rs index f6cbd4a..58f557d 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -36,83 +36,3 @@ pub enum Error { Io(IoError), Json(SerdeError), } - -// TODO -#[derive(Builder, Clone, Debug, Default)] -#[builder(derive(Debug))] -// TODO: Rename to ProjectsQuery -pub struct PluginsQuery<'a> { - categories: Option>, - limit: Option, - offset: Option, - query: Option<&'a str>, - sort: Option, -} - -// TODO: documentation -pub fn plugins_matching(query: &str) -> PluginsQueryBuilder { - PluginsQueryBuilder::default() - .query(Some(query)) - .to_owned() -} - -impl StdError for Error { - fn cause(&self) -> Option<&StdError> { - error_impl::error_cause(self) - } - - fn description(&self) -> &str { - error_impl::error_description(self) - } -} - -impl Display for Error { - fn fmt(&self, f: &mut Formatter) -> FmtResult { - error_impl::fmt_display(self, f) - } -} - -impl<'a> PluginsQuery<'a> { - // TODO: documentation - pub fn categories(&self) -> Option> { - self.categories.to_owned() - } - - // TODO: documentation - pub fn limit(&self) -> Option { - self.limit - } - - // TODO: documentation - pub fn offset(&self) -> Option { - self.offset - } - - // TODO: documentation - pub fn query(&self) -> Option<&'a str> { - self.query - } - - // TODO: documentation - pub fn sort(&self) -> Option { - self.sort - } -} - -impl<'a> Query<'a> for PluginsQuery<'a> { - type Ret = Vec; - fn query(&self, url: &'a str) -> Result { - plugins_query_impl::plugins_query(self, url) - } -} - -impl<'a, 'b> From> for PluginsQueryBuilder<'b> - where 'a: 'b -{ - fn from(plugins_query: PluginsQuery<'a>) -> Self { - plugins_query_impl::from_builder(plugins_query) - } -} - -mod error_impl; -mod plugins_query_impl; diff --git a/src/query/plugins_query_impl.rs b/src/query/plugins_query_impl.rs deleted file mode 100644 index 7acb74a..0000000 --- a/src/query/plugins_query_impl.rs +++ /dev/null @@ -1,85 +0,0 @@ -/* - Crate: ore - File: /query/impls.rs - Module: ::query::impls - Visibility: private - */ - -// TODO: documentation - -use types::Plugin; -use hyper_rustls::TlsClient; -use hyper::{Client, Url}; -use hyper::net::HttpsConnector; -use serde_json; -use std::io::Read; -use super::{Error, PluginsQuery, PluginsQueryBuilder}; - -const PROJECTS: &'static str = "/projects"; - -// TODO: documentation -#[inline] -pub fn from_builder<'a, 'b>(plugins_query: PluginsQuery<'a>) -> PluginsQueryBuilder<'b> - where 'a: 'b -{ - let mut tmp = PluginsQueryBuilder::default(); - &mut tmp.categories(plugins_query.categories()); - &mut tmp.limit(plugins_query.limit()); - &mut tmp.offset(plugins_query.offset()); - &mut tmp.query(plugins_query.query()); - &mut tmp.sort(plugins_query.sort()); - tmp -} - -// TODO: documentation -#[inline] -pub fn plugins_query(plugin_query: &PluginsQuery, url: &str) -> Result, Error> { - let mut req_url: Url; - - { - let mut base_url = url.to_string(); - base_url.push_str(PROJECTS); - - req_url = Url::parse(&base_url)?; - } - - { - let mut query_pairs = req_url.query_pairs_mut(); - - if let Some(ref categories) = plugin_query.categories { - query_pairs.append_pair("categories", - categories - .into_iter() - .map(|c| *c as u8) - .fold(String::new(), |acc, next| { - acc + "," + next.to_string().as_str() - }) - .as_str()); - } - - if let Some(ref limit) = plugin_query.limit { - query_pairs.append_pair("limit", (*limit).to_string().as_str()); - } - - if let Some(ref offset) = plugin_query.offset { - query_pairs.append_pair("offset", offset.to_string().as_str()); - } - - if let Some(ref query) = plugin_query.query { - query_pairs.append_pair("q", query); - } - - if let Some(ref sort) = plugin_query.sort { - query_pairs.append_pair("sort", (*sort as u8).to_string().as_str()); - } - } - - let mut res = String::new(); - - { - let client = Client::with_connector(HttpsConnector::new(TlsClient::new())); - client.get(req_url).send()?.read_to_string(&mut res)?; - } - - Ok(serde_json::from_str::>(res.as_str())?) -} From b854684cffc717d8679a5359d4f31db89e0faa94 Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Mon, 22 May 2017 14:11:31 -0700 Subject: [PATCH 06/22] its working locally... Signed-off-by: Hunar Roop Kahlon --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5d0a67e..866997f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ chrono = "0.3" hyper = "0.10" hyper-rustls = "0.3" -webpki = "0.12.0" +webpki = "0.12" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" From ea79e1e32e08dca2f7c253b6702ddf8fafc64459 Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Mon, 22 May 2017 14:16:32 -0700 Subject: [PATCH 07/22] ok this is getting annoying now Signed-off-by: Hunar Roop Kahlon --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 866997f..a87004b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ chrono = "0.3" hyper = "0.10" hyper-rustls = "0.3" -webpki = "0.12" +webpki-roots = "0.10" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" From 22dcd5e2927d66a22fbe1ef278958f2446924639 Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Mon, 22 May 2017 14:53:15 -0700 Subject: [PATCH 08/22] ok finally working, hyper-rustls was outdated Signed-off-by: Hunar Roop Kahlon --- Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a87004b..c56af05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,9 @@ [dependencies] chrono = "0.3" hyper = "0.10" -hyper-rustls = "0.3" -webpki-roots = "0.10" +hyper-rustls = "0.6" +# webpki = "0.12.1" +# webpki-roots = "0.10.0" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" From 83defeaa5ea10cc37587bc2c2c51d6a2c964dcaf Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Mon, 22 May 2017 14:56:05 -0700 Subject: [PATCH 09/22] no need for these anymore Signed-off-by: Hunar Roop Kahlon --- Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c56af05..4db2e13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,8 +2,6 @@ chrono = "0.3" hyper = "0.10" hyper-rustls = "0.6" -# webpki = "0.12.1" -# webpki-roots = "0.10.0" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" From 85c52139c9e24047f9b1a8dd9f40ba3f6a1fadda Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Wed, 24 May 2017 18:36:22 -0700 Subject: [PATCH 10/22] provide getters and do some housekeeping Signed-off-by: Hunar Roop Kahlon --- src/api.rs | 277 ----------------------------------------- src/lib.rs | 5 - src/project/channel.rs | 55 ++++++++ src/project/member.rs | 40 +++++- src/project/mod.rs | 71 ++++++++++- src/project/version.rs | 58 +++++++++ src/query/mod.rs | 1 - src/serialize.rs | 2 +- src/types.rs | 152 +--------------------- 9 files changed, 223 insertions(+), 438 deletions(-) delete mode 100644 src/api.rs diff --git a/src/api.rs b/src/api.rs deleted file mode 100644 index a9579dc..0000000 --- a/src/api.rs +++ /dev/null @@ -1,277 +0,0 @@ -use hyper::{Client, Url}; -use hyper::error::Error as HyperError; -use hyper::net::HttpsConnector; -use hyper_rustls::TlsClient; -use serde_json::Error as SerdeError; -use std::error::Error as StdError; -use std::fmt::{Formatter, Result as FmtResult, Display}; -use chrono::ParseError; -use std::io::{Read, Error as IoError}; -use super::*; - -#[derive(Clone, Debug)] -pub struct PluginSearchQuery<'a> { - categories: Option>, - sort: Option, - query: &'a str, - limit: Option, - offset: Option, -} - -impl<'a> PluginSearchQuery<'a> { - pub fn categories(&mut self, categories: &Vec) -> &mut Self { - self.categories = Some(categories.clone()); - self - } - pub fn sort_type(&mut self, sort_type: SortType) -> &mut Self { - self.sort = Some(sort_type); - self - } - pub fn limit(&mut self, limit: u32) -> &mut Self { - self.limit = Some(limit); - self - } - pub fn offset(&mut self, offset: u32) -> &mut Self { - self.offset = Some(offset); - self - } - pub fn exec(&self) -> Result, Error> { - let client = Client::with_connector(HttpsConnector::new(TlsClient::new())); - let mut url = Url::parse("https://ore.spongepowered.org/api/projects").unwrap(); - { - let mut pairs = url.query_pairs_mut(); - if let Some(ref categories) = self.categories { - pairs.append_pair("categories", - categories - .into_iter() - .map(|x| *x as u8) - .fold(String::new(), - |x, y| x + "," + y.to_string().as_str()) - .as_str()); - } - if let Some(ref sort) = self.sort { - pairs.append_pair("sort", (*sort as u8).to_string().as_str()); - } - if let Some(ref limit) = self.limit { - pairs.append_pair("limit", limit.to_string().as_str()); - } - if let Some(ref offset) = self.offset { - pairs.append_pair("offset", offset.to_string().as_str()); - } - pairs.append_pair("q", self.query); - } - let mut res = String::new(); - client.get(url).send()?.read_to_string(&mut res)?; - Ok(serde_json::from_str::>(&res)?) - } -} - -pub fn search_plugins(query: &str) -> PluginSearchQuery { - PluginSearchQuery { - categories: None, - sort: None, - query: query, - limit: None, - offset: None, - } -} - -pub fn get_plugin(id: &str) -> Result { - let client = Client::with_connector(HttpsConnector::new(TlsClient::new())); - let url = Url::parse("https://ore.spongepowered.org/api/projects/") - .unwrap() - .join(id) - .map_err(|_| Error::IncorrectIdError)?; - let mut res = String::new(); - println!("{}", url.to_string()); - client.get(url).send()?.read_to_string(&mut res)?; - println!("{}", res); - Ok(serde_json::from_str::(&res)?) -} - -pub fn search_versions(id: &str) -> VersionSearchQuery { - VersionSearchQuery { - channels: None, - limit: 10, - offset: None, - id: id, - } -} - -#[derive(Clone, Debug)] -pub struct VersionSearchQuery<'a> { - channels: Option>, - limit: u32, - offset: Option, - id: &'a str, -} - -impl<'a> VersionSearchQuery<'a> { - pub fn channels(&mut self, channels: Vec<&'a str>) -> &mut Self { - self.channels = Some(channels); - self - } - pub fn limit(&mut self, limit: u32) -> &mut Self { - self.limit = limit; - self - } - pub fn offset(&mut self, offset: u32) -> &mut Self { - self.offset = Some(offset); - self - } - pub fn exec(&self) -> Result, Error> { - let client = Client::with_connector(HttpsConnector::new(TlsClient::new())); - let mut url = Url::parse("https://ore.spongepowered.org/api/projects/") - .unwrap() - .join((self.id.to_owned() + "/").as_str()) - .map_err(|_| Error::IncorrectIdError)? - .join("versions") - .unwrap(); - { - let mut pairs = url.query_pairs_mut(); - if let Some(ref channels) = self.channels { - pairs.append_pair("channels", - channels - .into_iter() - .fold(String::new(), |x, y| x + "," + y) - .as_str()); - } - pairs.append_pair("limit", self.limit.to_string().as_str()); - if let Some(offset) = self.offset { - pairs.append_pair("offset", offset.to_string().as_str()); - } - } - let mut res = String::new(); - client.get(url).send()?.read_to_string(&mut res)?; - Ok(serde_json::from_str::>(&res)?) - } -} - -pub fn get_version(id: &str, version: &str) -> Result { - let client = Client::with_connector(HttpsConnector::new(TlsClient::new())); - let url = Url::parse("https://ore.spongepowered.org/api/projects/") - .unwrap() - .join((id.to_owned() + "/").as_str()) - .map_err(|_| Error::IncorrectIdError)? - .join("versions/") - .unwrap() - .join((version.to_owned() + "/").as_str()) - .map_err(|_| Error::IncorrectVersionError)?; - let mut res = String::new(); - client.get(url).send()?.read_to_string(&mut res)?; - Ok(serde_json::from_str::(&res)?) -} - -pub fn get_users() -> UserQuery { - UserQuery { - limit: None, - offset: None, - } -} - -#[derive(Debug, Clone)] -pub struct UserQuery { - limit: Option, - offset: Option, -} - -impl UserQuery { - pub fn limit(&mut self, limit: u32) -> &mut Self { - self.limit = Some(limit); - self - } - pub fn offset(&mut self, offset: u32) -> &mut Self { - self.offset = Some(offset); - self - } - pub fn exec(&self) -> Result, Error> { - let client = Client::with_connector(HttpsConnector::new(TlsClient::new())); - let mut url = Url::parse("https://ore.spongepowered.org/api/users").unwrap(); - { - let mut pairs = url.query_pairs_mut(); - if let Some(ref limit) = self.limit { - pairs.append_pair("limit", limit.to_string().as_str()); - } - if let Some(ref offset) = self.offset { - pairs.append_pair("offset", offset.to_string().as_str()); - } - } - let mut res = String::new(); - client.get(url).send()?.read_to_string(&mut res)?; - Ok(serde_json::from_str::>(&res)?) - } -} - -pub fn get_user(name: &str) -> Result { - unimplemented!() -} - -#[derive(Debug)] -pub enum Error { - IoError(IoError), - NetError(HyperError), - ParseError(SerdeError), - DateError(ParseError), - IncorrectIdError, - IncorrectVersionError, -} - -impl StdError for Error { - fn description(&self) -> &str { - match *self { - Error::IoError(ref err) => err.description(), - Error::ParseError(ref err) => err.description(), - Error::NetError(ref err) => err.description(), - Error::DateError(ref err) => err.description(), - Error::IncorrectIdError => "Incorrect plugin ID format", - Error::IncorrectVersionError => "Incorrect version format", - } - } - fn cause(&self) -> Option<&StdError> { - match *self { - Error::IoError(ref err) => Some(err), - Error::ParseError(ref err) => Some(err), - Error::NetError(ref err) => Some(err), - Error::DateError(ref err) => Some(err), - Error::IncorrectIdError => None, - Error::IncorrectVersionError => None, - } - } -} - -impl From for Error { - fn from(err: SerdeError) -> Self { - Error::ParseError(err) - } -} - -impl From for Error { - fn from(err: HyperError) -> Self { - Error::NetError(err) - } -} - -impl From for Error { - fn from(err: IoError) -> Self { - Error::IoError(err) - } -} - -impl From for Error { - fn from(err: ParseError) -> Self { - Error::DateError(err) - } -} - -impl Display for Error { - fn fmt(&self, f: &mut Formatter) -> FmtResult { - match *self { - Error::IoError(ref err) => err.fmt(f), - Error::ParseError(ref err) => err.fmt(f), - Error::NetError(ref err) => err.fmt(f), - Error::DateError(ref err) => err.fmt(f), - Error::IncorrectIdError => write!(f, "Incorrect plugin ID format."), - Error::IncorrectVersionError => write!(f, "Incorrect version format."), - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 5a6182f..a4666b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,9 +18,4 @@ pub mod query; mod serialize; -mod api; mod types; - -pub use types::{Plugin, PluginCategory, SortType, ShortUser, Channel, Version, Dependency, User}; -pub use api::{UserQuery, Error, PluginSearchQuery, VersionSearchQuery}; -pub use api::{search_plugins, search_versions, get_plugin, get_users, get_user, get_version}; diff --git a/src/project/channel.rs b/src/project/channel.rs index f8f190b..c429433 100644 --- a/src/project/channel.rs +++ b/src/project/channel.rs @@ -20,6 +20,26 @@ pub struct Channel<'a> { name: &'a str, } +impl<'a> Channel<'a> { + + // TODO: documentation + pub fn color(&self) -> Color { + self.color + } + + // TODO: documentation + pub fn name(&self) -> &str { + self.name + } +} + +impl<'a> Display for Channel<'a> { + + fn fmt(&self, f: &mut Formatter) -> FmtResult { + write!(f, "{}", self.name) + } +} + // TODO documentation #[derive(Clone, Copy, Debug)] pub enum Color { @@ -27,6 +47,41 @@ pub enum Color { Transparent, } +impl Color { + + // TODO: documentation + pub fn red(&self) -> Option { + match *self { + Color::RGB(r, ..) => Some(r), + Color::Transparent => None, + } + } + + // TODO: documentation + pub fn green(&self) -> Option { + match *self { + Color::RGB(_, g, ..) => Some(g), + Color::Transparent => None, + } + } + + // TODO: documentation + pub fn blue(&self) -> Option { + match *self { + Color::RGB(_, _, b) => Some(b), + Color::Transparent => None, + } + } + + // TODO: documentation + pub fn rbg(&self) -> Option<(u8, u8, u8)> { + match *self { + Color::RGB(r, g, b) => Some((r, g, b)), + Color::Transparent => None, + } + } +} + #[doc(hidden)] impl<'a> Deserialize<'a> for Color { diff --git a/src/project/member.rs b/src/project/member.rs index 5112dcf..061144c 100644 --- a/src/project/member.rs +++ b/src/project/member.rs @@ -7,6 +7,8 @@ // TODO: documentation +use std::fmt::{Display, Formatter, Result as FmtResult}; + // TODO: documentation #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] @@ -17,13 +19,49 @@ pub struct Member<'a> { user_id: u32, } +impl<'a> Member<'a> { + + // TODO: documentation + pub fn head_role(&self) -> Role { + self.head_role + } + + // TODO: documentation + pub fn name(&self) -> &str { + self.name + } + + // TODO: documentation + pub fn roles(&self) -> Vec { + self.roles.to_vec() + } + + // TODO: documentation + pub fn user_id(&self) -> u32 { + self.user_id + } +} + // TODO: documentation #[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[repr(u8)] pub enum Role { + Owner, Admin, Developer, Editor, - Owner, Support, } + +impl Display for Role { + + fn fmt(&self, f: &mut Formatter) -> FmtResult { + write!(f, "{}", match *self { + Role::Admin => "Admin", + Role::Developer => "Developer", + Role::Editor => "Editor", + Role::Owner => "Owner", + Role::Support => "Support", + }) + } +} diff --git a/src/project/mod.rs b/src/project/mod.rs index 70ce601..8fc2aab 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -18,8 +18,6 @@ use self::channel::Channel; use self::member::Member; use self::version::Version; use serialize::{deserialize_datetime, serialize_datetime}; -use std::fmt::{Display, Formatter, Result as FmtResult}; -use std::result::Result as StdResult; // // TODO: documentation #[derive(Clone, Debug, Serialize, Deserialize)] @@ -40,3 +38,72 @@ pub struct Project<'a> { stars: u32, views: u32, } + +impl<'a> Project<'a> { + + // TODO: documentation + pub fn category(&self) -> Category { + self.category + } + + // TODO: documentation + pub fn channels(&self) -> Vec { + self.channels.to_vec() + } + + // TODO: documentation + pub fn created_at(&self) -> String { + use serialize::DATE_TIME_FMT; + format!("{}", self.created_at.format(DATE_TIME_FMT)) + } + + // TODO: documentation + pub fn description(&self) -> &str { + self.description + } + + // TODO: documentation + pub fn downloads(&self) -> u32 { + self.downloads + } + + // TODO: documentation + pub fn href(&self) -> &str { + self.href + } + + // TODO: documentation + pub fn members(&self) -> Vec { + self.members.to_vec() + } + + // TODO: documentation + pub fn name(&self) -> &str { + self.name + } + + // TODO: documentation + pub fn owner(&self) -> &str { + self.owner + } + + // TODO: documentation + pub fn plugin_id(&self) -> &str { + self.plugin_id + } + + // TODO: documentation + pub fn recommended(&self) -> Version { + self.recommended.to_owned() + } + + // TODO: documentation + pub fn stars(&self) -> u32 { + self.stars + } + + // TODO: documentation + pub fn views(&self) -> u32 { + self.views + } +} diff --git a/src/project/version.rs b/src/project/version.rs index e816199..0f87afa 100644 --- a/src/project/version.rs +++ b/src/project/version.rs @@ -27,6 +27,51 @@ pub struct Version<'a> { staff_approved: bool, } +impl<'a> Version<'a> { + + // TODO: documentation + pub fn channel(&self) -> Channel + { + self.channel.to_owned() + } + + // TODO: documentation + pub fn created_at(&self) -> String { + use serialize::DATE_TIME_FMT; + format!("{}", self.created_at.format(DATE_TIME_FMT)) + } + + // TODO: documentation + pub fn dependencies(&self) -> Vec { + self.dependencies.to_vec() + } + + // TODO: documentation + pub fn file_size(&self) -> u32 { + self.file_size + } + + // TODO: documentation + pub fn id(&self) -> u32 { + self.id + } + + // TODO: documentation + pub fn name(&self) -> &str { + self.name + } + + // TODO: documentation + pub fn plugin_id(&self) -> &str { + self.plugin_id + } + + // TODO: documentation + pub fn staff_approved(&self) -> bool { + self.staff_approved + } +} + // TODO: documentation #[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] @@ -35,6 +80,19 @@ pub struct Dependency<'a> { version: &'a str, } +impl<'a> Dependency<'a> { + + // TODO: documentation + pub fn plugin_name(&self) -> &str { + self.plugin_id + } + + // TODO: documentation + pub fn version(&self) -> &str { + self.version + } +} + impl<'a> Display for Dependency<'a> { fn fmt(&self, f: &mut Formatter) -> FmtResult { diff --git a/src/query/mod.rs b/src/query/mod.rs index 58f557d..6ca67c4 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -7,7 +7,6 @@ // TODO: documentation -use types::{Plugin, PluginCategory, SortType}; use hyper::Error as HttpError; use serde_json::Error as SerdeError; use std::error::Error as StdError; diff --git a/src/serialize.rs b/src/serialize.rs index b34acaa..94ca0d2 100644 --- a/src/serialize.rs +++ b/src/serialize.rs @@ -11,7 +11,7 @@ use chrono::{DateTime, TimeZone, UTC}; use serde::{Deserialize, Deserializer, Serializer}; use serde::de::Error as SerdeError; -const DATE_TIME_FMT: &'static str = "%F %T%.3f"; +pub const DATE_TIME_FMT: &'static str = "%F %T%.3f"; // TODO: documentation pub fn serialize_datetime(datetime: &DateTime, serializer: S) -> Result diff --git a/src/types.rs b/src/types.rs index de60420..03aa0d6 100644 --- a/src/types.rs +++ b/src/types.rs @@ -3,90 +3,6 @@ use serde::ser::{Serializer, Serialize}; use std::fmt::{Formatter, Result as FmtResult}; use std::error::Error; use chrono::{DateTime, UTC, TimeZone}; -#[repr(u8)] -#[derive(Clone, Copy, Debug)] -pub enum PluginCategory { - AdminTools = 0, - Chat = 1, - DeveloperTools = 2, - Economy = 3, - Gameplay = 4, - Games = 5, - Protection = 6, - RolePlaying = 7, - WorldManagement = 8, - Miscellaneous = 9, - Undefined, -} - -struct PluginCategoryVisitor; - -impl<'a> Visitor<'a> for PluginCategoryVisitor { - type Value = PluginCategory; - fn expecting(&self, formatter: &mut Formatter) -> FmtResult { - write!(formatter, - r#"an integer between 0 and 9 or an object with a string value "category""#) - } - - fn visit_u8(self, v: u8) -> Result - where E: Error - { - let res = match v { - 0 => PluginCategory::AdminTools, - 1 => PluginCategory::Chat, - 2 => PluginCategory::DeveloperTools, - 3 => PluginCategory::Economy, - 4 => PluginCategory::Gameplay, - 5 => PluginCategory::Games, - 6 => PluginCategory::Protection, - 7 => PluginCategory::RolePlaying, - 8 => PluginCategory::WorldManagement, - 9 => PluginCategory::Miscellaneous, - _ => PluginCategory::Undefined, - }; - Ok(res) - } - fn visit_map(self, mut map: A) -> Result - where A: MapAccess<'a> - { - let mut category: Option = None; - while let Ok(Some((key, value))) = map.next_entry::() { - if key == "title" { - category = Some(match value.as_str() { - "Admin Tools" => PluginCategory::AdminTools, - "Chat" => PluginCategory::Chat, - "Developer Tools" => PluginCategory::DeveloperTools, - "Economy" => PluginCategory::Economy, - "Gameplay" => PluginCategory::Gameplay, - "Games" => PluginCategory::Games, - "Protection" => PluginCategory::Protection, - "Role Playing" => PluginCategory::RolePlaying, - "World Management" => PluginCategory::WorldManagement, - "Miscellaneous" => PluginCategory::Miscellaneous, - _ => PluginCategory::Undefined, - }); - - } - } - category.ok_or(SerdeError::custom(r#"Invalid value "category""#)) - } -} - -impl Serialize for PluginCategory { - fn serialize(&self, serializer: S) -> Result - where S: Serializer - { - serializer.serialize_u8(*self as u8) - } -} - -impl<'a> Deserialize<'a> for PluginCategory { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'a> - { - deserializer.deserialize_any(PluginCategoryVisitor) - } -} #[repr(u8)] #[derive(Debug, Copy, Clone)] @@ -137,72 +53,6 @@ impl<'a> Deserialize<'a> for SortType { } } -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Plugin { - pub plugin_id: String, - #[serde(serialize_with = "serialize_datetime", deserialize_with = "deserialize_datetime")] - pub created_at: DateTime, - pub name: String, - pub owner: String, - pub description: String, - pub href: String, - pub members: Vec, - pub channels: Vec, - pub recommended: Version, - pub category: PluginCategory, - pub views: u32, - pub downloads: u32, - pub stars: u32, - #[serde(skip_serializing, skip_deserializing)] - lock: (), -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ShortUser { - pub user_id: u32, - pub name: String, - pub roles: Vec, - pub head_role: String, - #[serde(skip_serializing, skip_deserializing)] - lock: (), -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Channel { - pub name: String, - pub color: String, - #[serde(skip_serializing, skip_deserializing)] - lock: (), -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Version { - pub id: u32, - #[serde(serialize_with = "serialize_datetime", deserialize_with = "deserialize_datetime")] - pub created_at: DateTime, - pub name: String, - pub dependencies: Vec, - pub plugin_id: String, - pub channel: Channel, - pub file_size: u32, - pub staff_approved: bool, - #[serde(skip_serializing, skip_deserializing)] - lock: (), -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Dependency { - pub plugin_id: String, - pub version: String, - #[serde(skip_serializing, skip_deserializing)] - lock: (), -} - #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct User { @@ -214,7 +64,7 @@ pub struct User { pub starred: Vec, pub avatar_template: String, pub avatar_url: String, - pub projects: Vec, + // pub projects: Vec, #[serde(skip_serializing, skip_deserializing)] lock: (), } From 98b072a941f703cd2866ecc780e883e936b304cf Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Wed, 24 May 2017 19:10:36 -0700 Subject: [PATCH 11/22] fix module path comments Signed-off-by: Hunar Roop Kahlon --- src/project/category.rs | 2 +- src/project/channel.rs | 2 +- src/project/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/project/category.rs b/src/project/category.rs index 1935e67..dc60c8d 100644 --- a/src/project/category.rs +++ b/src/project/category.rs @@ -1,7 +1,7 @@ /* Crate: ore File: /project/category.rs - Module: ::project + Module: ::project::category Visibility: public */ diff --git a/src/project/channel.rs b/src/project/channel.rs index c429433..15a7c11 100644 --- a/src/project/channel.rs +++ b/src/project/channel.rs @@ -1,7 +1,7 @@ /* Crate: ore File: /project/category.rs - Module: ::project + Module: ::project::category Visibility: public */ diff --git a/src/project/mod.rs b/src/project/mod.rs index 8fc2aab..451c0e4 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -2,7 +2,7 @@ Crate: ore File: /project/mod.rs Module: ::project - Visibility: private + Visibility: public */ // TODO: documentation From 082af3d4f4bee8b51c65901ae540c68b963d298e Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Thu, 25 May 2017 09:20:13 -0700 Subject: [PATCH 12/22] query (re)fixed Signed-off-by: Hunar Roop Kahlon --- src/query.rs | 99 ++++++++++++++++++++++++++++++++++++++++++++++++ src/query/mod.rs | 37 ------------------ 2 files changed, 99 insertions(+), 37 deletions(-) create mode 100644 src/query.rs delete mode 100644 src/query/mod.rs diff --git a/src/query.rs b/src/query.rs new file mode 100644 index 0000000..2c73d9e --- /dev/null +++ b/src/query.rs @@ -0,0 +1,99 @@ +/* + Crate: ore + File: /query.rs + Module: ::query + Visibility: public + */ + +// TODO: documentation + +use hyper::Error as HttpError; +use hyper::error::ParseError as UriParseError; +use serde_json::Error as SerdeError; +use std::error::Error as StdError; +use std::fmt::{Display, Formatter, Result as FmtResult}; +use std::io::Error as IoError; +use std::result::Result as StdResult; + +pub type Result = StdResult; + +// TODO: documentation +pub trait Query<'a> { + // TODO: documentation + /// The return type. + type Ret; + + // TODO: documentation + /// Initiate a query. + fn query(&self, url: &'a str) -> Result; +} + +// TODO: documentation +#[derive(Debug)] +pub enum Error { + Http(HttpError), + InvalidId(String), + Io(IoError), + Json(SerdeError), +} + +impl Display for Error { + + fn fmt(&self, f: &mut Formatter) -> FmtResult { + match *self { + Error::Http(ref why) => why.fmt(f), + Error::InvalidId(ref why) => write!(f, "invalid project id {}", why), + Error::Io(ref why) => why.fmt(f), + Error::Json(ref why) => why.fmt(f), + } + } +} + +impl From for Error { + + fn from(err: HttpError) -> Self { + Error::Http(err) + } +} + +impl From for Error { + + fn from(err: UriParseError) -> Self { + Error::Http(HttpError::Uri(err)) + } +} + +impl From for Error { + + fn from(err: IoError) -> Self { + Error::Io(err) + } +} + +impl From for Error { + + fn from(err: SerdeError) -> Self { + Error::Json(err) + } +} + +impl StdError for Error { + + fn description(&self) -> &str { + match *self { + Error::Http(ref why) => why.description(), + Error::InvalidId(..) => "Invalid project id found", + Error::Io(ref why) => why.description(), + Error::Json(ref why) => why.description() + } + } + + fn cause(&self) -> Option<&StdError> { + match *self { + Error::Http(ref why) => Some(why), + Error::Io(ref why) => Some(why), + Error::Json(ref why) => Some(why), + _ => None, + } + } +} diff --git a/src/query/mod.rs b/src/query/mod.rs deleted file mode 100644 index 6ca67c4..0000000 --- a/src/query/mod.rs +++ /dev/null @@ -1,37 +0,0 @@ -/* - Crate: ore - File: /query/mod.rs - Module: ::query - Visibility: public - */ - -// TODO: documentation - -use hyper::Error as HttpError; -use serde_json::Error as SerdeError; -use std::error::Error as StdError; -use std::fmt::{Display, Formatter, Result as FmtResult}; -use std::io::Error as IoError; -use std::result::Result as StdResult; - -pub type Result = StdResult; - -// TODO: documentation -pub trait Query<'a> { - // TODO: documentation - /// The return type. - type Ret; - - // TODO: documentation - /// Initiate a query. - fn query(&self, url: &'a str) -> Result; -} - -// TODO: documentation -#[derive(Debug)] -pub enum Error { - Http(HttpError), - InvalidId(String), - Io(IoError), - Json(SerdeError), -} From a9b28491e54c9f3f68ea4fd82e6d882de12bf052 Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Sat, 27 May 2017 11:43:36 -0700 Subject: [PATCH 13/22] rewrite some structs to remove the &str , remove Query, replace with Request, provide a ProjectsQuery Signed-off-by: Hunar Roop Kahlon --- src/lib.rs | 2 +- src/project/channel.rs | 12 +- src/project/member.rs | 10 +- src/project/mod.rs | 44 +++--- src/project/request.rs | 264 +++++++++++++++++++++++++++++++++++ src/project/version.rs | 41 +++--- src/{query.rs => request.rs} | 18 ++- 7 files changed, 328 insertions(+), 63 deletions(-) create mode 100644 src/project/request.rs rename src/{query.rs => request.rs} (85%) diff --git a/src/lib.rs b/src/lib.rs index a4666b5..62be55d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ extern crate serde_derive; extern crate serde_json; pub mod project; -pub mod query; +pub mod request; mod serialize; diff --git a/src/project/channel.rs b/src/project/channel.rs index 15a7c11..5230e67 100644 --- a/src/project/channel.rs +++ b/src/project/channel.rs @@ -15,12 +15,12 @@ use std::result::Result as StdResult; // TODO documentation #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -pub struct Channel<'a> { +pub struct Channel { color: Color, - name: &'a str, + name: String, } -impl<'a> Channel<'a> { +impl Channel { // TODO: documentation pub fn color(&self) -> Color { @@ -28,12 +28,12 @@ impl<'a> Channel<'a> { } // TODO: documentation - pub fn name(&self) -> &str { - self.name + pub fn name(&self) -> String { + self.name.to_owned() } } -impl<'a> Display for Channel<'a> { +impl Display for Channel { fn fmt(&self, f: &mut Formatter) -> FmtResult { write!(f, "{}", self.name) diff --git a/src/project/member.rs b/src/project/member.rs index 061144c..8b4b243 100644 --- a/src/project/member.rs +++ b/src/project/member.rs @@ -12,14 +12,14 @@ use std::fmt::{Display, Formatter, Result as FmtResult}; // TODO: documentation #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -pub struct Member<'a> { +pub struct Member { head_role: Role, - name: &'a str, + name: String, roles: Vec, user_id: u32, } -impl<'a> Member<'a> { +impl Member { // TODO: documentation pub fn head_role(&self) -> Role { @@ -27,8 +27,8 @@ impl<'a> Member<'a> { } // TODO: documentation - pub fn name(&self) -> &str { - self.name + pub fn name(&self) -> String { + self.name.to_owned() } // TODO: documentation diff --git a/src/project/mod.rs b/src/project/mod.rs index 451c0e4..150cd3d 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -10,6 +10,7 @@ pub mod category; pub mod channel; pub mod member; +pub mod request; pub mod version; use chrono::{DateTime, UTC}; @@ -19,27 +20,27 @@ use self::member::Member; use self::version::Version; use serialize::{deserialize_datetime, serialize_datetime}; -// // TODO: documentation +// TODO: documentation #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct Project<'a> { +pub struct Project { category: Category, - channels: Vec>, + channels: Vec, #[serde(serialize_with = "serialize_datetime", deserialize_with = "deserialize_datetime")] created_at: DateTime, - description: &'a str, + description: String, downloads: u32, - href: &'a str, - members: Vec>, - name: &'a str, - owner: &'a str, - plugin_id: &'a str, - recommended: Version<'a>, + href: String, + members: Vec, + name: String, + owner: String, + plugin_id: String, + recommended: Version, stars: u32, views: u32, } -impl<'a> Project<'a> { +impl Project { // TODO: documentation pub fn category(&self) -> Category { @@ -54,12 +55,13 @@ impl<'a> Project<'a> { // TODO: documentation pub fn created_at(&self) -> String { use serialize::DATE_TIME_FMT; + format!("{}", self.created_at.format(DATE_TIME_FMT)) } // TODO: documentation - pub fn description(&self) -> &str { - self.description + pub fn description(&self) -> String { + self.description.to_owned() } // TODO: documentation @@ -68,8 +70,8 @@ impl<'a> Project<'a> { } // TODO: documentation - pub fn href(&self) -> &str { - self.href + pub fn href(&self) -> String { + self.href.to_owned() } // TODO: documentation @@ -78,18 +80,18 @@ impl<'a> Project<'a> { } // TODO: documentation - pub fn name(&self) -> &str { - self.name + pub fn name(&self) -> String { + self.name.to_owned() } // TODO: documentation - pub fn owner(&self) -> &str { - self.owner + pub fn owner(&self) -> String { + self.owner.to_owned() } // TODO: documentation - pub fn plugin_id(&self) -> &str { - self.plugin_id + pub fn plugin_id(&self) -> String { + self.plugin_id.to_owned() } // TODO: documentation diff --git a/src/project/request.rs b/src/project/request.rs new file mode 100644 index 0000000..2bfe606 --- /dev/null +++ b/src/project/request.rs @@ -0,0 +1,264 @@ +/* + Crate: ore + File: /project/request.rs + Module: ::project::request + Visibility: public + */ + +// TODO: documentation + +use hyper::{Client, Url}; +use hyper::net::HttpsConnector; +use hyper_rustls::TlsClient; +use project::category::Category; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde_json; +use request::{Error as RequestError, Request}; +use super::Project; +use serde::de::{Error as DeserializeError, Visitor}; +use std::fmt::{Display, Formatter, Result as FmtResult}; +use std::io::Read; +use std::result::Result as StdResult; + +const PROJECTS: &'static str = "/projects"; + +// TODO: documentation +#[derive(Clone, Debug)] +pub struct ProjectsQuery { + categories: Option>, + limit: Option, + offset: Option, + q: Option, + sort: Option, +} + +impl ProjectsQuery { + + // TODO: documentation + pub fn categories(&self) -> Option> { + self.categories.to_owned() + } + + // TODO: documentation + pub fn add_category(&mut self, category: &Category) -> &mut Self { + + match self.categories { + Some(ref mut cats) => cats.push(*category), + None => self.categories = Some(vec![*category]), + } + + self + } + + // TODO: documentation + pub fn set_categories(&mut self, categories: &Vec) -> &mut Self { + self.categories = Some(categories.to_vec()); + self + } + + // TODO: documentation + pub fn reset_categories(&mut self) -> &mut Self { + self.categories = None; + self + } + + // TODO: documentation + pub fn limit(&self) -> Option { + self.limit + } + + // TODO: documentation + pub fn set_limit(&mut self, limit: u32) -> &mut Self { + self.limit = Some(limit); + self + } + + // TODO: documentation + pub fn reset_limit(&mut self) -> &mut Self { + self.limit = None; + self + } + + // TODO: documentation + pub fn offset(&self) -> Option { + self.offset + } + + // TODO: documentation + pub fn set_offset(&mut self, offset: u32) -> &mut Self { + self.offset = Some(offset); + self + } + + // TODO: documentation + pub fn reset_offset(&mut self) -> &mut Self { + self.offset = None; + self + } + + // TODO: documentation + pub fn query(&self) -> Option { + self.q.to_owned() + } + + // TODO: documentation + pub fn set_query(&mut self, query: String) -> &mut Self { + self.q = Some(query); + self + } + + // TODO: documentation + pub fn reset_query(&mut self) -> &mut Self { + self.q = None; + self + } + + // TODO: documentation + pub fn sort_type(&self) -> Option { + self.sort + } + + // TODO: documentation + pub fn set_sort_type(&mut self, sort_type: &SortType) -> &mut Self { + self.sort = Some(*sort_type); + self + } + + pub fn reset_sort_type(&mut self) -> &mut Self { + self.sort = None; + self + } +} + +impl Default for ProjectsQuery { + + fn default() -> Self { + ProjectsQuery { + categories: None, + limit: None, + offset: None, + q: None, + sort: None, + } + } +} + +impl<'a> Request<'a> for ProjectsQuery { + type Ret = Vec; + + fn request(&self, url: &'a str) -> StdResult { + let mut req_url = Url::parse((url.to_string() + PROJECTS).as_str())?; + + { + let mut query_pairs = req_url.query_pairs_mut(); + + if let Some(ref categories) = self.categories { + query_pairs.append_pair("categories", + categories + .into_iter() + .map(|c| *c as u8) + .fold(String::new(), |acc, next| { + acc + "," + next.to_string().as_str() + }) + .as_str()); + } + + if let Some(ref limit) = self.limit { + query_pairs.append_pair("limit", (*limit).to_string().as_str()); + } + + if let Some(ref offset) = self.offset { + query_pairs.append_pair("offset", offset.to_string().as_str()); + } + + if let Some(ref query) = self.q { + query_pairs.append_pair("q", query); + } + + if let Some(ref sort) = self.sort { + query_pairs.append_pair("sort", (*sort as u8).to_string().as_str()); + } + } + + let mut res = String::new(); + Client::with_connector(HttpsConnector::new(TlsClient::new())).get(req_url).send()? + .read_to_string(&mut res)?; + + Ok(serde_json::from_str::(res.as_str())?) + } +} + +// TODO: documentation +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +pub enum SortType { + MostStars, + MostDownloads, + MostViews, + Newest, + RecentlyUpdated, +} + +#[doc(hidden)] +impl<'a> Deserialize<'a> for SortType { + + fn deserialize(deserializer: D) -> StdResult + where D: Deserializer<'a> + { + deserializer.deserialize_u8(SortTypeVisitor) + } +} + +impl Display for SortType { + + fn fmt(&self, f: &mut Formatter) -> FmtResult { + write!(f, "{}", match *self { + SortType::MostStars => "Most Stars", + SortType::MostDownloads => "Most Downloads", + SortType::MostViews => "Most Views", + SortType::Newest => "Newest", + SortType::RecentlyUpdated => "Recently Updated", + }) + } +} + +#[doc(hidden)] +impl Serialize for SortType { + + fn serialize(&self, serializer: S) -> StdResult + where S: Serializer + { + serializer.serialize_u8(*self as u8) + } +} + +// TODO: documentation +struct SortTypeVisitor; + +impl<'a> Visitor<'a> for SortTypeVisitor { + + type Value = SortType; + + fn expecting(&self, f: &mut Formatter) -> FmtResult { + write!(f, "an integer between 0-{}", 4) + } + + fn visit_u8(self, v: u8) -> Result + where E: DeserializeError + { + match v { + 0 => Ok(SortType::MostStars), + 1 => Ok(SortType::MostDownloads), + 2 => Ok(SortType::MostViews), + 3 => Ok(SortType::Newest), + 4 => Ok(SortType::RecentlyUpdated), + _ => Err(DeserializeError::custom(r#"invalid sort type"#)) + } + } + + fn visit_u64(self, v: u64) -> Result + where E: DeserializeError + { + Self::visit_u8(self, v as u8) + } +} diff --git a/src/project/version.rs b/src/project/version.rs index 0f87afa..2e75cae 100644 --- a/src/project/version.rs +++ b/src/project/version.rs @@ -15,19 +15,19 @@ use std::fmt::{Display, Formatter, Result as FmtResult}; // TODO: documentation #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -pub struct Version<'a> { - channel: Channel<'a>, +pub struct Version { + channel: Channel, #[serde(serialize_with = "serialize_datetime", deserialize_with = "deserialize_datetime")] created_at: DateTime, - dependencies: Vec>, + dependencies: Vec, file_size: u32, id: u32, - name: &'a str, - plugin_id: &'a str, + name: String, + plugin_id: String, staff_approved: bool, } -impl<'a> Version<'a> { +impl Version { // TODO: documentation pub fn channel(&self) -> Channel @@ -38,6 +38,7 @@ impl<'a> Version<'a> { // TODO: documentation pub fn created_at(&self) -> String { use serialize::DATE_TIME_FMT; + format!("{}", self.created_at.format(DATE_TIME_FMT)) } @@ -57,13 +58,13 @@ impl<'a> Version<'a> { } // TODO: documentation - pub fn name(&self) -> &str { - self.name + pub fn name(&self) -> String { + self.name.to_owned() } // TODO: documentation - pub fn plugin_id(&self) -> &str { - self.plugin_id + pub fn plugin_id(&self) -> String { + self.plugin_id.to_owned() } // TODO: documentation @@ -73,27 +74,27 @@ impl<'a> Version<'a> { } // TODO: documentation -#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -pub struct Dependency<'a> { - plugin_id: &'a str, - version: &'a str, +pub struct Dependency { + plugin_id: String, + version: String, } -impl<'a> Dependency<'a> { +impl Dependency { // TODO: documentation - pub fn plugin_name(&self) -> &str { - self.plugin_id + pub fn plugin_name(&self) -> String { + self.plugin_id.to_owned() } // TODO: documentation - pub fn version(&self) -> &str { - self.version + pub fn version(&self) -> String { + self.version.to_owned() } } -impl<'a> Display for Dependency<'a> { +impl Display for Dependency { fn fmt(&self, f: &mut Formatter) -> FmtResult { write!(f, "{}@{}", self.plugin_id, self.version) diff --git a/src/query.rs b/src/request.rs similarity index 85% rename from src/query.rs rename to src/request.rs index 2c73d9e..db3ec97 100644 --- a/src/query.rs +++ b/src/request.rs @@ -1,7 +1,7 @@ /* Crate: ore - File: /query.rs - Module: ::query + File: /request.rs + Module: ::request Visibility: public */ @@ -9,23 +9,21 @@ use hyper::Error as HttpError; use hyper::error::ParseError as UriParseError; -use serde_json::Error as SerdeError; +use serde_json::Error as JsonError; use std::error::Error as StdError; use std::fmt::{Display, Formatter, Result as FmtResult}; use std::io::Error as IoError; use std::result::Result as StdResult; -pub type Result = StdResult; - // TODO: documentation -pub trait Query<'a> { +pub trait Request<'a> { // TODO: documentation /// The return type. type Ret; // TODO: documentation /// Initiate a query. - fn query(&self, url: &'a str) -> Result; + fn request(&self, url: &'a str) -> StdResult; } // TODO: documentation @@ -34,7 +32,7 @@ pub enum Error { Http(HttpError), InvalidId(String), Io(IoError), - Json(SerdeError), + Json(JsonError), } impl Display for Error { @@ -70,9 +68,9 @@ impl From for Error { } } -impl From for Error { +impl From for Error { - fn from(err: SerdeError) -> Self { + fn from(err: JsonError) -> Self { Error::Json(err) } } From 90a531fa1a7ef570f4191d04bce8945d0ba6ad34 Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Sat, 27 May 2017 12:00:24 -0700 Subject: [PATCH 14/22] ProjectsQuery -> ProjectsRequest Signed-off-by: Hunar Roop Kahlon --- src/project/request.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/project/request.rs b/src/project/request.rs index 2bfe606..79423df 100644 --- a/src/project/request.rs +++ b/src/project/request.rs @@ -24,7 +24,7 @@ const PROJECTS: &'static str = "/projects"; // TODO: documentation #[derive(Clone, Debug)] -pub struct ProjectsQuery { +pub struct ProjectsRequest { categories: Option>, limit: Option, offset: Option, @@ -32,7 +32,7 @@ pub struct ProjectsQuery { sort: Option, } -impl ProjectsQuery { +impl ProjectsRequest { // TODO: documentation pub fn categories(&self) -> Option> { @@ -130,10 +130,10 @@ impl ProjectsQuery { } } -impl Default for ProjectsQuery { +impl Default for ProjectsRequest { fn default() -> Self { - ProjectsQuery { + ProjectsRequest { categories: None, limit: None, offset: None, @@ -143,7 +143,7 @@ impl Default for ProjectsQuery { } } -impl<'a> Request<'a> for ProjectsQuery { +impl<'a> Request<'a> for ProjectsRequest { type Ret = Vec; fn request(&self, url: &'a str) -> StdResult { From bcdd09595b595243ee8e1f24de1d344bc6878747 Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Sat, 27 May 2017 12:21:59 -0700 Subject: [PATCH 15/22] formatting fixes Signed-off-by: Hunar Roop Kahlon --- src/project/channel.rs | 29 +++++++++++++---------------- src/project/member.rs | 18 +++++++++--------- src/project/mod.rs | 1 - src/project/request.rs | 40 ++++++++++++++++++++-------------------- src/project/version.rs | 6 +----- src/request.rs | 8 +------- 6 files changed, 44 insertions(+), 58 deletions(-) diff --git a/src/project/channel.rs b/src/project/channel.rs index 5230e67..68fbac4 100644 --- a/src/project/channel.rs +++ b/src/project/channel.rs @@ -21,7 +21,6 @@ pub struct Channel { } impl Channel { - // TODO: documentation pub fn color(&self) -> Color { self.color @@ -34,7 +33,6 @@ impl Channel { } impl Display for Channel { - fn fmt(&self, f: &mut Formatter) -> FmtResult { write!(f, "{}", self.name) } @@ -48,7 +46,6 @@ pub enum Color { } impl Color { - // TODO: documentation pub fn red(&self) -> Option { match *self { @@ -84,7 +81,6 @@ impl Color { #[doc(hidden)] impl<'a> Deserialize<'a> for Color { - fn deserialize(deserializer: D) -> StdResult where D: Deserializer<'a> { @@ -93,7 +89,6 @@ impl<'a> Deserialize<'a> for Color { } impl Display for Color { - fn fmt(&self, f: &mut Formatter) -> FmtResult { match *self { Color::Transparent => write!(f, "transparent"), @@ -104,14 +99,17 @@ impl Display for Color { #[doc(hidden)] impl Serialize for Color { - fn serialize(&self, serializer: S) -> StdResult where S: Serializer { - serializer.serialize_str(format!("{}", match *self { - Color::RGB(ref r, ref g, ref b) => format!("#{:x}{:x}{:x}", r, g, b), - Color::Transparent => "transparent".to_string(), - }).as_str()) + serializer.serialize_str(format!("{}", + match *self { + Color::RGB(ref r, ref g, ref b) => { + format!("#{:x}{:x}{:x}", r, g, b) + } + Color::Transparent => "transparent".to_string(), + }) + .as_str()) } } @@ -132,11 +130,10 @@ impl<'a> Visitor<'a> for ColorVisitor { "transparent" => Ok(Color::Transparent), ref s => { if s.len() != 7 { - Err(DeserializeError::custom("color code has to be 7 characters long")) + Err(DeserializeError::custom("color code should be 7 characters long")) } else { if !s.starts_with("#") { - return Err( - DeserializeError::custom("color code needs to start with a \"#\"")) + return Err(DeserializeError::custom("color code should start with \"#\"")); } let mut rgb: (u8, u8, u8) = (0, 0, 0); @@ -149,7 +146,7 @@ impl<'a> Visitor<'a> for ColorVisitor { match buf.as_str().parse::() { Ok(x) => rgb.0 = x, Err(..) => return Err(DeserializeError::custom( - r#""red" component of the color code is incorrect"#)) + r#""red" component of the color code is incorrect"#)), } buf.clear(); @@ -159,7 +156,7 @@ impl<'a> Visitor<'a> for ColorVisitor { match buf.as_str().parse::() { Ok(x) => rgb.1 = x, Err(..) => return Err(DeserializeError::custom( - r#""green" component of the color code is incorrect"#)) + r#""green" component of the color code is incorrect"#)), } buf.clear(); @@ -169,7 +166,7 @@ impl<'a> Visitor<'a> for ColorVisitor { match buf.as_str().parse::() { Ok(x) => rgb.2 = x, Err(..) => return Err(DeserializeError::custom( - r#""blue" component of the color code is incorrect"#)) + r#""blue" component of the color code is incorrect"#)), } Ok(Color::RGB(rgb.0, rgb.1, rgb.2)) diff --git a/src/project/member.rs b/src/project/member.rs index 8b4b243..3a90dab 100644 --- a/src/project/member.rs +++ b/src/project/member.rs @@ -20,7 +20,6 @@ pub struct Member { } impl Member { - // TODO: documentation pub fn head_role(&self) -> Role { self.head_role @@ -54,14 +53,15 @@ pub enum Role { } impl Display for Role { - fn fmt(&self, f: &mut Formatter) -> FmtResult { - write!(f, "{}", match *self { - Role::Admin => "Admin", - Role::Developer => "Developer", - Role::Editor => "Editor", - Role::Owner => "Owner", - Role::Support => "Support", - }) + write!(f, + "{}", + match *self { + Role::Admin => "Admin", + Role::Developer => "Developer", + Role::Editor => "Editor", + Role::Owner => "Owner", + Role::Support => "Support", + }) } } diff --git a/src/project/mod.rs b/src/project/mod.rs index 150cd3d..ad94e93 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -41,7 +41,6 @@ pub struct Project { } impl Project { - // TODO: documentation pub fn category(&self) -> Category { self.category diff --git a/src/project/request.rs b/src/project/request.rs index 79423df..206db28 100644 --- a/src/project/request.rs +++ b/src/project/request.rs @@ -7,9 +7,7 @@ // TODO: documentation -use hyper::{Client, Url}; -use hyper::net::HttpsConnector; -use hyper_rustls::TlsClient; + use project::category::Category; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_json; @@ -17,7 +15,6 @@ use request::{Error as RequestError, Request}; use super::Project; use serde::de::{Error as DeserializeError, Visitor}; use std::fmt::{Display, Formatter, Result as FmtResult}; -use std::io::Read; use std::result::Result as StdResult; const PROJECTS: &'static str = "/projects"; @@ -33,14 +30,13 @@ pub struct ProjectsRequest { } impl ProjectsRequest { - // TODO: documentation pub fn categories(&self) -> Option> { self.categories.to_owned() } // TODO: documentation - pub fn add_category(&mut self, category: &Category) -> &mut Self { + pub fn add_category(&mut self, category: &Category) -> &mut Self { match self.categories { Some(ref mut cats) => cats.push(*category), @@ -131,7 +127,6 @@ impl ProjectsRequest { } impl Default for ProjectsRequest { - fn default() -> Self { ProjectsRequest { categories: None, @@ -147,6 +142,11 @@ impl<'a> Request<'a> for ProjectsRequest { type Ret = Vec; fn request(&self, url: &'a str) -> StdResult { + use hyper::{Client, Url}; + use hyper::net::HttpsConnector; + use hyper_rustls::TlsClient; + use std::io::Read; + let mut req_url = Url::parse((url.to_string() + PROJECTS).as_str())?; { @@ -181,7 +181,9 @@ impl<'a> Request<'a> for ProjectsRequest { } let mut res = String::new(); - Client::with_connector(HttpsConnector::new(TlsClient::new())).get(req_url).send()? + Client::with_connector(HttpsConnector::new(TlsClient::new())) + .get(req_url) + .send()? .read_to_string(&mut res)?; Ok(serde_json::from_str::(res.as_str())?) @@ -201,7 +203,6 @@ pub enum SortType { #[doc(hidden)] impl<'a> Deserialize<'a> for SortType { - fn deserialize(deserializer: D) -> StdResult where D: Deserializer<'a> { @@ -210,21 +211,21 @@ impl<'a> Deserialize<'a> for SortType { } impl Display for SortType { - fn fmt(&self, f: &mut Formatter) -> FmtResult { - write!(f, "{}", match *self { - SortType::MostStars => "Most Stars", - SortType::MostDownloads => "Most Downloads", - SortType::MostViews => "Most Views", - SortType::Newest => "Newest", - SortType::RecentlyUpdated => "Recently Updated", - }) + write!(f, + "{}", + match *self { + SortType::MostStars => "Most Stars", + SortType::MostDownloads => "Most Downloads", + SortType::MostViews => "Most Views", + SortType::Newest => "Newest", + SortType::RecentlyUpdated => "Recently Updated", + }) } } #[doc(hidden)] impl Serialize for SortType { - fn serialize(&self, serializer: S) -> StdResult where S: Serializer { @@ -236,7 +237,6 @@ impl Serialize for SortType { struct SortTypeVisitor; impl<'a> Visitor<'a> for SortTypeVisitor { - type Value = SortType; fn expecting(&self, f: &mut Formatter) -> FmtResult { @@ -252,7 +252,7 @@ impl<'a> Visitor<'a> for SortTypeVisitor { 2 => Ok(SortType::MostViews), 3 => Ok(SortType::Newest), 4 => Ok(SortType::RecentlyUpdated), - _ => Err(DeserializeError::custom(r#"invalid sort type"#)) + _ => Err(DeserializeError::custom(r#"invalid sort type"#)), } } diff --git a/src/project/version.rs b/src/project/version.rs index 2e75cae..a7890ae 100644 --- a/src/project/version.rs +++ b/src/project/version.rs @@ -28,10 +28,8 @@ pub struct Version { } impl Version { - // TODO: documentation - pub fn channel(&self) -> Channel - { + pub fn channel(&self) -> Channel { self.channel.to_owned() } @@ -82,7 +80,6 @@ pub struct Dependency { } impl Dependency { - // TODO: documentation pub fn plugin_name(&self) -> String { self.plugin_id.to_owned() @@ -95,7 +92,6 @@ impl Dependency { } impl Display for Dependency { - fn fmt(&self, f: &mut Formatter) -> FmtResult { write!(f, "{}@{}", self.plugin_id, self.version) } diff --git a/src/request.rs b/src/request.rs index db3ec97..f7dbc34 100644 --- a/src/request.rs +++ b/src/request.rs @@ -36,7 +36,6 @@ pub enum Error { } impl Display for Error { - fn fmt(&self, f: &mut Formatter) -> FmtResult { match *self { Error::Http(ref why) => why.fmt(f), @@ -48,41 +47,36 @@ impl Display for Error { } impl From for Error { - fn from(err: HttpError) -> Self { Error::Http(err) } } impl From for Error { - fn from(err: UriParseError) -> Self { Error::Http(HttpError::Uri(err)) } } impl From for Error { - fn from(err: IoError) -> Self { Error::Io(err) } } impl From for Error { - fn from(err: JsonError) -> Self { Error::Json(err) } } impl StdError for Error { - fn description(&self) -> &str { match *self { Error::Http(ref why) => why.description(), Error::InvalidId(..) => "Invalid project id found", Error::Io(ref why) => why.description(), - Error::Json(ref why) => why.description() + Error::Json(ref why) => why.description(), } } From 6087093a08138aae3c5faedaf0cda84ee98129ec Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Sat, 27 May 2017 21:52:31 -0700 Subject: [PATCH 16/22] add request functions for projects Signed-off-by: Hunar Roop Kahlon --- src/project/mod.rs | 10 ++++++++++ src/project/request.rs | 16 ++++++++++++++++ src/request.rs | 6 +++--- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/project/mod.rs b/src/project/mod.rs index ad94e93..99ee88d 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -13,6 +13,9 @@ pub mod member; pub mod request; pub mod version; +pub use self::request::get_plugin; + +use ::request::{Error as RequestError, Request}; use chrono::{DateTime, UTC}; use self::category::Category; use self::channel::Channel; @@ -108,3 +111,10 @@ impl Project { self.views } } + +// TODO: documentation +pub fn search_projects(query: &str, url: &str) -> Result, RequestError> { + use self::request::ProjectsRequest; + + ProjectsRequest::default().set_query(query.to_string()).request(url) +} diff --git a/src/project/request.rs b/src/project/request.rs index 206db28..7b590a4 100644 --- a/src/project/request.rs +++ b/src/project/request.rs @@ -262,3 +262,19 @@ impl<'a> Visitor<'a> for SortTypeVisitor { Self::visit_u8(self, v as u8) } } + +pub fn get_plugin(id: &str, url: &str) -> Result { + use hyper::{Client, Url}; + use hyper::net::HttpsConnector; + use hyper_rustls::TlsClient; + use std::io::Read; + + let mut res = String::new(); + Client::with_connector(HttpsConnector::new(TlsClient::new())) + .get(Url::parse((url.to_string() + PROJECTS).as_str())?.join(id) + .map_err(|_| RequestError::InvalidId)?) + .send()? + .read_to_string(&mut res)?; + + Ok(serde_json::from_str::(res.as_str())?) +} diff --git a/src/request.rs b/src/request.rs index f7dbc34..eceefb3 100644 --- a/src/request.rs +++ b/src/request.rs @@ -30,7 +30,7 @@ pub trait Request<'a> { #[derive(Debug)] pub enum Error { Http(HttpError), - InvalidId(String), + InvalidId, Io(IoError), Json(JsonError), } @@ -39,7 +39,7 @@ impl Display for Error { fn fmt(&self, f: &mut Formatter) -> FmtResult { match *self { Error::Http(ref why) => why.fmt(f), - Error::InvalidId(ref why) => write!(f, "invalid project id {}", why), + Error::InvalidId => write!(f, "invalid project id"), Error::Io(ref why) => why.fmt(f), Error::Json(ref why) => why.fmt(f), } @@ -74,7 +74,7 @@ impl StdError for Error { fn description(&self) -> &str { match *self { Error::Http(ref why) => why.description(), - Error::InvalidId(..) => "Invalid project id found", + Error::InvalidId => "Invalid project id found", Error::Io(ref why) => why.description(), Error::Json(ref why) => why.description(), } From 29cd95bebbfaa5e812edaebd6993f157b394f1ac Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Sun, 28 May 2017 13:10:57 -0700 Subject: [PATCH 17/22] revert revert revert Signed-off-by: Hunar Roop Kahlon --- src/project/mod.rs | 2 +- src/project/request.rs | 4 ++-- src/request.rs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/project/mod.rs b/src/project/mod.rs index 99ee88d..b825dd0 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -92,7 +92,7 @@ impl Project { } // TODO: documentation - pub fn plugin_id(&self) -> String { + pub fn project_id(&self) -> String { self.plugin_id.to_owned() } diff --git a/src/project/request.rs b/src/project/request.rs index 7b590a4..2e6a27a 100644 --- a/src/project/request.rs +++ b/src/project/request.rs @@ -271,8 +271,8 @@ pub fn get_plugin(id: &str, url: &str) -> Result { let mut res = String::new(); Client::with_connector(HttpsConnector::new(TlsClient::new())) - .get(Url::parse((url.to_string() + PROJECTS).as_str())?.join(id) - .map_err(|_| RequestError::InvalidId)?) + .get(Url::parse((url.to_string() + PROJECTS).as_str())?.join(&id) + .map_err(|_| RequestError::InvalidId(id.to_string()))?) .send()? .read_to_string(&mut res)?; diff --git a/src/request.rs b/src/request.rs index eceefb3..f7dbc34 100644 --- a/src/request.rs +++ b/src/request.rs @@ -30,7 +30,7 @@ pub trait Request<'a> { #[derive(Debug)] pub enum Error { Http(HttpError), - InvalidId, + InvalidId(String), Io(IoError), Json(JsonError), } @@ -39,7 +39,7 @@ impl Display for Error { fn fmt(&self, f: &mut Formatter) -> FmtResult { match *self { Error::Http(ref why) => why.fmt(f), - Error::InvalidId => write!(f, "invalid project id"), + Error::InvalidId(ref why) => write!(f, "invalid project id {}", why), Error::Io(ref why) => why.fmt(f), Error::Json(ref why) => why.fmt(f), } @@ -74,7 +74,7 @@ impl StdError for Error { fn description(&self) -> &str { match *self { Error::Http(ref why) => why.description(), - Error::InvalidId => "Invalid project id found", + Error::InvalidId(..) => "Invalid project id found", Error::Io(ref why) => why.description(), Error::Json(ref why) => why.description(), } From 8d0dfc2d47bbd78a24d7ed92cc1adfdd7f5ecc0a Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Sun, 28 May 2017 15:04:12 -0700 Subject: [PATCH 18/22] eliminate unnecessary module Signed-off-by: Hunar Roop Kahlon --- src/project/mod.rs | 278 ++++++++++++++++++++++++++++++++++++++++- src/project/request.rs | 262 -------------------------------------- 2 files changed, 272 insertions(+), 268 deletions(-) diff --git a/src/project/mod.rs b/src/project/mod.rs index b825dd0..83e1c54 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -10,18 +10,20 @@ pub mod category; pub mod channel; pub mod member; -pub mod request; pub mod version; -pub use self::request::get_plugin; - -use ::request::{Error as RequestError, Request}; +use request::{Error as RequestError, Request}; use chrono::{DateTime, UTC}; use self::category::Category; use self::channel::Channel; use self::member::Member; use self::version::Version; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde::de::{Error as DeserializeError, Visitor}; +use serde_json; use serialize::{deserialize_datetime, serialize_datetime}; +use std::fmt::{Display, Formatter, Result as FmtResult}; +use std::result::Result as StdResult; // TODO: documentation #[derive(Clone, Debug, Serialize, Deserialize)] @@ -112,9 +114,273 @@ impl Project { } } +const PROJECTS: &'static str = "/projects"; + +// TODO: documentation +#[derive(Clone, Debug)] +pub struct ProjectsRequest { + categories: Option>, + limit: Option, + offset: Option, + q: Option, + sort: Option, +} + +impl ProjectsRequest { + // TODO: documentation + pub fn categories(&self) -> Option> { + self.categories.to_owned() + } + + // TODO: documentation + pub fn add_category(&mut self, category: &Category) -> &mut Self { + + match self.categories { + Some(ref mut cats) => cats.push(*category), + None => self.categories = Some(vec![*category]), + } + + self + } + + // TODO: documentation + pub fn set_categories(&mut self, categories: &Vec) -> &mut Self { + self.categories = Some(categories.to_vec()); + self + } + + // TODO: documentation + pub fn reset_categories(&mut self) -> &mut Self { + self.categories = None; + self + } + + // TODO: documentation + pub fn limit(&self) -> Option { + self.limit + } + + // TODO: documentation + pub fn set_limit(&mut self, limit: u32) -> &mut Self { + self.limit = Some(limit); + self + } + + // TODO: documentation + pub fn reset_limit(&mut self) -> &mut Self { + self.limit = None; + self + } + + // TODO: documentation + pub fn offset(&self) -> Option { + self.offset + } + + // TODO: documentation + pub fn set_offset(&mut self, offset: u32) -> &mut Self { + self.offset = Some(offset); + self + } + + // TODO: documentation + pub fn reset_offset(&mut self) -> &mut Self { + self.offset = None; + self + } + + // TODO: documentation + pub fn query(&self) -> Option { + self.q.to_owned() + } + + // TODO: documentation + pub fn set_query(&mut self, query: String) -> &mut Self { + self.q = Some(query); + self + } + + // TODO: documentation + pub fn reset_query(&mut self) -> &mut Self { + self.q = None; + self + } + + // TODO: documentation + pub fn sort_type(&self) -> Option { + self.sort + } + + // TODO: documentation + pub fn set_sort_type(&mut self, sort_type: &SortType) -> &mut Self { + self.sort = Some(*sort_type); + self + } + + pub fn reset_sort_type(&mut self) -> &mut Self { + self.sort = None; + self + } +} + +impl Default for ProjectsRequest { + fn default() -> Self { + ProjectsRequest { + categories: None, + limit: None, + offset: None, + q: None, + sort: None, + } + } +} + +impl<'a> Request<'a> for ProjectsRequest { + type Ret = Vec; + + fn request(&self, url: &'a str) -> StdResult { + use hyper::{Client, Url}; + use hyper::net::HttpsConnector; + use hyper_rustls::TlsClient; + use std::io::Read; + + let mut req_url = Url::parse((url.to_string() + PROJECTS).as_str())?; + + { + let mut query_pairs = req_url.query_pairs_mut(); + + if let Some(ref categories) = self.categories { + query_pairs.append_pair("categories", + categories + .into_iter() + .map(|c| *c as u8) + .fold(String::new(), |acc, next| { + acc + "," + next.to_string().as_str() + }) + .as_str()); + } + + if let Some(ref limit) = self.limit { + query_pairs.append_pair("limit", (*limit).to_string().as_str()); + } + + if let Some(ref offset) = self.offset { + query_pairs.append_pair("offset", offset.to_string().as_str()); + } + + if let Some(ref query) = self.q { + query_pairs.append_pair("q", query); + } + + if let Some(ref sort) = self.sort { + query_pairs.append_pair("sort", (*sort as u8).to_string().as_str()); + } + } + + let mut res = String::new(); + Client::with_connector(HttpsConnector::new(TlsClient::new())) + .get(req_url) + .send()? + .read_to_string(&mut res)?; + + Ok(serde_json::from_str::(res.as_str())?) + } +} + +// TODO: documentation +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +pub enum SortType { + MostStars, + MostDownloads, + MostViews, + Newest, + RecentlyUpdated, +} + +#[doc(hidden)] +impl<'a> Deserialize<'a> for SortType { + fn deserialize(deserializer: D) -> StdResult + where D: Deserializer<'a> + { + deserializer.deserialize_u8(SortTypeVisitor) + } +} + +impl Display for SortType { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + write!(f, + "{}", + match *self { + SortType::MostStars => "Most Stars", + SortType::MostDownloads => "Most Downloads", + SortType::MostViews => "Most Views", + SortType::Newest => "Newest", + SortType::RecentlyUpdated => "Recently Updated", + }) + } +} + +#[doc(hidden)] +impl Serialize for SortType { + fn serialize(&self, serializer: S) -> StdResult + where S: Serializer + { + serializer.serialize_u8(*self as u8) + } +} + +// TODO: documentation +struct SortTypeVisitor; + +impl<'a> Visitor<'a> for SortTypeVisitor { + type Value = SortType; + + fn expecting(&self, f: &mut Formatter) -> FmtResult { + write!(f, "an integer between 0-{}", 4) + } + + fn visit_u8(self, v: u8) -> Result + where E: DeserializeError + { + match v { + 0 => Ok(SortType::MostStars), + 1 => Ok(SortType::MostDownloads), + 2 => Ok(SortType::MostViews), + 3 => Ok(SortType::Newest), + 4 => Ok(SortType::RecentlyUpdated), + _ => Err(DeserializeError::custom(r#"invalid sort type"#)), + } + } + + fn visit_u64(self, v: u64) -> Result + where E: DeserializeError + { + Self::visit_u8(self, v as u8) + } +} + + // TODO: documentation pub fn search_projects(query: &str, url: &str) -> Result, RequestError> { - use self::request::ProjectsRequest; + ProjectsRequest::default() + .set_query(query.to_string()) + .request(url) +} + +pub fn get_plugin(id: &str, url: &str) -> Result { + use hyper::{Client, Url}; + use hyper::net::HttpsConnector; + use hyper_rustls::TlsClient; + use std::io::Read; + + let mut res = String::new(); + Client::with_connector(HttpsConnector::new(TlsClient::new())) + .get(Url::parse((url.to_string() + PROJECTS).as_str())? + .join(&id) + .map_err(|_| RequestError::InvalidId(id.to_string()))?) + .send()? + .read_to_string(&mut res)?; - ProjectsRequest::default().set_query(query.to_string()).request(url) + Ok(serde_json::from_str::(res.as_str())?) } diff --git a/src/project/request.rs b/src/project/request.rs index 2e6a27a..4cdb9af 100644 --- a/src/project/request.rs +++ b/src/project/request.rs @@ -16,265 +16,3 @@ use super::Project; use serde::de::{Error as DeserializeError, Visitor}; use std::fmt::{Display, Formatter, Result as FmtResult}; use std::result::Result as StdResult; - -const PROJECTS: &'static str = "/projects"; - -// TODO: documentation -#[derive(Clone, Debug)] -pub struct ProjectsRequest { - categories: Option>, - limit: Option, - offset: Option, - q: Option, - sort: Option, -} - -impl ProjectsRequest { - // TODO: documentation - pub fn categories(&self) -> Option> { - self.categories.to_owned() - } - - // TODO: documentation - pub fn add_category(&mut self, category: &Category) -> &mut Self { - - match self.categories { - Some(ref mut cats) => cats.push(*category), - None => self.categories = Some(vec![*category]), - } - - self - } - - // TODO: documentation - pub fn set_categories(&mut self, categories: &Vec) -> &mut Self { - self.categories = Some(categories.to_vec()); - self - } - - // TODO: documentation - pub fn reset_categories(&mut self) -> &mut Self { - self.categories = None; - self - } - - // TODO: documentation - pub fn limit(&self) -> Option { - self.limit - } - - // TODO: documentation - pub fn set_limit(&mut self, limit: u32) -> &mut Self { - self.limit = Some(limit); - self - } - - // TODO: documentation - pub fn reset_limit(&mut self) -> &mut Self { - self.limit = None; - self - } - - // TODO: documentation - pub fn offset(&self) -> Option { - self.offset - } - - // TODO: documentation - pub fn set_offset(&mut self, offset: u32) -> &mut Self { - self.offset = Some(offset); - self - } - - // TODO: documentation - pub fn reset_offset(&mut self) -> &mut Self { - self.offset = None; - self - } - - // TODO: documentation - pub fn query(&self) -> Option { - self.q.to_owned() - } - - // TODO: documentation - pub fn set_query(&mut self, query: String) -> &mut Self { - self.q = Some(query); - self - } - - // TODO: documentation - pub fn reset_query(&mut self) -> &mut Self { - self.q = None; - self - } - - // TODO: documentation - pub fn sort_type(&self) -> Option { - self.sort - } - - // TODO: documentation - pub fn set_sort_type(&mut self, sort_type: &SortType) -> &mut Self { - self.sort = Some(*sort_type); - self - } - - pub fn reset_sort_type(&mut self) -> &mut Self { - self.sort = None; - self - } -} - -impl Default for ProjectsRequest { - fn default() -> Self { - ProjectsRequest { - categories: None, - limit: None, - offset: None, - q: None, - sort: None, - } - } -} - -impl<'a> Request<'a> for ProjectsRequest { - type Ret = Vec; - - fn request(&self, url: &'a str) -> StdResult { - use hyper::{Client, Url}; - use hyper::net::HttpsConnector; - use hyper_rustls::TlsClient; - use std::io::Read; - - let mut req_url = Url::parse((url.to_string() + PROJECTS).as_str())?; - - { - let mut query_pairs = req_url.query_pairs_mut(); - - if let Some(ref categories) = self.categories { - query_pairs.append_pair("categories", - categories - .into_iter() - .map(|c| *c as u8) - .fold(String::new(), |acc, next| { - acc + "," + next.to_string().as_str() - }) - .as_str()); - } - - if let Some(ref limit) = self.limit { - query_pairs.append_pair("limit", (*limit).to_string().as_str()); - } - - if let Some(ref offset) = self.offset { - query_pairs.append_pair("offset", offset.to_string().as_str()); - } - - if let Some(ref query) = self.q { - query_pairs.append_pair("q", query); - } - - if let Some(ref sort) = self.sort { - query_pairs.append_pair("sort", (*sort as u8).to_string().as_str()); - } - } - - let mut res = String::new(); - Client::with_connector(HttpsConnector::new(TlsClient::new())) - .get(req_url) - .send()? - .read_to_string(&mut res)?; - - Ok(serde_json::from_str::(res.as_str())?) - } -} - -// TODO: documentation -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -pub enum SortType { - MostStars, - MostDownloads, - MostViews, - Newest, - RecentlyUpdated, -} - -#[doc(hidden)] -impl<'a> Deserialize<'a> for SortType { - fn deserialize(deserializer: D) -> StdResult - where D: Deserializer<'a> - { - deserializer.deserialize_u8(SortTypeVisitor) - } -} - -impl Display for SortType { - fn fmt(&self, f: &mut Formatter) -> FmtResult { - write!(f, - "{}", - match *self { - SortType::MostStars => "Most Stars", - SortType::MostDownloads => "Most Downloads", - SortType::MostViews => "Most Views", - SortType::Newest => "Newest", - SortType::RecentlyUpdated => "Recently Updated", - }) - } -} - -#[doc(hidden)] -impl Serialize for SortType { - fn serialize(&self, serializer: S) -> StdResult - where S: Serializer - { - serializer.serialize_u8(*self as u8) - } -} - -// TODO: documentation -struct SortTypeVisitor; - -impl<'a> Visitor<'a> for SortTypeVisitor { - type Value = SortType; - - fn expecting(&self, f: &mut Formatter) -> FmtResult { - write!(f, "an integer between 0-{}", 4) - } - - fn visit_u8(self, v: u8) -> Result - where E: DeserializeError - { - match v { - 0 => Ok(SortType::MostStars), - 1 => Ok(SortType::MostDownloads), - 2 => Ok(SortType::MostViews), - 3 => Ok(SortType::Newest), - 4 => Ok(SortType::RecentlyUpdated), - _ => Err(DeserializeError::custom(r#"invalid sort type"#)), - } - } - - fn visit_u64(self, v: u64) -> Result - where E: DeserializeError - { - Self::visit_u8(self, v as u8) - } -} - -pub fn get_plugin(id: &str, url: &str) -> Result { - use hyper::{Client, Url}; - use hyper::net::HttpsConnector; - use hyper_rustls::TlsClient; - use std::io::Read; - - let mut res = String::new(); - Client::with_connector(HttpsConnector::new(TlsClient::new())) - .get(Url::parse((url.to_string() + PROJECTS).as_str())?.join(&id) - .map_err(|_| RequestError::InvalidId(id.to_string()))?) - .send()? - .read_to_string(&mut res)?; - - Ok(serde_json::from_str::(res.as_str())?) -} From 3a1e1c9f72367c4c368f7c51498b061a9868d5d3 Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Sun, 28 May 2017 15:08:01 -0700 Subject: [PATCH 19/22] oops i forgot to delete the file Signed-off-by: Hunar Roop Kahlon --- src/project/mod.rs | 2 +- src/project/request.rs | 18 ------------------ 2 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 src/project/request.rs diff --git a/src/project/mod.rs b/src/project/mod.rs index 83e1c54..5bfcec7 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -368,7 +368,7 @@ pub fn search_projects(query: &str, url: &str) -> Result, RequestEr .request(url) } -pub fn get_plugin(id: &str, url: &str) -> Result { +pub fn get_project(id: &str, url: &str) -> Result { use hyper::{Client, Url}; use hyper::net::HttpsConnector; use hyper_rustls::TlsClient; diff --git a/src/project/request.rs b/src/project/request.rs deleted file mode 100644 index 4cdb9af..0000000 --- a/src/project/request.rs +++ /dev/null @@ -1,18 +0,0 @@ -/* - Crate: ore - File: /project/request.rs - Module: ::project::request - Visibility: public - */ - -// TODO: documentation - - -use project::category::Category; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use serde_json; -use request::{Error as RequestError, Request}; -use super::Project; -use serde::de::{Error as DeserializeError, Visitor}; -use std::fmt::{Display, Formatter, Result as FmtResult}; -use std::result::Result as StdResult; From 0acb7700571c03bb60f318f3d66faf1cd5f1771e Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Sun, 28 May 2017 16:18:08 -0700 Subject: [PATCH 20/22] introduce prelude Signed-off-by: Hunar Roop Kahlon --- src/lib.rs | 1 + src/prelude/mod.rs | 10 ++++++++++ src/prelude/v1.rs | 16 ++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 src/prelude/mod.rs create mode 100644 src/prelude/v1.rs diff --git a/src/lib.rs b/src/lib.rs index 62be55d..de91d21 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ extern crate serde; extern crate serde_derive; extern crate serde_json; +pub mod prelude; pub mod project; pub mod request; diff --git a/src/prelude/mod.rs b/src/prelude/mod.rs new file mode 100644 index 0000000..3152f82 --- /dev/null +++ b/src/prelude/mod.rs @@ -0,0 +1,10 @@ +/* + Crate: ore + File: /prelude/mod.rs + Module: ::prelude + Visibility: public + */ + +// TODO: documentation + +pub mod v1; diff --git a/src/prelude/v1.rs b/src/prelude/v1.rs new file mode 100644 index 0000000..eec5c60 --- /dev/null +++ b/src/prelude/v1.rs @@ -0,0 +1,16 @@ +/* + Crate: ore + File: /prelude/v1.rs + Module: ::prelude::v1 + Visibility: public + */ + +// TODO: documentation + +pub use project::{Project, ProjectsRequest}; +pub use project::category::Category; +pub use project::channel::{Channel, Color}; +pub use project::member::{Member, Role}; +pub use project::version::{Dependency, Version}; + +pub use request::{Error as RequestError, Request}; From c8794ffc692baba27fb1616ffc8b857e8d9e85d3 Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Sun, 4 Jun 2017 17:48:52 -0700 Subject: [PATCH 21/22] work on VersionsRequest - incomplete Signed-off-by: Hunar Roop Kahlon --- src/prelude/mod.rs | 10 ++- src/prelude/v1.rs | 16 ----- src/project/mod.rs | 25 ++++--- src/project/version.rs | 146 ++++++++++++++++++++++++++++++++++++++++- src/request.rs | 3 + 5 files changed, 168 insertions(+), 32 deletions(-) delete mode 100644 src/prelude/v1.rs diff --git a/src/prelude/mod.rs b/src/prelude/mod.rs index 3152f82..f1205d9 100644 --- a/src/prelude/mod.rs +++ b/src/prelude/mod.rs @@ -7,4 +7,12 @@ // TODO: documentation -pub mod v1; +pub use project::{Project, ProjectsRequest}; +pub use project::category::Category; +pub use project::channel::{Channel, Color}; +pub use project::member::{Member, Role}; +pub use project::version::{Dependency, Version, VersionsRequest}; + +pub use request::{Error as RequestError, Request}; + +pub use project::{get_project, search_projects}; diff --git a/src/prelude/v1.rs b/src/prelude/v1.rs deleted file mode 100644 index eec5c60..0000000 --- a/src/prelude/v1.rs +++ /dev/null @@ -1,16 +0,0 @@ -/* - Crate: ore - File: /prelude/v1.rs - Module: ::prelude::v1 - Visibility: public - */ - -// TODO: documentation - -pub use project::{Project, ProjectsRequest}; -pub use project::category::Category; -pub use project::channel::{Channel, Color}; -pub use project::member::{Member, Role}; -pub use project::version::{Dependency, Version}; - -pub use request::{Error as RequestError, Request}; diff --git a/src/project/mod.rs b/src/project/mod.rs index 5bfcec7..615cf2e 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -17,7 +17,7 @@ use chrono::{DateTime, UTC}; use self::category::Category; use self::channel::Channel; use self::member::Member; -use self::version::Version; +use self::version::{Version, VersionsRequest}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::de::{Error as DeserializeError, Visitor}; use serde_json; @@ -112,12 +112,18 @@ impl Project { pub fn views(&self) -> u32 { self.views } + + // TODO: documentation + #[inline] + pub fn versions(&self) -> Result { + VersionsRequest::new_from_project(self) + } } const PROJECTS: &'static str = "/projects"; // TODO: documentation -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct ProjectsRequest { categories: Option>, limit: Option, @@ -223,18 +229,6 @@ impl ProjectsRequest { } } -impl Default for ProjectsRequest { - fn default() -> Self { - ProjectsRequest { - categories: None, - limit: None, - offset: None, - q: None, - sort: None, - } - } -} - impl<'a> Request<'a> for ProjectsRequest { type Ret = Vec; @@ -362,12 +356,15 @@ impl<'a> Visitor<'a> for SortTypeVisitor { // TODO: documentation +#[inline] pub fn search_projects(query: &str, url: &str) -> Result, RequestError> { ProjectsRequest::default() .set_query(query.to_string()) .request(url) } +// TODO: documentation +#[inline] pub fn get_project(id: &str, url: &str) -> Result { use hyper::{Client, Url}; use hyper::net::HttpsConnector; diff --git a/src/project/version.rs b/src/project/version.rs index a7890ae..8b0fc34 100644 --- a/src/project/version.rs +++ b/src/project/version.rs @@ -9,8 +9,14 @@ use chrono::{DateTime, UTC}; use project::channel::Channel; +use request::{Error as RequestError, Request}; use serialize::{deserialize_datetime, serialize_datetime}; +use std::collections::HashMap; use std::fmt::{Display, Formatter, Result as FmtResult}; +use super::Project; +use super::get_project; + +const VERSIONS: &'static str = "/versions"; // TODO: documentation #[derive(Clone, Debug, Deserialize, Serialize)] @@ -81,7 +87,7 @@ pub struct Dependency { impl Dependency { // TODO: documentation - pub fn plugin_name(&self) -> String { + pub fn project_name(&self) -> String { self.plugin_id.to_owned() } @@ -89,6 +95,11 @@ impl Dependency { pub fn version(&self) -> String { self.version.to_owned() } + + // TODO: documentation + pub fn get_project(&self, url: &str) -> Result { + super::get_project(self.plugin_id.as_str(), url) + } } impl Display for Dependency { @@ -96,3 +107,136 @@ impl Display for Dependency { write!(f, "{}@{}", self.plugin_id, self.version) } } + +#[derive(Clone, Debug)] +pub struct VersionsRequest { + channels: Option>, + limit: Option, + offset: Option, + _project: Box, +} + +impl VersionsRequest { + + // TODO: documentation + #[inline] + pub fn new_from_id(project_id: String, url: &str) -> Result { + Self::new_from_project(&get_project(project_id.as_str(), url)?) + } + + // TODO: documentation + pub fn new_from_project(project: &Project) -> Result { + Ok(VersionsRequest { + channels: None, + limit: None, + offset: None, + _project: Box::new(project.to_owned()) + }) + } + + // TODO: documentation + pub fn channels(&self) -> Option> { + self.channels.to_owned() + } + + // TODO: documentation + pub fn add_channel(&mut self, channel: &Channel) -> &mut Self { + + match self.channels { + Some(ref mut channels) => channels.push(channel.to_owned()), + None => self.channels = Some(vec![channel.to_owned()]), + } + + self + } + + // TODO: documentation + pub fn set_channels(&mut self, channels: &Vec) -> &mut Self { + self.channels = Some(channels.to_vec()); + self + } + + // TODO: documentation + pub fn reset_channels(&mut self) -> &mut Self { + self.channels = None; + self + } + + // TODO: documentation + pub fn limit(&self) -> Option { + self.limit + } + + // TODO: documentation + pub fn set_limit(&mut self, limit: u32) -> &mut Self { + self.limit = Some(limit); + self + } + + // TODO: documentation + pub fn reset_limit(&mut self) -> &mut Self { + self.limit = None; + self + } + + // TODO: documentation + pub fn offset(&self) -> Option { + self.offset + } + + // TODO: documentation + pub fn set_offset(&mut self, offset: u32) -> &mut Self { + self.limit = Some(offset); + self + } + + // TODO: documentation + pub fn reset_offset(&mut self) -> &mut Self { + self.offset = None; + self + } +} + +impl<'a> Request<'a> for VersionsRequest { + type Ret = Vec; + + fn request(&self, url: &str) -> Result { + use hyper::{Client, Url}; + use hyper::net::HttpsConnector; + use hyper_rustls::TlsClient; + use serde_json; + use std::io::Read; + + // /projects/:pluginId/versions + let mut req_url = Url::parse((url.to_string() + self._project.project_id().as_str() + VERSIONS) + .as_str())?; + + { + let mut query_pairs = req_url.query_pairs_mut(); + + if let Some(ref channels) = self.channels { + query_pairs.append_pair("channels", + channels + .into_iter() + .map(|c| c.name()) + .fold(String::new(), |o, n| o + "," + n.as_str()) + .as_str()); + } + + if let Some(ref limit) = self.limit { + query_pairs.append_pair("limit", limit.to_string().as_str()); + } + + if let Some(ref offset) = self.offset { + query_pairs.append_pair("offset", offset.to_string().as_str()); + } + } + + let mut res = String::new(); + Client::with_connector(HttpsConnector::new(TlsClient::new())) + .get(req_url) + .send()? + .read_to_string(&mut res)?; + Ok(serde_json::from_str::(res.as_str())?) + } +} diff --git a/src/request.rs b/src/request.rs index f7dbc34..2d1d11f 100644 --- a/src/request.rs +++ b/src/request.rs @@ -31,6 +31,7 @@ pub trait Request<'a> { pub enum Error { Http(HttpError), InvalidId(String), + InvalidVersion(String), Io(IoError), Json(JsonError), } @@ -40,6 +41,7 @@ impl Display for Error { match *self { Error::Http(ref why) => why.fmt(f), Error::InvalidId(ref why) => write!(f, "invalid project id {}", why), + Error::InvalidVersion(ref why) => write!(f, "invalid project version {}", why), Error::Io(ref why) => why.fmt(f), Error::Json(ref why) => why.fmt(f), } @@ -75,6 +77,7 @@ impl StdError for Error { match *self { Error::Http(ref why) => why.description(), Error::InvalidId(..) => "Invalid project id found", + Error::InvalidVersion(..) => "invalid project version found", Error::Io(ref why) => why.description(), Error::Json(ref why) => why.description(), } From df58afb2aac0755d6dd974eadfa10c384e2bfa6d Mon Sep 17 00:00:00 2001 From: Hunar Roop Kahlon Date: Sun, 4 Jun 2017 17:53:50 -0700 Subject: [PATCH 22/22] there is only one prelude file so lets remove the mod.rs thingy Signed-off-by: Hunar Roop Kahlon --- src/{prelude/mod.rs => prelude.rs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/{prelude/mod.rs => prelude.rs} (93%) diff --git a/src/prelude/mod.rs b/src/prelude.rs similarity index 93% rename from src/prelude/mod.rs rename to src/prelude.rs index f1205d9..d7c490d 100644 --- a/src/prelude/mod.rs +++ b/src/prelude.rs @@ -1,6 +1,6 @@ /* Crate: ore - File: /prelude/mod.rs + File: /prelude.rs Module: ::prelude Visibility: public */