forked from MightyPork/elefren-fork
Allow constructing Scopes from a string
This commit is contained in:
+127
-4
@@ -3,10 +3,13 @@ use std::{
|
|||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
fmt,
|
fmt,
|
||||||
ops::BitOr,
|
ops::BitOr,
|
||||||
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::ser::{Serialize, Serializer};
|
use serde::ser::{Serialize, Serializer};
|
||||||
|
|
||||||
|
use errors::Error;
|
||||||
|
|
||||||
/// Represents a set of OAuth scopes
|
/// Represents a set of OAuth scopes
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@@ -24,6 +27,21 @@ pub struct Scopes {
|
|||||||
scopes: HashSet<Scope>,
|
scopes: HashSet<Scope>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromStr for Scopes {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Scopes, Self::Err> {
|
||||||
|
let mut set = HashSet::new();
|
||||||
|
for scope in s.split_whitespace() {
|
||||||
|
let scope = Scope::from_str(&scope)?;
|
||||||
|
set.insert(scope);
|
||||||
|
}
|
||||||
|
Ok(Scopes {
|
||||||
|
scopes: set,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Serialize for Scopes {
|
impl Serialize for Scopes {
|
||||||
fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -250,7 +268,7 @@ impl fmt::Display for Scopes {
|
|||||||
/// Permission scope of the application.
|
/// Permission scope of the application.
|
||||||
/// [Details on what each permission provides][1]
|
/// [Details on what each permission provides][1]
|
||||||
/// [1]: https://github.com/tootsuite/documentation/blob/master/Using-the-API/OAuth-details.md)
|
/// [1]: https://github.com/tootsuite/documentation/blob/master/Using-the-API/OAuth-details.md)
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Hash, Serialize)]
|
||||||
enum Scope {
|
enum Scope {
|
||||||
/// Read only permissions.
|
/// Read only permissions.
|
||||||
#[serde(rename = "read")]
|
#[serde(rename = "read")]
|
||||||
@@ -266,9 +284,25 @@ enum Scope {
|
|||||||
Push,
|
Push,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for Scope {
|
impl FromStr for Scope {
|
||||||
fn partial_cmp(&self, other: &Scope) -> Option<Ordering> {
|
type Err = Error;
|
||||||
Some(self.cmp(other))
|
|
||||||
|
fn from_str(s: &str) -> Result<Scope, Self::Err> {
|
||||||
|
Ok(match s {
|
||||||
|
"read" => Scope::Read(None),
|
||||||
|
"write" => Scope::Write(None),
|
||||||
|
"follow" => Scope::Follow,
|
||||||
|
"push" => Scope::Push,
|
||||||
|
read if read.starts_with("read:") => {
|
||||||
|
let r: Read = Read::from_str(&read[5..])?;
|
||||||
|
Scope::Read(Some(r))
|
||||||
|
},
|
||||||
|
write if write.starts_with("write:") => {
|
||||||
|
let w: Write = Write::from_str(&write[6..])?;
|
||||||
|
Scope::Write(Some(w))
|
||||||
|
},
|
||||||
|
_ => return Err(Error::Other("Unknown scope".to_string())),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,6 +397,27 @@ pub enum Read {
|
|||||||
Statuses,
|
Statuses,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromStr for Read {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Read, Self::Err> {
|
||||||
|
Ok(match s {
|
||||||
|
"accounts" => Read::Accounts,
|
||||||
|
"blocks" => Read::Blocks,
|
||||||
|
"favourites" => Read::Favourites,
|
||||||
|
"filters" => Read::Filters,
|
||||||
|
"follows" => Read::Follows,
|
||||||
|
"lists" => Read::Lists,
|
||||||
|
"mutes" => Read::Mutes,
|
||||||
|
"notifications" => Read::Notifications,
|
||||||
|
"reports" => Read::Reports,
|
||||||
|
"search" => Read::Search,
|
||||||
|
"statuses" => Read::Statuses,
|
||||||
|
_ => return Err(Error::Other("Unknown 'read' subcategory".to_string())),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialOrd for Read {
|
impl PartialOrd for Read {
|
||||||
fn partial_cmp(&self, other: &Read) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Read) -> Option<Ordering> {
|
||||||
Some(self.cmp(other))
|
Some(self.cmp(other))
|
||||||
@@ -437,6 +492,27 @@ pub enum Write {
|
|||||||
Statuses,
|
Statuses,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromStr for Write {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Write, Self::Err> {
|
||||||
|
Ok(match s {
|
||||||
|
"accounts" => Write::Accounts,
|
||||||
|
"blocks" => Write::Blocks,
|
||||||
|
"favourites" => Write::Favourites,
|
||||||
|
"filters" => Write::Filters,
|
||||||
|
"follows" => Write::Follows,
|
||||||
|
"lists" => Write::Lists,
|
||||||
|
"media" => Write::Media,
|
||||||
|
"mutes" => Write::Mutes,
|
||||||
|
"notifications" => Write::Notifications,
|
||||||
|
"reports" => Write::Reports,
|
||||||
|
"statuses" => Write::Statuses,
|
||||||
|
_ => return Err(Error::Other("Unknown 'write' subcategory".to_string())),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialOrd for Write {
|
impl PartialOrd for Write {
|
||||||
fn partial_cmp(&self, other: &Write) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Write) -> Option<Ordering> {
|
||||||
Some(self.cmp(other))
|
Some(self.cmp(other))
|
||||||
@@ -664,4 +740,51 @@ mod tests {
|
|||||||
assert_eq!(&ser, &expected);
|
assert_eq!(&ser, &expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_scope_from_str() {
|
||||||
|
let tests = [
|
||||||
|
("read", Scope::Read(None)),
|
||||||
|
("read:accounts", Scope::Read(Some(Read::Accounts))),
|
||||||
|
("read:blocks", Scope::Read(Some(Read::Blocks))),
|
||||||
|
("read:favourites", Scope::Read(Some(Read::Favourites))),
|
||||||
|
("read:filters", Scope::Read(Some(Read::Filters))),
|
||||||
|
("read:follows", Scope::Read(Some(Read::Follows))),
|
||||||
|
("read:lists", Scope::Read(Some(Read::Lists))),
|
||||||
|
("read:mutes", Scope::Read(Some(Read::Mutes))),
|
||||||
|
("read:notifications", Scope::Read(Some(Read::Notifications))),
|
||||||
|
("read:reports", Scope::Read(Some(Read::Reports))),
|
||||||
|
("read:search", Scope::Read(Some(Read::Search))),
|
||||||
|
("read:statuses", Scope::Read(Some(Read::Statuses))),
|
||||||
|
("write", Scope::Write(None)),
|
||||||
|
("write:accounts", Scope::Write(Some(Write::Accounts))),
|
||||||
|
("write:blocks", Scope::Write(Some(Write::Blocks))),
|
||||||
|
("write:favourites", Scope::Write(Some(Write::Favourites))),
|
||||||
|
("write:filters", Scope::Write(Some(Write::Filters))),
|
||||||
|
("write:follows", Scope::Write(Some(Write::Follows))),
|
||||||
|
("write:lists", Scope::Write(Some(Write::Lists))),
|
||||||
|
("write:media", Scope::Write(Some(Write::Media))),
|
||||||
|
("write:mutes", Scope::Write(Some(Write::Mutes))),
|
||||||
|
(
|
||||||
|
"write:notifications",
|
||||||
|
Scope::Write(Some(Write::Notifications)),
|
||||||
|
),
|
||||||
|
("write:reports", Scope::Write(Some(Write::Reports))),
|
||||||
|
("write:statuses", Scope::Write(Some(Write::Statuses))),
|
||||||
|
("follow", Scope::Follow),
|
||||||
|
("push", Scope::Push),
|
||||||
|
];
|
||||||
|
for (source, expected) in &tests {
|
||||||
|
let result = Scope::from_str(source).expect(&format!("Couldn't parse '{}'", &source));
|
||||||
|
assert_eq!(result, *expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_scopes_str_round_trip() {
|
||||||
|
let original = "read write follow push";
|
||||||
|
let scopes = Scopes::from_str(original).expect("Couldn't convert to Scopes");
|
||||||
|
let result = format!("{}", scopes);
|
||||||
|
assert_eq!(original, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user