Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resectioning sequences #35

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
441ecbc
Created initial 'it works' test
bookdude13 Aug 13, 2016
f97327b
Restructured into separate tests. 'is-working' tests complete?
bookdude13 Aug 13, 2016
d62314b
Restructured 'all working' test
bookdude13 Aug 14, 2016
33f9ef8
Added more tests. Reorganized again
bookdude13 Aug 14, 2016
9a29661
One more test
bookdude13 Aug 14, 2016
6d34109
Added test for seq sec editor added on perm change. Implemented; passing
bookdude13 Aug 15, 2016
6568a8b
All tests implemented except working and 0 sections
bookdude13 Aug 16, 2016
cf3ef58
Resectioning to 0 sections not allowed
bookdude13 Aug 16, 2016
ed38573
All tests passing
bookdude13 Aug 17, 2016
c93b3c5
Restructured so sequence not returned on resection
bookdude13 Aug 18, 2016
26485bc
Updated README
bookdude13 Aug 18, 2016
a23a9cf
Added debug message
bookdude13 Aug 18, 2016
fbb946b
Converted main code to new permissions api
bookdude13 Aug 19, 2016
1990790
Tests using new api. Removed check for sequence section editor. Some …
bookdude13 Aug 19, 2016
ed51ca4
All tests passing
bookdude13 Aug 19, 2016
66da0e5
Removed editor from sequence_section type
bookdude13 Aug 19, 2016
8aed7fb
Tests now want seq sec in range [0, numSections)
bookdude13 Aug 19, 2016
e23466b
SeqSec now 0-indexed. Removed last traces of editor field
bookdude13 Aug 19, 2016
b640012
Replaced loops with iterators
bookdude13 Aug 19, 2016
043d496
More iter().enumerate()
bookdude13 Aug 19, 2016
0e607d7
Updated README and fixed error in main
bookdude13 Aug 20, 2016
3e9d36f
Removed unnecessary println
bookdude13 Aug 20, 2016
6a31815
PR tweaks
bookdude13 Aug 20, 2016
61892e0
Added checks
bookdude13 Aug 20, 2016
fffeab0
Simplified getting all sections
bookdude13 Aug 20, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@ Command line interface to manipulate ProtonLights projects.
- `remove-sequence <admin-key> <name>`: Removes a sequence and deletes its files
- `id-user <private-key>`: Identify user by ssh key (public key in repo)
- `list-permissions <private-key>`: Get list of user's permissions
- `set-permission <admin-key> (add | remove) <name> <permission> [<target>]`: Change user permissions
- `resection-sequence [TODO]`: (Re-)Section a sequence
- On init, section as section1.
- Number each section, and don't delete.
- Use patch to copy changes.
- Use git --find-renames=100%?
- `set-permission <admin-key> (add | remove) <name> Administrate`: Set admin permission
- `set-permission <admin-key> (add | remove) <name> EditSeq <target-sequence>`: Set permission to edit a sequence
- `set-permission <admin-key> (add | remove) <name> EditSeqSec <target-sequence> <target-section>`: Set permission to edit a sequence section
- `resection-sequence <admin-key> <name> <num-sections>`: (Re-)Section a sequence

Permissions include:
- edit sequence
- edit sequence section
Expand Down
30 changes: 25 additions & 5 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@ pub enum Error {
InvalidPublicKey(String),
InvalidFileName,
InvalidSequenceName(String),
InvalidPermissionTarget,
InvalidSequenceSection(u32),
InvalidPermissionName(String),
InvalidFrameDuration(u32),
InvalidNumSequenceSections(u32),
LoadProjectError,
DuplicateUser(String, String),
DuplicateSequence(String),
MusicFileNotFound(String),
UnsupportedFileType(String),
UserNotFound,
SequenceNotFound(String),
SequenceSectionNotFound(String),
UnauthorizedAction,
TodoErr,
}
Expand All @@ -39,14 +43,18 @@ impl error::Error for Error {
Error::InvalidPublicKey(_) => "Invalid public key",
Error::InvalidFileName => "Invalid file name",
Error::InvalidSequenceName(_) => "Invalid sequence name",
Error::InvalidPermissionTarget => "Invalid permission target",
Error::InvalidSequenceSection(_) => "Invalid sequence section",
Error::InvalidPermissionName(_) => "Invalid permission name",
Error::InvalidFrameDuration(_) => "Invalid frame duration",
Error::InvalidNumSequenceSections(_) => "Invalid number of sequence sections",
Error::LoadProjectError => "Loading project failed",
Error::DuplicateUser(_, _) => "User already exists",
Error::DuplicateSequence(_) => "Sequence already exists",
Error::MusicFileNotFound(_) => "Music file not found",
Error::UnsupportedFileType(_) => "Unsupported file type",
Error::UserNotFound => "User not found",
Error::SequenceNotFound(_) => "Sequence not found",
Error::SequenceSectionNotFound(_) => "Sequence section not found",
Error::UnauthorizedAction => "Unauthorized action",
Error::TodoErr => "Todo",
}
Expand All @@ -63,14 +71,18 @@ impl error::Error for Error {
Error::InvalidPublicKey(_) => None,
Error::InvalidFileName => None,
Error::InvalidSequenceName(_) => None,
Error::InvalidPermissionTarget => None,
Error::InvalidSequenceSection(_) => None,
Error::InvalidPermissionName(_) => None,
Error::InvalidFrameDuration(_) => None,
Error::InvalidNumSequenceSections(_) => None,
Error::LoadProjectError => None,
Error::DuplicateUser(_, _) => None,
Error::DuplicateSequence(_) => None,
Error::MusicFileNotFound(_) => None,
Error::UnsupportedFileType(_) => None,
Error::UserNotFound => None,
Error::SequenceNotFound(_) => None,
Error::SequenceSectionNotFound(_) => None,
Error::UnauthorizedAction => None,
Error::TodoErr => None,
}
Expand Down Expand Up @@ -98,8 +110,14 @@ impl fmt::Display for Error {
"File name provided is invalid and cannot be retrieved"),
Error::InvalidSequenceName(ref seq_name) => write!(f,
"Sequence name had invalid characters: {}", seq_name),
Error::InvalidPermissionTarget => write!(f,
"Invalid permission target provided"),
Error::InvalidSequenceSection(ref section) => write!(f,
"Invalid sequence section: {}", section),
Error::InvalidPermissionName(ref name) => write!(f,
"Invalid permission name provided: {}", name),
Error::InvalidFrameDuration(ref duration) => write!(f,
"Invalid frame duration: {}", duration),
Error::InvalidNumSequenceSections(ref num_sections) => write!(f,
"Invalid number of sequence sections: {}", num_sections),
Error::LoadProjectError => write!(f, "Loading project failed"),
Error::DuplicateUser(ref key, ref user) => write!(f,
"Duplicate user '{}' or key '{}'", user, key),
Expand All @@ -112,6 +130,8 @@ impl fmt::Display for Error {
Error::UserNotFound => write!(f, "User not found"),
Error::SequenceNotFound(ref name) => write!(f,
"Sequence not found: '{}'", name),
Error::SequenceSectionNotFound(ref path) => write!(f,
"Sequence section not found: '{}'", path),
Error::UnauthorizedAction => write!(f, "Unauthorized action"),
Error::TodoErr => write!(f, "TodoErr"),
}
Expand Down
35 changes: 27 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use rustc_serialize::json;
use docopt::Docopt;

use proton_cli::error::Error;
use proton_cli::project_types::PermissionEnum;
use proton_cli::utils;


Expand All @@ -22,9 +21,12 @@ Usage:
./proton remove-user <admin-key> <name>
./proton new-sequence <admin-key> <name> <music-file>
./proton remove-sequence <admin-key> <name>
./proton resection-sequence <admin-key> <name> <num-sections>
./proton id-user <private-key>
./proton list-permissions <private-key>
./proton set-permission <admin-key> (add | remove) <name> <permission> [<target>]
./proton set-permission <admin-key> (add | remove) <name> Administrate
./proton set-permission <admin-key> (add | remove) <name> EditSeq <target-sequence>
./proton set-permission <admin-key> (add | remove) <name> EditSeqSec <target-sequence> <target-section>
./proton (-h | --help)

Options:
Expand All @@ -40,8 +42,9 @@ struct Args {
arg_admin_key: Option<String>,
arg_name: Option<String>,
arg_music_file: Option<String>,
arg_permission: Option<PermissionEnum>,
arg_target: Option<String>,
arg_target_sequence: Option<String>,
arg_target_section: Option<u32>,
arg_num_sections: Option<u32>,
}

fn main() {
Expand All @@ -58,6 +61,7 @@ fn main() {
"id-user" => run_id_user,
"new-sequence" => run_new_sequence,
"remove-sequence" => run_remove_sequence,
"resection-sequence" => run_resection_sequence,
"list-permissions" => run_list_permissions,
"set-permission" => run_set_permission,
_ => panic!("Invalid first argument"),
Expand Down Expand Up @@ -119,6 +123,14 @@ fn run_remove_sequence(args: Args) -> Result<(), Error> {
proton_cli::remove_sequence(&admin_key_path, &name)
}

fn run_resection_sequence(args: Args) -> Result<(), Error> {
let admin_key = args.arg_admin_key.unwrap();
let admin_key_path = Path::new(&admin_key);
let name = args.arg_name.unwrap();
let num_sections = args.arg_num_sections.unwrap();
proton_cli::resection_sequence(&admin_key_path, &name, num_sections)
}

fn run_list_permissions(args: Args) -> Result<(), Error> {
let private_key = args.arg_private_key;
proton_cli::get_permissions(&private_key.unwrap())
Expand All @@ -131,8 +143,15 @@ fn run_set_permission(args: Args) -> Result<(), Error> {

let added = env::args().nth(3).unwrap() == "add";
let username = args.arg_name.unwrap();
let permission = args.arg_permission.unwrap();
let target = args.arg_target;

proton_cli::set_permission(&auth_user, added, &username, permission, target)
let permission_name = env::args().nth(5).unwrap();
let target_sequence = args.arg_target_sequence;
let target_section = args.arg_target_section;

proton_cli::set_permission(
&auth_user,
added,
&username,
&permission_name,
target_sequence,
target_section)
}
12 changes: 7 additions & 5 deletions src/permissions.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@

use std::path::Path;
use std::ascii::AsciiExt;

use git2::Signature;

use error::Error;
use project_types::{User, Permission, PermissionEnum};
use project_types::{User, Permission};
use utils;
use user;

Expand All @@ -13,8 +14,9 @@ pub fn set_permission(
auth_user: &User,
add: bool,
target_username: &str,
permission: PermissionEnum,
target: Option<String>
permission_name: &str,
target_sequence: Option<String>,
target_section: Option<u32>
) -> Result<(), Error> {

// Only admins (those with GrantPerm permission) can change permissions
Expand All @@ -23,12 +25,12 @@ pub fn set_permission(
}

// Make sure root isn't losing admin privileges
if target_username == "root" && !add && permission == PermissionEnum::Administrate {
if target_username == "root" && !add && permission_name.eq_ignore_ascii_case("Administrate") {
return Err(Error::UnauthorizedAction);
}

// Validate and create permission
let perm = try!(Permission::new(permission, target));
let perm = try!(Permission::new(permission_name, target_sequence, target_section));

// Get project that will be modified
let mut project = try!(utils::read_protonfile(None::<&Path>));
Expand Down
2 changes: 1 addition & 1 deletion src/project_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod sequence;
mod sequence_section;
mod user;

pub use self::permissions::{Permission, PermissionEnum};
pub use self::permissions::Permission;
pub use self::project::Project;
pub use self::sequence::Sequence;
pub use self::sequence_section::SequenceSection;
Expand Down
105 changes: 33 additions & 72 deletions src/project_types/permissions.rs
Original file line number Diff line number Diff line change
@@ -1,94 +1,55 @@

use std::path::Path;
use std::ascii::AsciiExt;

use error::Error;
use utils;


#[derive(Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable)]
pub enum PermissionEnum {
pub enum Permission {
Administrate,
EditSeq,
EditSeqSec,
}

#[derive(Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Permission {
pub which: PermissionEnum,
pub target: Option<String>,
EditSeq(String),
EditSeqSec(String, u32),
}

impl Permission {
/// Creates a new Permission, joining a permission type with a target
/// Returns an error if the target is invalid
pub fn new(which_enum: PermissionEnum, t: Option<String>) -> Result<Permission, Error> {
// Make sure the target is valid for the given permission type
try!(Permission::validate_permission(&which_enum, &t));

// Create permission if valid
Ok(Permission {
which: which_enum,
target: t,
})
}

/// Validates the target for the given permission type
/// Returns error if invalid target
fn validate_permission(permission: &PermissionEnum, target: &Option<String>) -> Result<(), Error> {

let valid = match permission {
&PermissionEnum::Administrate => {
target == &None::<String>
},
&PermissionEnum::EditSeq => {
if target.is_none() {
false
/// Creates a new Permission
/// Assumes target options are from Docopt, and are therefore safe to unwrap
/// if the permission name is correct
pub fn new(
perm_name: &str,
target_sequence: Option<String>,
target_section: Option<u32>
) -> Result<Permission, Error> {

match perm_name.to_ascii_lowercase().as_ref() {
"administrate" => Ok(Permission::Administrate),
"editseq" => {
let sequence_name = target_sequence.unwrap();
let project = try!(utils::read_protonfile(None::<&Path>));
if project.find_sequence_by_name(&sequence_name).is_none() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you reverse this if/else? Use is_some instead. Idk, it just feels nicer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to have the errors first. That way the error messages/types are right next to the check that triggered them. It's stylistic preference, so I think keep it like this unless you give me a better reason to switch it.

Err(Error::SequenceNotFound(sequence_name))
} else {
let seq_name = target.to_owned().unwrap();
let project = try!(utils::read_protonfile(None::<&Path>));
project.find_sequence_by_name(&seq_name).is_some()
Ok(Permission::EditSeq(sequence_name))
}
},
&PermissionEnum::EditSeqSec => {
if target.is_none() {
false
"editseqsec" => {
let sequence_name = target_sequence.unwrap();
let section_idx = target_section.unwrap();
let project = try!(utils::read_protonfile(None::<&Path>));
let sequence_opt = project.find_sequence_by_name(&sequence_name);
if sequence_opt.is_none() {
Err(Error::SequenceNotFound(sequence_name))
} else {
let target_str = target.to_owned().unwrap();
let targets: Vec<&str> = target_str.split(",").collect();
if targets.len() != 2 {
println!("EditSeqSec target must be of the form \"name,section\"");
false
let sequence = sequence_opt.unwrap().to_owned();
if !sequence.section_in_range(section_idx) {
Err(Error::InvalidSequenceSection(section_idx))
} else {
let seq_name = targets[0];
let section_num_str = targets[1];
let section_num = match section_num_str.parse::<u32>() {
Ok(n) => n,
Err(_) => return Err(Error::InvalidPermissionTarget),
};
let project = try!(utils::read_protonfile(None::<&Path>));
match project.find_sequence_by_name(&seq_name) {
Some(seq) => {
let in_range = section_num > 0 && section_num <= seq.num_sections;
if !in_range {
println!("EditSeqSec target must be of the form \"name,section\"");
}
in_range
},
None => {
println!("EditSeqSec target must be of the form \"name,section\"");
false
},
}

Ok(Permission::EditSeqSec(sequence_name, section_idx))
}
}
},
};

if valid {
Ok(())
} else {
Err(Error::InvalidPermissionTarget)
_ => Err(Error::InvalidPermissionName(perm_name.to_owned()))
}
}
}
Loading