|
|
@ -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); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|