Implemented some admin methods, inserted CollectionsUsers only when Org accessAll == false, and implemented find_collection when user has access_all in Org

This commit is contained in:
Daniel García 2018-05-04 19:25:50 +02:00
parent 92236394e6
commit 0cb58add54
5 changed files with 108 additions and 64 deletions

View File

@ -69,6 +69,12 @@ fn get_cipher(uuid: String, headers: Headers, conn: DbConn) -> JsonResult {
Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, &conn)))
}
#[get("/ciphers/<uuid>/admin")]
fn get_cipher_admin(uuid: String, headers: Headers, conn: DbConn) -> JsonResult {
// TODO: Implement this correctly
get_cipher(uuid, headers, conn)
}
#[derive(Deserialize, Debug)]
#[allow(non_snake_case)]
struct CipherData {
@ -100,6 +106,7 @@ struct CipherData {
#[post("/ciphers/admin", data = "<data>")]
fn post_ciphers_admin(data: Json<CipherData>, headers: Headers, conn: DbConn) -> JsonResult {
// TODO: Implement this correctly
post_ciphers(data, headers, conn)
}
@ -230,8 +237,8 @@ fn post_ciphers_import(data: Json<ImportData>, headers: Headers, conn: DbConn) -
let data: ImportData = data.into_inner();
// Read and create the folders
let folders: Vec<_> = data.folders.iter().map(|folder| {
let mut folder = Folder::new(headers.user.uuid.clone(), folder.name.clone());
let folders: Vec<_> = data.folders.into_iter().map(|folder| {
let mut folder = Folder::new(headers.user.uuid.clone(), folder.name);
folder.save(&conn);
folder
}).collect();
@ -261,6 +268,12 @@ fn post_ciphers_import(data: Json<ImportData>, headers: Headers, conn: DbConn) -
Ok(())
}
#[post("/ciphers/<uuid>/admin", data = "<data>")]
fn post_cipher_admin(uuid: String, data: Json<CipherData>, headers: Headers, conn: DbConn) -> JsonResult {
// TODO: Implement this correctly
post_cipher(uuid, data, headers, conn)
}
#[post("/ciphers/<uuid>", data = "<data>")]
fn post_cipher(uuid: String, data: Json<CipherData>, headers: Headers, conn: DbConn) -> JsonResult {
put_cipher(uuid, data, headers, conn)

View File

@ -26,12 +26,14 @@ pub fn routes() -> Vec<Route> {
get_ciphers,
get_cipher,
get_cipher_admin,
post_ciphers,
post_ciphers_admin,
post_ciphers_import,
post_attachment,
delete_attachment_post,
delete_attachment,
post_cipher_admin,
post_cipher,
put_cipher,
delete_cipher_post,

View File

@ -5,7 +5,7 @@ use rocket_contrib::{Json, Value};
use db::DbConn;
use db::models::*;
use api::{PasswordData, JsonResult, EmptyResult};
use api::{PasswordData, JsonResult, EmptyResult, NumberOrString};
use auth::Headers;
@ -41,10 +41,6 @@ fn create_organization(headers: Headers, data: Json<OrgData>, conn: DbConn) -> J
headers.user.uuid.clone(), org.uuid.clone());
let mut collection = Collection::new(
org.uuid.clone(), data.collectionName);
let mut collection_user = CollectionUsers::new(
headers.user.uuid.clone(),
collection.uuid.clone(),
);
user_org.key = data.key;
user_org.access_all = true;
@ -54,7 +50,6 @@ fn create_organization(headers: Headers, data: Json<OrgData>, conn: DbConn) -> J
org.save(&conn);
user_org.save(&conn);
collection.save(&conn);
collection_user.save(&conn);
Ok(Json(org.to_json()))
}
@ -64,6 +59,8 @@ fn delete_organization(org_id: String, data: Json<PasswordData>, headers: Header
let data: PasswordData = data.into_inner();
let password_hash = data.masterPasswordHash;
// TODO: Delete ciphers from organization, collection_users, collections, organization_users and the org itself
unimplemented!()
}
@ -109,7 +106,6 @@ fn get_user_collections(headers: Headers, conn: DbConn) -> JsonResult {
Ok(Json(json!({
"Data":
Collection::find_by_user_uuid(&headers.user.uuid, &conn)
.expect("Error loading collections")
.iter()
.map(|collection| {
collection.to_json()
@ -123,7 +119,6 @@ fn get_org_collections(org_id: String, headers: Headers, conn: DbConn) -> JsonRe
Ok(Json(json!({
"Data":
Collection::find_by_organization_and_user_uuid(&org_id, &headers.user.uuid, &conn)
.unwrap_or(vec![])
.iter()
.map(|collection| {
collection.to_json()
@ -136,10 +131,12 @@ fn get_org_collections(org_id: String, headers: Headers, conn: DbConn) -> JsonRe
fn post_organization_collections(org_id: String, headers: Headers, data: Json<NewCollectionData>, conn: DbConn) -> JsonResult {
let data: NewCollectionData = data.into_inner();
match UserOrganization::find_by_user_and_org( &headers.user.uuid, &org_id, &conn) {
let org_user = match UserOrganization::find_by_user_and_org( &headers.user.uuid, &org_id, &conn) {
None => err!("User not in Organization or Organization doesn't exist"),
Some(org_user) => if org_user.type_ > 1 { // not owner or admin
Some(org_user) => if org_user.type_ == UserOrgType::User as i32 {
err!("Only Organization owner and admin can add Collection")
} else {
org_user
}
};
@ -149,13 +146,12 @@ fn post_organization_collections(org_id: String, headers: Headers, data: Json<Ne
};
let mut collection = Collection::new(org.uuid.clone(), data.name);
let mut collection_user = CollectionUsers::new(
headers.user.uuid.clone(),
collection.uuid.clone(),
);
collection.save(&conn);
collection_user.save(&conn);
if !org_user.access_all {
CollectionUsers::save(&headers.user.uuid, &collection.uuid, &conn);
}
Ok(Json(collection.to_json()))
}
@ -267,7 +263,7 @@ struct CollectionData {
struct InviteData {
emails: Vec<String>,
#[serde(rename = "type")]
type_: String,
type_: NumberOrString,
collections: Vec<CollectionData>,
accessAll: bool,
}
@ -285,7 +281,7 @@ fn send_invite(org_id: String, data: Json<InviteData>, headers: Headers, conn: D
err!("Users can't invite other people. Ask an Admin or Owner")
}
let new_type = match UserOrgType::from_str(data.type_.as_ref()) {
let new_type = match UserOrgType::from_str(&data.type_.to_string()) {
Some(new_type) => new_type as i32,
None => err!("Invalid type")
};
@ -304,18 +300,21 @@ fn send_invite(org_id: String, data: Json<InviteData>, headers: Headers, conn: D
None => ()
}
let mut new_user = UserOrganization::new(
user.uuid, org_id.clone());
if data.accessAll {
new_user.access_all = data.accessAll;
} else {
err!("Select collections unimplemented")
// TODO create Users_collections
}
let mut new_user = UserOrganization::new(user.uuid, org_id.clone());
new_user.access_all = data.accessAll;
new_user.type_ = new_type;
// If no accessAll, add the collections received
if !data.accessAll {
for collection in data.collections.iter() {
// TODO: Check that collection is in org
// TODO: Save the readOnly bit
CollectionUsers::save(&headers.user.uuid, &collection.id, &conn);
}
}
new_user.save(&conn);
}
}
@ -381,7 +380,7 @@ fn get_user(org_id: String, user_id: String, headers: Headers, conn: DbConn) ->
#[allow(non_snake_case)]
struct EditUserData {
#[serde(rename = "type")]
type_: String,
type_: NumberOrString,
collections: Vec<CollectionData>,
accessAll: bool,
}
@ -396,7 +395,7 @@ fn edit_user(org_id: String, user_id: String, data: Json<EditUserData>, headers:
None => err!("The current user isn't member of the organization")
};
let new_type = match UserOrgType::from_str(data.type_.as_ref()) {
let new_type = match UserOrgType::from_str(&data.type_.to_string()) {
Some(new_type) => new_type as i32,
None => err!("Invalid type")
};
@ -436,10 +435,19 @@ fn edit_user(org_id: String, user_id: String, data: Json<EditUserData>, headers:
user_to_edit.access_all = data.accessAll;
user_to_edit.type_ = new_type;
if data.accessAll {
// Remove users_collections if there is any
} else {
// TODO create users_collections
// Delete all the odd collections
for c in Collection::find_by_organization_and_user_uuid(&org_id, &current_user.uuid, &conn) {
CollectionUsers::delete(&current_user.uuid, &c.uuid, &conn);
}
// If no accessAll, add the collections received
if !data.accessAll {
for collection in data.collections.iter() {
// TODO: Check that collection is in org
// TODO: Save the readOnly bit
CollectionUsers::save(&current_user.uuid, &collection.id, &conn);
}
}
user_to_edit.save(&conn);
@ -482,7 +490,9 @@ fn delete_user(org_id: String, user_id: String, headers: Headers, conn: DbConn)
user_to_delete.delete(&conn);
// TODO Delete users_collections from this org
for c in Collection::find_by_organization_and_user_uuid(&org_id, &current_user.uuid, &conn) {
CollectionUsers::delete(&current_user.uuid, &c.uuid, &conn);
}
Ok(())
}

View File

@ -21,3 +21,19 @@ type EmptyResult = Result<(), BadRequest<Json>>;
struct PasswordData {
masterPasswordHash: String
}
#[derive(Deserialize)]
#[serde(untagged)]
enum NumberOrString {
Number(i32),
String(String),
}
impl NumberOrString {
fn to_string(self) -> String {
match self {
NumberOrString::Number(n) => n.to_string(),
NumberOrString::String(s) => s
}
}
}

View File

@ -38,7 +38,7 @@ impl Collection {
use diesel;
use diesel::prelude::*;
use db::DbConn;
use db::schema::collections;
use db::schema::*;
/// Database methods
impl Collection {
@ -66,19 +66,25 @@ impl Collection {
.first::<Self>(&**conn).ok()
}
pub fn find_by_user_uuid(user_uuid: &str, conn: &DbConn) -> Option<Vec<Self>> {
users_collections::table.inner_join(collections::table)
pub fn find_by_user_uuid(user_uuid: &str, conn: &DbConn) -> Vec<Self> {
let mut all_access_collections = users_organizations::table
.filter(users_organizations::user_uuid.eq(user_uuid))
.filter(users_organizations::access_all.eq(true))
.inner_join(collections::table.on(collections::org_uuid.eq(users_organizations::org_uuid)))
.select(collections::all_columns)
.load::<Self>(&**conn).expect("Error loading collections");
let mut assigned_collections = users_collections::table.inner_join(collections::table)
.filter(users_collections::user_uuid.eq(user_uuid))
.select(collections::all_columns)
.load::<Self>(&**conn).ok()
.load::<Self>(&**conn).expect("Error loading collections");
all_access_collections.append(&mut assigned_collections);
all_access_collections
}
pub fn find_by_organization_and_user_uuid(org_uuid: &str, user_uuid: &str, conn: &DbConn) -> Option<Vec<Self>> {
users_collections::table.inner_join(collections::table)
.filter(users_collections::user_uuid.eq(user_uuid))
.filter(collections::org_uuid.eq(org_uuid))
.select(collections::all_columns)
.load::<Self>(&**conn).ok()
pub fn find_by_organization_and_user_uuid(org_uuid: &str, user_uuid: &str, conn: &DbConn) -> Vec<Self> {
Self::find_by_user_uuid(user_uuid, conn).into_iter().filter(|c| c.org_uuid == org_uuid).collect()
}
pub fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &DbConn) -> Option<Self> {
@ -102,29 +108,26 @@ pub struct CollectionUsers {
pub collection_uuid: String,
}
/// Local methods
impl CollectionUsers {
pub fn new(
user_uuid: String,
collection_uuid: String,
) -> Self {
Self {
user_uuid,
collection_uuid,
}
}
}
use db::schema::users_collections;
/// Database methods
impl CollectionUsers {
pub fn save(&mut self, conn: &DbConn) -> bool {
pub fn save(user_uuid: &str, collection_uuid: &str, conn: &DbConn) -> bool {
match diesel::replace_into(users_collections::table)
.values(&*self)
.execute(&**conn) {
.values((
users_collections::user_uuid.eq(user_uuid),
users_collections::collection_uuid.eq(collection_uuid)
)).execute(&**conn) {
Ok(1) => true, // One row inserted
_ => false,
}
}
pub fn delete(user_uuid: &str, collection_uuid: &str, conn: &DbConn) -> bool {
match diesel::delete(users_collections::table
.filter(users_collections::user_uuid.eq(user_uuid))
.filter(users_collections::collection_uuid.eq(collection_uuid)))
.execute(&**conn) {
Ok(1) => true, // One row deleted
_ => false,
}
}
}