Improved access level tracking as per #3, but more improvements are
necessary still.
This commit is contained in:
parent
3fdd58e695
commit
116ac10e48
3 changed files with 146 additions and 38 deletions
|
@ -5,7 +5,7 @@ pub use data::command::Command;
|
|||
pub use data::config::Config;
|
||||
pub use data::message::Message;
|
||||
pub use data::response::Response;
|
||||
pub use data::user::User;
|
||||
pub use data::user::{AccessLevel, User};
|
||||
|
||||
pub mod kinds {
|
||||
//! Trait definitions of appropriate Writers and Buffers for use with this library.
|
||||
|
|
169
src/data/user.rs
169
src/data/user.rs
|
@ -7,11 +7,11 @@ use std::str::FromStr;
|
|||
#[deriving(Clone, Show)]
|
||||
pub struct User {
|
||||
/// The user's nickname.
|
||||
/// This is the only detail used in determining the equality of two users.
|
||||
name: String,
|
||||
/// The user's access level.
|
||||
/// For simplicity, this is not used to determine the equality of two users.
|
||||
/// That is a user is equal if and only if their nickname is the same.
|
||||
access_level: AccessLevel,
|
||||
/// The user's highest access level.
|
||||
highest_access_level: AccessLevel,
|
||||
access_levels: Vec<AccessLevel>,
|
||||
}
|
||||
|
||||
impl User {
|
||||
|
@ -25,7 +25,12 @@ impl User {
|
|||
} else {
|
||||
name[1..].into_string()
|
||||
},
|
||||
access_level: rank.unwrap(),
|
||||
highest_access_level: rank.unwrap(),
|
||||
access_levels: if let Some(AccessLevel::Member) = rank {
|
||||
vec![rank.unwrap()]
|
||||
} else {
|
||||
vec![rank.unwrap(), AccessLevel::Member]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,27 +40,57 @@ impl User {
|
|||
self.name[]
|
||||
}
|
||||
|
||||
/// Gets the user's access level.
|
||||
/// Gets the user's highest access level.
|
||||
#[experimental]
|
||||
pub fn access_level(&self) -> AccessLevel {
|
||||
self.access_level
|
||||
pub fn highest_access_level(&self) -> AccessLevel {
|
||||
self.highest_access_level
|
||||
}
|
||||
|
||||
/// Gets all the user's access levels.
|
||||
#[experimental]
|
||||
pub fn access_levels(&self) -> Vec<AccessLevel> {
|
||||
self.access_levels.clone()
|
||||
}
|
||||
|
||||
/// Updates the user's access level.
|
||||
#[unstable]
|
||||
pub fn update_access_level(&mut self, mode: &str) {
|
||||
self.access_level = match mode {
|
||||
"+q" => AccessLevel::Owner,
|
||||
"-q" => AccessLevel::Member,
|
||||
"+a" => AccessLevel::Admin,
|
||||
"-a" => AccessLevel::Member,
|
||||
"+o" => AccessLevel::Oper,
|
||||
"-o" => AccessLevel::Member,
|
||||
"+h" => AccessLevel::HalfOp,
|
||||
"-h" => AccessLevel::Member,
|
||||
"+v" => AccessLevel::Voice,
|
||||
"-v" => AccessLevel::Member,
|
||||
_ => self.access_level,
|
||||
match mode {
|
||||
"+q" => self.add_access_level(AccessLevel::Owner),
|
||||
"-q" => self.sub_access_level(AccessLevel::Owner),
|
||||
"+a" => self.add_access_level(AccessLevel::Admin),
|
||||
"-a" => self.sub_access_level(AccessLevel::Admin),
|
||||
"+o" => self.add_access_level(AccessLevel::Oper),
|
||||
"-o" => self.sub_access_level(AccessLevel::Oper),
|
||||
"+h" => self.add_access_level(AccessLevel::HalfOp),
|
||||
"-h" => self.sub_access_level(AccessLevel::HalfOp),
|
||||
"+v" => self.add_access_level(AccessLevel::Voice),
|
||||
"-v" => self.sub_access_level(AccessLevel::Voice),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn add_access_level(&mut self, level: AccessLevel) {
|
||||
if level > self.highest_access_level() {
|
||||
self.highest_access_level = level
|
||||
}
|
||||
self.access_levels.push(level.clone())
|
||||
}
|
||||
|
||||
fn sub_access_level(&mut self, level: AccessLevel) {
|
||||
if let Some(n) = self.access_levels[].position_elem(&level) {
|
||||
self.access_levels.swap_remove(n);
|
||||
}
|
||||
if level == self.highest_access_level() {
|
||||
self.highest_access_level = {
|
||||
let mut max = AccessLevel::Member;
|
||||
for level in self.access_levels.iter() {
|
||||
if level > &max {
|
||||
max = level.clone()
|
||||
}
|
||||
}
|
||||
max
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +119,44 @@ pub enum AccessLevel {
|
|||
Member,
|
||||
}
|
||||
|
||||
impl PartialOrd for AccessLevel {
|
||||
fn partial_cmp(&self, other: &AccessLevel) -> Option<Ordering> {
|
||||
if self == other { return Some(Equal) }
|
||||
match self {
|
||||
&AccessLevel::Owner => Some(Greater),
|
||||
&AccessLevel::Admin => {
|
||||
if other == &AccessLevel::Owner {
|
||||
Some(Less)
|
||||
} else {
|
||||
Some(Greater)
|
||||
}
|
||||
},
|
||||
&AccessLevel::Oper => {
|
||||
if other == &AccessLevel::Owner || other == &AccessLevel::Admin {
|
||||
Some(Less)
|
||||
} else {
|
||||
Some(Greater)
|
||||
}
|
||||
},
|
||||
&AccessLevel::HalfOp => {
|
||||
if other == &AccessLevel::Voice || other == &AccessLevel::Member {
|
||||
Some(Greater)
|
||||
} else {
|
||||
Some(Less)
|
||||
}
|
||||
},
|
||||
&AccessLevel::Voice => {
|
||||
if other == &AccessLevel::Member {
|
||||
Some(Greater)
|
||||
} else {
|
||||
Some(Less)
|
||||
}
|
||||
},
|
||||
&AccessLevel::Member => Some(Less),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for AccessLevel {
|
||||
fn from_str(s: &str) -> Option<AccessLevel> {
|
||||
if s.len() == 0 { Some(AccessLevel::Member) } else {
|
||||
|
@ -120,10 +193,11 @@ mod test {
|
|||
let user = User::new("~owner");
|
||||
let exp = User {
|
||||
name: format!("owner"),
|
||||
access_level: Owner,
|
||||
highest_access_level: Owner,
|
||||
access_levels: vec![Owner, Member],
|
||||
};
|
||||
assert_eq!(user, exp);
|
||||
assert_eq!(user.access_level, exp.access_level);
|
||||
assert_eq!(user.highest_access_level, exp.highest_access_level);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -135,32 +209,59 @@ mod test {
|
|||
#[test]
|
||||
fn access_level() {
|
||||
let user = User::new("~owner");
|
||||
assert_eq!(user.access_level(), Owner);
|
||||
assert_eq!(user.highest_access_level(), Owner);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_user_rank() {
|
||||
let mut user = User::new("user");
|
||||
assert_eq!(user.access_level, Member);
|
||||
assert_eq!(user.highest_access_level, Member);
|
||||
user.update_access_level("+q");
|
||||
assert_eq!(user.access_level, Owner);
|
||||
assert_eq!(user.highest_access_level, Owner);
|
||||
user.update_access_level("-q");
|
||||
assert_eq!(user.access_level, Member);
|
||||
assert_eq!(user.highest_access_level, Member);
|
||||
user.update_access_level("+a");
|
||||
assert_eq!(user.access_level, Admin);
|
||||
assert_eq!(user.highest_access_level, Admin);
|
||||
user.update_access_level("-a");
|
||||
assert_eq!(user.access_level, Member);
|
||||
assert_eq!(user.highest_access_level, Member);
|
||||
user.update_access_level("+o");
|
||||
assert_eq!(user.access_level, Oper);
|
||||
assert_eq!(user.highest_access_level, Oper);
|
||||
user.update_access_level("-o");
|
||||
assert_eq!(user.access_level, Member);
|
||||
assert_eq!(user.highest_access_level, Member);
|
||||
user.update_access_level("+h");
|
||||
assert_eq!(user.access_level, HalfOp);
|
||||
assert_eq!(user.highest_access_level, HalfOp);
|
||||
user.update_access_level("-h");
|
||||
assert_eq!(user.access_level, Member);
|
||||
assert_eq!(user.highest_access_level, Member);
|
||||
user.update_access_level("+v");
|
||||
assert_eq!(user.access_level, Voice);
|
||||
assert_eq!(user.highest_access_level, Voice);
|
||||
user.update_access_level("-v");
|
||||
assert_eq!(user.access_level, Member);
|
||||
assert_eq!(user.highest_access_level, Member);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derank_user_in_full() {
|
||||
let mut user = User::new("user");
|
||||
user.update_access_level("+q");
|
||||
user.update_access_level("+a");
|
||||
user.update_access_level("+o");
|
||||
user.update_access_level("+h");
|
||||
user.update_access_level("+v");
|
||||
assert_eq!(user.highest_access_level, Owner);
|
||||
assert_eq!(user.access_levels, vec![Member, Owner, Admin, Oper, HalfOp, Voice]);
|
||||
user.update_access_level("-h");
|
||||
assert_eq!(user.highest_access_level, Owner);
|
||||
assert_eq!(user.access_levels, vec![Member, Owner, Admin, Oper, Voice]);
|
||||
user.update_access_level("-q");
|
||||
assert_eq!(user.highest_access_level, Admin);
|
||||
assert_eq!(user.access_levels, vec![Member, Voice, Admin, Oper]);
|
||||
user.update_access_level("-a");
|
||||
assert_eq!(user.highest_access_level, Oper);
|
||||
assert_eq!(user.access_levels, vec![Member, Voice, Oper]);
|
||||
user.update_access_level("-o");
|
||||
assert_eq!(user.highest_access_level, Voice);
|
||||
assert_eq!(user.access_levels, vec![Member, Voice]);
|
||||
user.update_access_level("-v");
|
||||
assert_eq!(user.highest_access_level, Member);
|
||||
assert_eq!(user.access_levels, vec![Member]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -339,7 +339,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn user_tracking_names_mode() {
|
||||
let value = ":irc.test.net 353 test = #test :test ~owner &admin\r\n\
|
||||
let value = ":irc.test.net 353 test = #test :+test ~owner &admin\r\n\
|
||||
:test!test@test MODE #test +o test\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), Connection::new(
|
||||
MemReader::new(value.as_bytes().to_vec()), NullWriter
|
||||
|
@ -349,7 +349,14 @@ mod test {
|
|||
}
|
||||
assert_eq!(server.list_users("#test").unwrap(),
|
||||
vec![User::new("@test"), User::new("~owner"), User::new("&admin")]);
|
||||
assert_eq!(server.list_users("#test").unwrap()[0].access_level(),
|
||||
User::new("@test").access_level());
|
||||
let mut exp = User::new("@test");
|
||||
exp.update_access_level("+v");
|
||||
assert_eq!(server.list_users("#test").unwrap()[0].highest_access_level(),
|
||||
exp.highest_access_level());
|
||||
// The following tests if the maintained user contains the same entries as what is expected
|
||||
// but ignores the ordering of these entries.
|
||||
let mut levels = server.list_users("#test").unwrap()[0].access_levels();
|
||||
levels.retain(|l| exp.access_levels().contains(l));
|
||||
assert_eq!(levels.len(), exp.access_levels().len());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue