commit 0cb58add54a85993ba9ff3665df170dfce04972e
parent 92236394e6e55e1078bb044651a4c2b08b6c3f42
Author: Daniel GarcĂa <dani1861994@hotmail.com>
Date: Fri, 4 May 2018 19:25:50 +0200
Implemented some admin methods, inserted CollectionsUsers only when Org accessAll == false, and implemented find_collection when user has access_all in Org
Diffstat:
5 files changed, 106 insertions(+), 62 deletions(-)
diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs
@@ -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)
diff --git a/src/api/core/mod.rs b/src/api/core/mod.rs
@@ -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,
diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs
@@ -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());
+ let mut new_user = UserOrganization::new(user.uuid, org_id.clone());
+
+ new_user.access_all = data.accessAll;
+ new_user.type_ = new_type;
- if data.accessAll {
- new_user.access_all = data.accessAll;
- } else {
- err!("Select collections unimplemented")
- // TODO create Users_collections
+ // 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.type_ = new_type;
-
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, ¤t_user.uuid, &conn) {
+ CollectionUsers::delete(¤t_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(¤t_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, ¤t_user.uuid, &conn) {
+ CollectionUsers::delete(¤t_user.uuid, &c.uuid, &conn);
+ }
Ok(())
}
\ No newline at end of file
diff --git a/src/api/mod.rs b/src/api/mod.rs
@@ -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
+ }
+ }
+}
diff --git a/src/db/models/collection.rs b/src/db/models/collection.rs
@@ -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)
- .filter(users_collections::user_uuid.eq(user_uuid))
+ 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).ok()
- }
+ .load::<Self>(&**conn).expect("Error loading 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)
+ let mut assigned_collections = 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()
+ .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) -> 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,28 +108,25 @@ pub struct CollectionUsers {
pub collection_uuid: String,
}
-/// Local methods
+/// Database methods
impl CollectionUsers {
- pub fn new(
- user_uuid: String,
- collection_uuid: String,
- ) -> Self {
- Self {
- user_uuid,
- collection_uuid,
+ pub fn save(user_uuid: &str, collection_uuid: &str, conn: &DbConn) -> bool {
+ match diesel::replace_into(users_collections::table)
+ .values((
+ users_collections::user_uuid.eq(user_uuid),
+ users_collections::collection_uuid.eq(collection_uuid)
+ )).execute(&**conn) {
+ Ok(1) => true, // One row inserted
+ _ => false,
}
}
-}
-
-use db::schema::users_collections;
-/// Database methods
-impl CollectionUsers {
- pub fn save(&mut self, conn: &DbConn) -> bool {
- match diesel::replace_into(users_collections::table)
- .values(&*self)
+ 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 inserted
+ Ok(1) => true, // One row deleted
_ => false,
}
}