From 2f9ba4a4e21c1318fa45465a752e06a148b0a334 Mon Sep 17 00:00:00 2001 From: Matlink Date: Wed, 11 Nov 2020 22:20:52 +0100 Subject: [PATCH] Support Manager role --- src/api/core/organizations.rs | 59 +++++++++++++++++++++++++++++------ src/auth.rs | 41 ++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 9 deletions(-) diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index 1d7b99b6..93ce7ca4 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -5,7 +5,7 @@ use serde_json::Value; use crate::{ api::{EmptyResult, JsonResult, JsonUpcase, JsonUpcaseVec, Notify, NumberOrString, PasswordData, UpdateType}, - auth::{decode_invite, AdminHeaders, Headers, OwnerHeaders}, + auth::{decode_invite, AdminHeaders, Headers, OwnerHeaders, ManagerHeaders}, db::{models::*, DbConn}, mail, CONFIG, }; @@ -217,7 +217,7 @@ fn get_org_collections(org_id: String, _headers: AdminHeaders, conn: DbConn) -> #[post("/organizations//collections", data = "")] fn post_organization_collections( org_id: String, - _headers: AdminHeaders, + headers: ManagerHeaders, data: JsonUpcase, conn: DbConn, ) -> JsonResult { @@ -230,6 +230,7 @@ fn post_organization_collections( let collection = Collection::new(org.uuid, data.Name); collection.save(&conn)?; + CollectionUser::save(&headers.user.uuid, &collection.uuid, false, false, &conn)?; Ok(Json(collection.to_json())) } @@ -317,10 +318,14 @@ fn post_organization_collection_delete_user( } #[delete("/organizations//collections/")] -fn delete_organization_collection(org_id: String, col_id: String, _headers: AdminHeaders, conn: DbConn) -> EmptyResult { +fn delete_organization_collection(org_id: String, col_id: String, headers: ManagerHeaders, conn: DbConn) -> EmptyResult { match Collection::find_by_uuid(&col_id, &conn) { None => err!("Collection not found"), Some(collection) => { + match check_manager_in_collection(&org_id, &col_id, &headers.user.uuid, &conn) { + Err(_error) => err!("You have no permission to edit this collection"), + Ok(result) => result, + } if collection.org_uuid == org_id { collection.delete(&conn) } else { @@ -341,7 +346,7 @@ struct DeleteCollectionData { fn post_organization_collection_delete( org_id: String, col_id: String, - headers: AdminHeaders, + headers: ManagerHeaders, _data: JsonUpcase, conn: DbConn, ) -> EmptyResult { @@ -349,7 +354,12 @@ fn post_organization_collection_delete( } #[get("/organizations//collections//details")] -fn get_org_collection_detail(org_id: String, coll_id: String, headers: AdminHeaders, conn: DbConn) -> JsonResult { +fn get_org_collection_detail(org_id: String, coll_id: String, headers: ManagerHeaders, conn: DbConn) -> JsonResult { + match check_manager_in_collection(&org_id, &coll_id, &headers.user.uuid, &conn) { + Err(_error) => err!("You have no permission to edit this collection"), + Ok(result) => result, + } + match Collection::find_by_uuid_and_user(&coll_id, &headers.user.uuid, &conn) { None => err!("Collection not found"), Some(collection) => { @@ -363,13 +373,18 @@ fn get_org_collection_detail(org_id: String, coll_id: String, headers: AdminHead } #[get("/organizations//collections//users")] -fn get_collection_users(org_id: String, coll_id: String, _headers: AdminHeaders, conn: DbConn) -> JsonResult { +fn get_collection_users(org_id: String, coll_id: String, headers: ManagerHeaders, conn: DbConn) -> JsonResult { // Get org and collection, check that collection is from org let collection = match Collection::find_by_uuid_and_org(&coll_id, &org_id, &conn) { None => err!("Collection not found in Organization"), Some(collection) => collection, }; + match check_manager_in_collection(&org_id, &coll_id, &headers.user.uuid, &conn) { + Err(_error) => err!("You have no permission to edit this collection"), + Ok(result) => result, + } + // Get the users from collection let user_list: Vec = CollectionUser::find_by_collection(&collection.uuid, &conn) .iter() @@ -388,7 +403,7 @@ fn put_collection_users( org_id: String, coll_id: String, data: JsonUpcaseVec, - _headers: AdminHeaders, + headers: ManagerHeaders, conn: DbConn, ) -> EmptyResult { // Get org and collection, check that collection is from org @@ -396,6 +411,12 @@ fn put_collection_users( err!("Collection not found in Organization") } + match check_manager_in_collection(&org_id, &coll_id, &headers.user.uuid, &conn) { + Err(_error) => err!("You have no permission to edit this collection"), + Ok(result) => result, + } + + // Delete all the user-collections CollectionUser::delete_all_by_collection(&coll_id, &conn)?; @@ -440,7 +461,7 @@ fn get_org_details(data: Form, headers: Headers, conn: DbConn) -> Jso } #[get("/organizations//users")] -fn get_org_users(org_id: String, _headers: AdminHeaders, conn: DbConn) -> JsonResult { +fn get_org_users(org_id: String, _headers: ManagerHeaders, conn: DbConn) -> JsonResult { let users = UserOrganization::find_by_org(&org_id, &conn); let users_json: Vec = users.iter().map(|c| c.to_json_user_details(&conn)).collect(); @@ -1043,4 +1064,24 @@ fn get_plans(_headers: Headers, _conn: DbConn) -> JsonResult { ], "ContinuationToken": null }))) -} \ No newline at end of file +} + +fn check_manager_in_collection(org_id: &str, col_id: &str, user_id: &str, conn: &DbConn) -> EmptyResult { + // Check current manager is in collection + let col_user = match CollectionUser::find_by_collection_and_user(&col_id, &user_id, &conn) { + None => err!("Manager not in Collection"), + Some(col_user) => col_user, + }; + + // Check current manager is manager of that the org + let user_org = match UserOrganization::find_by_user_and_org(&col_user.user_uuid, &org_id, &conn) { + None => err!("User is not manager of the Organisation"), + Some(user_org) => user_org, + }; + if user_org.atype != UserOrgType::Manager { + err!("Current user is not manager") + } + Ok(()) +} + + diff --git a/src/auth.rs b/src/auth.rs index da6f8fa4..1c994567 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -379,6 +379,47 @@ impl<'a, 'r> FromRequest<'a, 'r> for OrgHeaders { } } +pub struct ManagerHeaders { + pub host: String, + pub device: Device, + pub user: User, + pub org_user_type: UserOrgType, +} + +impl<'a, 'r> FromRequest<'a, 'r> for ManagerHeaders { + type Error = &'static str; + + fn from_request(request: &'a Request<'r>) -> Outcome { + match request.guard::() { + Outcome::Forward(_) => Outcome::Forward(()), + Outcome::Failure(f) => Outcome::Failure(f), + Outcome::Success(headers) => { + if headers.org_user_type >= UserOrgType::Manager { + Outcome::Success(Self { + host: headers.host, + device: headers.device, + user: headers.user, + org_user_type: headers.org_user_type, + }) + } else { + err_handler!("You need to be Manager, Admin or Owner to call this endpoint") + } + } + } + } +} + +impl Into for ManagerHeaders { + fn into(self) -> Headers { + Headers { + host: self.host, + device: self.device, + user: self.user, + } + } +} + + pub struct AdminHeaders { pub host: String, pub device: Device,