|
@ -5,11 +5,11 @@ use serde_json::Value; |
|
|
|
|
|
|
|
|
use crate::{ |
|
|
use crate::{ |
|
|
api::{ |
|
|
api::{ |
|
|
core::{CipherSyncData, CipherSyncType}, |
|
|
core::{log_event, CipherSyncData, CipherSyncType}, |
|
|
ApiResult, EmptyResult, JsonResult, JsonUpcase, JsonUpcaseVec, JsonVec, Notify, NumberOrString, PasswordData, |
|
|
ApiResult, EmptyResult, JsonResult, JsonUpcase, JsonUpcaseVec, JsonVec, Notify, NumberOrString, PasswordData, |
|
|
UpdateType, |
|
|
UpdateType, |
|
|
}, |
|
|
}, |
|
|
auth::{decode_invite, AdminHeaders, Headers, ManagerHeaders, ManagerHeadersLoose, OwnerHeaders}, |
|
|
auth::{decode_invite, AdminHeaders, ClientIp, Headers, ManagerHeaders, ManagerHeadersLoose, OwnerHeaders}, |
|
|
db::{models::*, DbConn}, |
|
|
db::{models::*, DbConn}, |
|
|
error::Error, |
|
|
error::Error, |
|
|
mail, |
|
|
mail, |
|
@ -203,7 +203,7 @@ async fn post_delete_organization( |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[post("/organizations/<org_id>/leave")] |
|
|
#[post("/organizations/<org_id>/leave")] |
|
|
async fn leave_organization(org_id: String, headers: Headers, mut conn: DbConn) -> EmptyResult { |
|
|
async fn leave_organization(org_id: String, headers: Headers, mut conn: DbConn, ip: ClientIp) -> EmptyResult { |
|
|
match UserOrganization::find_by_user_and_org(&headers.user.uuid, &org_id, &mut conn).await { |
|
|
match UserOrganization::find_by_user_and_org(&headers.user.uuid, &org_id, &mut conn).await { |
|
|
None => err!("User not part of organization"), |
|
|
None => err!("User not part of organization"), |
|
|
Some(user_org) => { |
|
|
Some(user_org) => { |
|
@ -213,6 +213,17 @@ async fn leave_organization(org_id: String, headers: Headers, mut conn: DbConn) |
|
|
err!("The last owner can't leave") |
|
|
err!("The last owner can't leave") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUserRemoved as i32, |
|
|
|
|
|
&user_org.uuid, |
|
|
|
|
|
org_id, |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
user_org.delete(&mut conn).await |
|
|
user_org.delete(&mut conn).await |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -232,16 +243,18 @@ async fn put_organization( |
|
|
headers: OwnerHeaders, |
|
|
headers: OwnerHeaders, |
|
|
data: JsonUpcase<OrganizationUpdateData>, |
|
|
data: JsonUpcase<OrganizationUpdateData>, |
|
|
conn: DbConn, |
|
|
conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> JsonResult { |
|
|
) -> JsonResult { |
|
|
post_organization(org_id, headers, data, conn).await |
|
|
post_organization(org_id, headers, data, conn, ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[post("/organizations/<org_id>", data = "<data>")] |
|
|
#[post("/organizations/<org_id>", data = "<data>")] |
|
|
async fn post_organization( |
|
|
async fn post_organization( |
|
|
org_id: String, |
|
|
org_id: String, |
|
|
_headers: OwnerHeaders, |
|
|
headers: OwnerHeaders, |
|
|
data: JsonUpcase<OrganizationUpdateData>, |
|
|
data: JsonUpcase<OrganizationUpdateData>, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> JsonResult { |
|
|
) -> JsonResult { |
|
|
let data: OrganizationUpdateData = data.into_inner().data; |
|
|
let data: OrganizationUpdateData = data.into_inner().data; |
|
|
|
|
|
|
|
@ -254,6 +267,18 @@ async fn post_organization( |
|
|
org.billing_email = data.BillingEmail; |
|
|
org.billing_email = data.BillingEmail; |
|
|
|
|
|
|
|
|
org.save(&mut conn).await?; |
|
|
org.save(&mut conn).await?; |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUpdated as i32, |
|
|
|
|
|
&org_id, |
|
|
|
|
|
org_id.clone(), |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
Ok(Json(org.to_json())) |
|
|
Ok(Json(org.to_json())) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -290,6 +315,7 @@ async fn post_organization_collections( |
|
|
headers: ManagerHeadersLoose, |
|
|
headers: ManagerHeadersLoose, |
|
|
data: JsonUpcase<NewCollectionData>, |
|
|
data: JsonUpcase<NewCollectionData>, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> JsonResult { |
|
|
) -> JsonResult { |
|
|
let data: NewCollectionData = data.into_inner().data; |
|
|
let data: NewCollectionData = data.into_inner().data; |
|
|
|
|
|
|
|
@ -307,6 +333,17 @@ async fn post_organization_collections( |
|
|
let collection = Collection::new(org.uuid, data.Name); |
|
|
let collection = Collection::new(org.uuid, data.Name); |
|
|
collection.save(&mut conn).await?; |
|
|
collection.save(&mut conn).await?; |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::CollectionCreated as i32, |
|
|
|
|
|
&collection.uuid, |
|
|
|
|
|
org_id, |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
for group in data.Groups { |
|
|
for group in data.Groups { |
|
|
CollectionGroup::new(collection.uuid.clone(), group.Id, group.ReadOnly, group.HidePasswords) |
|
|
CollectionGroup::new(collection.uuid.clone(), group.Id, group.ReadOnly, group.HidePasswords) |
|
|
.save(&mut conn) |
|
|
.save(&mut conn) |
|
@ -330,17 +367,19 @@ async fn put_organization_collection_update( |
|
|
headers: ManagerHeaders, |
|
|
headers: ManagerHeaders, |
|
|
data: JsonUpcase<NewCollectionData>, |
|
|
data: JsonUpcase<NewCollectionData>, |
|
|
conn: DbConn, |
|
|
conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> JsonResult { |
|
|
) -> JsonResult { |
|
|
post_organization_collection_update(org_id, col_id, headers, data, conn).await |
|
|
post_organization_collection_update(org_id, col_id, headers, data, conn, ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[post("/organizations/<org_id>/collections/<col_id>", data = "<data>")] |
|
|
#[post("/organizations/<org_id>/collections/<col_id>", data = "<data>")] |
|
|
async fn post_organization_collection_update( |
|
|
async fn post_organization_collection_update( |
|
|
org_id: String, |
|
|
org_id: String, |
|
|
col_id: String, |
|
|
col_id: String, |
|
|
_headers: ManagerHeaders, |
|
|
headers: ManagerHeaders, |
|
|
data: JsonUpcase<NewCollectionData>, |
|
|
data: JsonUpcase<NewCollectionData>, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> JsonResult { |
|
|
) -> JsonResult { |
|
|
let data: NewCollectionData = data.into_inner().data; |
|
|
let data: NewCollectionData = data.into_inner().data; |
|
|
|
|
|
|
|
@ -361,6 +400,17 @@ async fn post_organization_collection_update( |
|
|
collection.name = data.Name; |
|
|
collection.name = data.Name; |
|
|
collection.save(&mut conn).await?; |
|
|
collection.save(&mut conn).await?; |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::CollectionUpdated as i32, |
|
|
|
|
|
&collection.uuid, |
|
|
|
|
|
org_id, |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
CollectionGroup::delete_all_by_collection(&col_id, &mut conn).await?; |
|
|
CollectionGroup::delete_all_by_collection(&col_id, &mut conn).await?; |
|
|
|
|
|
|
|
|
for group in data.Groups { |
|
|
for group in data.Groups { |
|
@ -415,13 +465,24 @@ async fn post_organization_collection_delete_user( |
|
|
async fn delete_organization_collection( |
|
|
async fn delete_organization_collection( |
|
|
org_id: String, |
|
|
org_id: String, |
|
|
col_id: String, |
|
|
col_id: String, |
|
|
_headers: ManagerHeaders, |
|
|
headers: ManagerHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
match Collection::find_by_uuid(&col_id, &mut conn).await { |
|
|
match Collection::find_by_uuid(&col_id, &mut conn).await { |
|
|
None => err!("Collection not found"), |
|
|
None => err!("Collection not found"), |
|
|
Some(collection) => { |
|
|
Some(collection) => { |
|
|
if collection.org_uuid == org_id { |
|
|
if collection.org_uuid == org_id { |
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::CollectionDeleted as i32, |
|
|
|
|
|
&collection.uuid, |
|
|
|
|
|
org_id, |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
collection.delete(&mut conn).await |
|
|
collection.delete(&mut conn).await |
|
|
} else { |
|
|
} else { |
|
|
err!("Collection and Organization id do not match") |
|
|
err!("Collection and Organization id do not match") |
|
@ -444,8 +505,9 @@ async fn post_organization_collection_delete( |
|
|
headers: ManagerHeaders, |
|
|
headers: ManagerHeaders, |
|
|
_data: JsonUpcase<DeleteCollectionData>, |
|
|
_data: JsonUpcase<DeleteCollectionData>, |
|
|
conn: DbConn, |
|
|
conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
delete_organization_collection(org_id, col_id, headers, conn).await |
|
|
delete_organization_collection(org_id, col_id, headers, conn, ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[get("/organizations/<org_id>/collections/<coll_id>/details")] |
|
|
#[get("/organizations/<org_id>/collections/<coll_id>/details")] |
|
@ -632,6 +694,7 @@ async fn send_invite( |
|
|
data: JsonUpcase<InviteData>, |
|
|
data: JsonUpcase<InviteData>, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
let data: InviteData = data.into_inner().data; |
|
|
let data: InviteData = data.into_inner().data; |
|
|
|
|
|
|
|
@ -700,6 +763,17 @@ async fn send_invite( |
|
|
|
|
|
|
|
|
new_user.save(&mut conn).await?; |
|
|
new_user.save(&mut conn).await?; |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUserInvited as i32, |
|
|
|
|
|
&new_user.uuid, |
|
|
|
|
|
org_id.clone(), |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
if CONFIG.mail_enabled() { |
|
|
if CONFIG.mail_enabled() { |
|
|
let org_name = match Organization::find_by_uuid(&org_id, &mut conn).await { |
|
|
let org_name = match Organization::find_by_uuid(&org_id, &mut conn).await { |
|
|
Some(org) => org.name, |
|
|
Some(org) => org.name, |
|
@ -882,6 +956,7 @@ async fn bulk_confirm_invite( |
|
|
data: JsonUpcase<Value>, |
|
|
data: JsonUpcase<Value>, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> Json<Value> { |
|
|
) -> Json<Value> { |
|
|
let data = data.into_inner().data; |
|
|
let data = data.into_inner().data; |
|
|
|
|
|
|
|
@ -891,7 +966,7 @@ async fn bulk_confirm_invite( |
|
|
for invite in keys { |
|
|
for invite in keys { |
|
|
let org_user_id = invite["Id"].as_str().unwrap_or_default(); |
|
|
let org_user_id = invite["Id"].as_str().unwrap_or_default(); |
|
|
let user_key = invite["Key"].as_str().unwrap_or_default(); |
|
|
let user_key = invite["Key"].as_str().unwrap_or_default(); |
|
|
let err_msg = match _confirm_invite(&org_id, org_user_id, user_key, &headers, &mut conn).await { |
|
|
let err_msg = match _confirm_invite(&org_id, org_user_id, user_key, &headers, &mut conn, &ip).await { |
|
|
Ok(_) => String::new(), |
|
|
Ok(_) => String::new(), |
|
|
Err(e) => format!("{:?}", e), |
|
|
Err(e) => format!("{:?}", e), |
|
|
}; |
|
|
}; |
|
@ -922,10 +997,11 @@ async fn confirm_invite( |
|
|
data: JsonUpcase<Value>, |
|
|
data: JsonUpcase<Value>, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
let data = data.into_inner().data; |
|
|
let data = data.into_inner().data; |
|
|
let user_key = data["Key"].as_str().unwrap_or_default(); |
|
|
let user_key = data["Key"].as_str().unwrap_or_default(); |
|
|
_confirm_invite(&org_id, &org_user_id, user_key, &headers, &mut conn).await |
|
|
_confirm_invite(&org_id, &org_user_id, user_key, &headers, &mut conn, &ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async fn _confirm_invite( |
|
|
async fn _confirm_invite( |
|
@ -934,6 +1010,7 @@ async fn _confirm_invite( |
|
|
key: &str, |
|
|
key: &str, |
|
|
headers: &AdminHeaders, |
|
|
headers: &AdminHeaders, |
|
|
conn: &mut DbConn, |
|
|
conn: &mut DbConn, |
|
|
|
|
|
ip: &ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
if key.is_empty() || org_user_id.is_empty() { |
|
|
if key.is_empty() || org_user_id.is_empty() { |
|
|
err!("Key or UserId is not set, unable to process request"); |
|
|
err!("Key or UserId is not set, unable to process request"); |
|
@ -969,6 +1046,17 @@ async fn _confirm_invite( |
|
|
user_to_confirm.status = UserOrgStatus::Confirmed as i32; |
|
|
user_to_confirm.status = UserOrgStatus::Confirmed as i32; |
|
|
user_to_confirm.akey = key.to_string(); |
|
|
user_to_confirm.akey = key.to_string(); |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUserConfirmed as i32, |
|
|
|
|
|
&user_to_confirm.uuid, |
|
|
|
|
|
String::from(org_id), |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
if CONFIG.mail_enabled() { |
|
|
if CONFIG.mail_enabled() { |
|
|
let org_name = match Organization::find_by_uuid(org_id, conn).await { |
|
|
let org_name = match Organization::find_by_uuid(org_id, conn).await { |
|
|
Some(org) => org.name, |
|
|
Some(org) => org.name, |
|
@ -1009,8 +1097,9 @@ async fn put_organization_user( |
|
|
data: JsonUpcase<EditUserData>, |
|
|
data: JsonUpcase<EditUserData>, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
conn: DbConn, |
|
|
conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
edit_user(org_id, org_user_id, data, headers, conn).await |
|
|
edit_user(org_id, org_user_id, data, headers, conn, ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[post("/organizations/<org_id>/users/<org_user_id>", data = "<data>", rank = 1)] |
|
|
#[post("/organizations/<org_id>/users/<org_user_id>", data = "<data>", rank = 1)] |
|
@ -1020,6 +1109,7 @@ async fn edit_user( |
|
|
data: JsonUpcase<EditUserData>, |
|
|
data: JsonUpcase<EditUserData>, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
let data: EditUserData = data.into_inner().data; |
|
|
let data: EditUserData = data.into_inner().data; |
|
|
|
|
|
|
|
@ -1095,6 +1185,17 @@ async fn edit_user( |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUserUpdated as i32, |
|
|
|
|
|
&user_to_edit.uuid, |
|
|
|
|
|
org_id.clone(), |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
user_to_edit.save(&mut conn).await |
|
|
user_to_edit.save(&mut conn).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1104,12 +1205,13 @@ async fn bulk_delete_user( |
|
|
data: JsonUpcase<OrgBulkIds>, |
|
|
data: JsonUpcase<OrgBulkIds>, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> Json<Value> { |
|
|
) -> Json<Value> { |
|
|
let data: OrgBulkIds = data.into_inner().data; |
|
|
let data: OrgBulkIds = data.into_inner().data; |
|
|
|
|
|
|
|
|
let mut bulk_response = Vec::new(); |
|
|
let mut bulk_response = Vec::new(); |
|
|
for org_user_id in data.Ids { |
|
|
for org_user_id in data.Ids { |
|
|
let err_msg = match _delete_user(&org_id, &org_user_id, &headers, &mut conn).await { |
|
|
let err_msg = match _delete_user(&org_id, &org_user_id, &headers, &mut conn, &ip).await { |
|
|
Ok(_) => String::new(), |
|
|
Ok(_) => String::new(), |
|
|
Err(e) => format!("{:?}", e), |
|
|
Err(e) => format!("{:?}", e), |
|
|
}; |
|
|
}; |
|
@ -1131,11 +1233,34 @@ async fn bulk_delete_user( |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[delete("/organizations/<org_id>/users/<org_user_id>")] |
|
|
#[delete("/organizations/<org_id>/users/<org_user_id>")] |
|
|
async fn delete_user(org_id: String, org_user_id: String, headers: AdminHeaders, mut conn: DbConn) -> EmptyResult { |
|
|
async fn delete_user( |
|
|
_delete_user(&org_id, &org_user_id, &headers, &mut conn).await |
|
|
org_id: String, |
|
|
|
|
|
org_user_id: String, |
|
|
|
|
|
headers: AdminHeaders, |
|
|
|
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
|
|
|
) -> EmptyResult { |
|
|
|
|
|
_delete_user(&org_id, &org_user_id, &headers, &mut conn, &ip).await |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[post("/organizations/<org_id>/users/<org_user_id>/delete")] |
|
|
|
|
|
async fn post_delete_user( |
|
|
|
|
|
org_id: String, |
|
|
|
|
|
org_user_id: String, |
|
|
|
|
|
headers: AdminHeaders, |
|
|
|
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
|
|
|
) -> EmptyResult { |
|
|
|
|
|
_delete_user(&org_id, &org_user_id, &headers, &mut conn, &ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async fn _delete_user(org_id: &str, org_user_id: &str, headers: &AdminHeaders, conn: &mut DbConn) -> EmptyResult { |
|
|
async fn _delete_user( |
|
|
|
|
|
org_id: &str, |
|
|
|
|
|
org_user_id: &str, |
|
|
|
|
|
headers: &AdminHeaders, |
|
|
|
|
|
conn: &mut DbConn, |
|
|
|
|
|
ip: &ClientIp, |
|
|
|
|
|
) -> EmptyResult { |
|
|
let user_to_delete = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { |
|
|
let user_to_delete = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { |
|
|
Some(user) => user, |
|
|
Some(user) => user, |
|
|
None => err!("User to delete isn't member of the organization"), |
|
|
None => err!("User to delete isn't member of the organization"), |
|
@ -1152,12 +1277,18 @@ async fn _delete_user(org_id: &str, org_user_id: &str, headers: &AdminHeaders, c |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
user_to_delete.delete(conn).await |
|
|
log_event( |
|
|
} |
|
|
EventType::OrganizationUserRemoved as i32, |
|
|
|
|
|
&user_to_delete.uuid, |
|
|
|
|
|
String::from(org_id), |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
#[post("/organizations/<org_id>/users/<org_user_id>/delete")] |
|
|
user_to_delete.delete(conn).await |
|
|
async fn post_delete_user(org_id: String, org_user_id: String, headers: AdminHeaders, conn: DbConn) -> EmptyResult { |
|
|
|
|
|
delete_user(org_id, org_user_id, headers, conn).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[post("/organizations/<org_id>/users/public-keys", data = "<data>")] |
|
|
#[post("/organizations/<org_id>/users/public-keys", data = "<data>")] |
|
@ -1223,6 +1354,7 @@ async fn post_org_import( |
|
|
data: JsonUpcase<ImportData>, |
|
|
data: JsonUpcase<ImportData>, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
nt: Notify<'_>, |
|
|
nt: Notify<'_>, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
let data: ImportData = data.into_inner().data; |
|
|
let data: ImportData = data.into_inner().data; |
|
@ -1249,7 +1381,9 @@ async fn post_org_import( |
|
|
let mut ciphers = Vec::new(); |
|
|
let mut ciphers = Vec::new(); |
|
|
for cipher_data in data.Ciphers { |
|
|
for cipher_data in data.Ciphers { |
|
|
let mut cipher = Cipher::new(cipher_data.Type, cipher_data.Name.clone()); |
|
|
let mut cipher = Cipher::new(cipher_data.Type, cipher_data.Name.clone()); |
|
|
update_cipher_from_data(&mut cipher, cipher_data, &headers, false, &mut conn, &nt, UpdateType::None).await.ok(); |
|
|
update_cipher_from_data(&mut cipher, cipher_data, &headers, false, &mut conn, &ip, &nt, UpdateType::None) |
|
|
|
|
|
.await |
|
|
|
|
|
.ok(); |
|
|
ciphers.push(cipher); |
|
|
ciphers.push(cipher); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1333,8 +1467,9 @@ async fn put_policy( |
|
|
org_id: String, |
|
|
org_id: String, |
|
|
pol_type: i32, |
|
|
pol_type: i32, |
|
|
data: Json<PolicyData>, |
|
|
data: Json<PolicyData>, |
|
|
_headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> JsonResult { |
|
|
) -> JsonResult { |
|
|
let data: PolicyData = data.into_inner(); |
|
|
let data: PolicyData = data.into_inner(); |
|
|
|
|
|
|
|
@ -1360,6 +1495,18 @@ async fn put_policy( |
|
|
|
|
|
|
|
|
mail::send_2fa_removed_from_org(&user.email, &org.name).await?; |
|
|
mail::send_2fa_removed_from_org(&user.email, &org.name).await?; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUserRemoved as i32, |
|
|
|
|
|
&member.uuid, |
|
|
|
|
|
org_id.clone(), |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
member.delete(&mut conn).await?; |
|
|
member.delete(&mut conn).await?; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -1382,6 +1529,18 @@ async fn put_policy( |
|
|
|
|
|
|
|
|
mail::send_single_org_removed_from_org(&user.email, &org.name).await?; |
|
|
mail::send_single_org_removed_from_org(&user.email, &org.name).await?; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUserRemoved as i32, |
|
|
|
|
|
&member.uuid, |
|
|
|
|
|
org_id.clone(), |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
member.delete(&mut conn).await?; |
|
|
member.delete(&mut conn).await?; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -1389,13 +1548,24 @@ async fn put_policy( |
|
|
|
|
|
|
|
|
let mut policy = match OrgPolicy::find_by_org_and_type(&org_id, pol_type_enum, &mut conn).await { |
|
|
let mut policy = match OrgPolicy::find_by_org_and_type(&org_id, pol_type_enum, &mut conn).await { |
|
|
Some(p) => p, |
|
|
Some(p) => p, |
|
|
None => OrgPolicy::new(org_id, pol_type_enum, "{}".to_string()), |
|
|
None => OrgPolicy::new(org_id.clone(), pol_type_enum, "{}".to_string()), |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
policy.enabled = data.enabled; |
|
|
policy.enabled = data.enabled; |
|
|
policy.data = serde_json::to_string(&data.data)?; |
|
|
policy.data = serde_json::to_string(&data.data)?; |
|
|
policy.save(&mut conn).await?; |
|
|
policy.save(&mut conn).await?; |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::PolicyUpdated as i32, |
|
|
|
|
|
&policy.uuid, |
|
|
|
|
|
org_id, |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
Ok(Json(policy.to_json())) |
|
|
Ok(Json(policy.to_json())) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1467,7 +1637,13 @@ struct OrgImportData { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[post("/organizations/<org_id>/import", data = "<data>")] |
|
|
#[post("/organizations/<org_id>/import", data = "<data>")] |
|
|
async fn import(org_id: String, data: JsonUpcase<OrgImportData>, headers: Headers, mut conn: DbConn) -> EmptyResult { |
|
|
async fn import( |
|
|
|
|
|
org_id: String, |
|
|
|
|
|
data: JsonUpcase<OrgImportData>, |
|
|
|
|
|
headers: Headers, |
|
|
|
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
|
|
|
) -> EmptyResult { |
|
|
let data = data.into_inner().data; |
|
|
let data = data.into_inner().data; |
|
|
|
|
|
|
|
|
// TODO: Currently we aren't storing the externalId's anywhere, so we also don't have a way
|
|
|
// TODO: Currently we aren't storing the externalId's anywhere, so we also don't have a way
|
|
@ -1487,6 +1663,17 @@ async fn import(org_id: String, data: JsonUpcase<OrgImportData>, headers: Header |
|
|
// If user is marked for deletion and it exists, delete it
|
|
|
// If user is marked for deletion and it exists, delete it
|
|
|
if let Some(user_org) = UserOrganization::find_by_email_and_org(&user_data.Email, &org_id, &mut conn).await |
|
|
if let Some(user_org) = UserOrganization::find_by_email_and_org(&user_data.Email, &org_id, &mut conn).await |
|
|
{ |
|
|
{ |
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUserRemoved as i32, |
|
|
|
|
|
&user_org.uuid, |
|
|
|
|
|
org_id.clone(), |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
user_org.delete(&mut conn).await?; |
|
|
user_org.delete(&mut conn).await?; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1506,6 +1693,17 @@ async fn import(org_id: String, data: JsonUpcase<OrgImportData>, headers: Header |
|
|
|
|
|
|
|
|
new_org_user.save(&mut conn).await?; |
|
|
new_org_user.save(&mut conn).await?; |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUserInvited as i32, |
|
|
|
|
|
&new_org_user.uuid, |
|
|
|
|
|
org_id.clone(), |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
if CONFIG.mail_enabled() { |
|
|
if CONFIG.mail_enabled() { |
|
|
let org_name = match Organization::find_by_uuid(&org_id, &mut conn).await { |
|
|
let org_name = match Organization::find_by_uuid(&org_id, &mut conn).await { |
|
|
Some(org) => org.name, |
|
|
Some(org) => org.name, |
|
@ -1531,6 +1729,17 @@ async fn import(org_id: String, data: JsonUpcase<OrgImportData>, headers: Header |
|
|
for user_org in UserOrganization::find_by_org_and_type(&org_id, UserOrgType::User, &mut conn).await { |
|
|
for user_org in UserOrganization::find_by_org_and_type(&org_id, UserOrgType::User, &mut conn).await { |
|
|
if let Some(user_email) = User::find_by_uuid(&user_org.user_uuid, &mut conn).await.map(|u| u.email) { |
|
|
if let Some(user_email) = User::find_by_uuid(&user_org.user_uuid, &mut conn).await.map(|u| u.email) { |
|
|
if !data.Users.iter().any(|u| u.Email == user_email) { |
|
|
if !data.Users.iter().any(|u| u.Email == user_email) { |
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUserRemoved as i32, |
|
|
|
|
|
&user_org.uuid, |
|
|
|
|
|
org_id.clone(), |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
user_org.delete(&mut conn).await?; |
|
|
user_org.delete(&mut conn).await?; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -1547,8 +1756,9 @@ async fn deactivate_organization_user( |
|
|
org_user_id: String, |
|
|
org_user_id: String, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
_revoke_organization_user(&org_id, &org_user_id, &headers, &mut conn).await |
|
|
_revoke_organization_user(&org_id, &org_user_id, &headers, &mut conn, &ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Pre web-vault v2022.9.x endpoint
|
|
|
// Pre web-vault v2022.9.x endpoint
|
|
@ -1558,8 +1768,9 @@ async fn bulk_deactivate_organization_user( |
|
|
data: JsonUpcase<Value>, |
|
|
data: JsonUpcase<Value>, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
conn: DbConn, |
|
|
conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> Json<Value> { |
|
|
) -> Json<Value> { |
|
|
bulk_revoke_organization_user(org_id, data, headers, conn).await |
|
|
bulk_revoke_organization_user(org_id, data, headers, conn, ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[put("/organizations/<org_id>/users/<org_user_id>/revoke")] |
|
|
#[put("/organizations/<org_id>/users/<org_user_id>/revoke")] |
|
@ -1568,8 +1779,9 @@ async fn revoke_organization_user( |
|
|
org_user_id: String, |
|
|
org_user_id: String, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
_revoke_organization_user(&org_id, &org_user_id, &headers, &mut conn).await |
|
|
_revoke_organization_user(&org_id, &org_user_id, &headers, &mut conn, &ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[put("/organizations/<org_id>/users/revoke", data = "<data>")] |
|
|
#[put("/organizations/<org_id>/users/revoke", data = "<data>")] |
|
@ -1578,6 +1790,7 @@ async fn bulk_revoke_organization_user( |
|
|
data: JsonUpcase<Value>, |
|
|
data: JsonUpcase<Value>, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> Json<Value> { |
|
|
) -> Json<Value> { |
|
|
let data = data.into_inner().data; |
|
|
let data = data.into_inner().data; |
|
|
|
|
|
|
|
@ -1586,7 +1799,7 @@ async fn bulk_revoke_organization_user( |
|
|
Some(org_users) => { |
|
|
Some(org_users) => { |
|
|
for org_user_id in org_users { |
|
|
for org_user_id in org_users { |
|
|
let org_user_id = org_user_id.as_str().unwrap_or_default(); |
|
|
let org_user_id = org_user_id.as_str().unwrap_or_default(); |
|
|
let err_msg = match _revoke_organization_user(&org_id, org_user_id, &headers, &mut conn).await { |
|
|
let err_msg = match _revoke_organization_user(&org_id, org_user_id, &headers, &mut conn, &ip).await { |
|
|
Ok(_) => String::new(), |
|
|
Ok(_) => String::new(), |
|
|
Err(e) => format!("{:?}", e), |
|
|
Err(e) => format!("{:?}", e), |
|
|
}; |
|
|
}; |
|
@ -1615,6 +1828,7 @@ async fn _revoke_organization_user( |
|
|
org_user_id: &str, |
|
|
org_user_id: &str, |
|
|
headers: &AdminHeaders, |
|
|
headers: &AdminHeaders, |
|
|
conn: &mut DbConn, |
|
|
conn: &mut DbConn, |
|
|
|
|
|
ip: &ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { |
|
|
match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { |
|
|
Some(mut user_org) if user_org.status > UserOrgStatus::Revoked as i32 => { |
|
|
Some(mut user_org) if user_org.status > UserOrgStatus::Revoked as i32 => { |
|
@ -1632,6 +1846,17 @@ async fn _revoke_organization_user( |
|
|
|
|
|
|
|
|
user_org.revoke(); |
|
|
user_org.revoke(); |
|
|
user_org.save(conn).await?; |
|
|
user_org.save(conn).await?; |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUserRevoked as i32, |
|
|
|
|
|
&user_org.uuid, |
|
|
|
|
|
org_id.to_string(), |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
} |
|
|
} |
|
|
Some(_) => err!("User is already revoked"), |
|
|
Some(_) => err!("User is already revoked"), |
|
|
None => err!("User not found in organization"), |
|
|
None => err!("User not found in organization"), |
|
@ -1646,8 +1871,9 @@ async fn activate_organization_user( |
|
|
org_user_id: String, |
|
|
org_user_id: String, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
_restore_organization_user(&org_id, &org_user_id, &headers, &mut conn).await |
|
|
_restore_organization_user(&org_id, &org_user_id, &headers, &mut conn, &ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Pre web-vault v2022.9.x endpoint
|
|
|
// Pre web-vault v2022.9.x endpoint
|
|
@ -1657,8 +1883,9 @@ async fn bulk_activate_organization_user( |
|
|
data: JsonUpcase<Value>, |
|
|
data: JsonUpcase<Value>, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
conn: DbConn, |
|
|
conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> Json<Value> { |
|
|
) -> Json<Value> { |
|
|
bulk_restore_organization_user(org_id, data, headers, conn).await |
|
|
bulk_restore_organization_user(org_id, data, headers, conn, ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[put("/organizations/<org_id>/users/<org_user_id>/restore")] |
|
|
#[put("/organizations/<org_id>/users/<org_user_id>/restore")] |
|
@ -1667,8 +1894,9 @@ async fn restore_organization_user( |
|
|
org_user_id: String, |
|
|
org_user_id: String, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
_restore_organization_user(&org_id, &org_user_id, &headers, &mut conn).await |
|
|
_restore_organization_user(&org_id, &org_user_id, &headers, &mut conn, &ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[put("/organizations/<org_id>/users/restore", data = "<data>")] |
|
|
#[put("/organizations/<org_id>/users/restore", data = "<data>")] |
|
@ -1677,6 +1905,7 @@ async fn bulk_restore_organization_user( |
|
|
data: JsonUpcase<Value>, |
|
|
data: JsonUpcase<Value>, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> Json<Value> { |
|
|
) -> Json<Value> { |
|
|
let data = data.into_inner().data; |
|
|
let data = data.into_inner().data; |
|
|
|
|
|
|
|
@ -1685,7 +1914,7 @@ async fn bulk_restore_organization_user( |
|
|
Some(org_users) => { |
|
|
Some(org_users) => { |
|
|
for org_user_id in org_users { |
|
|
for org_user_id in org_users { |
|
|
let org_user_id = org_user_id.as_str().unwrap_or_default(); |
|
|
let org_user_id = org_user_id.as_str().unwrap_or_default(); |
|
|
let err_msg = match _restore_organization_user(&org_id, org_user_id, &headers, &mut conn).await { |
|
|
let err_msg = match _restore_organization_user(&org_id, org_user_id, &headers, &mut conn, &ip).await { |
|
|
Ok(_) => String::new(), |
|
|
Ok(_) => String::new(), |
|
|
Err(e) => format!("{:?}", e), |
|
|
Err(e) => format!("{:?}", e), |
|
|
}; |
|
|
}; |
|
@ -1714,6 +1943,7 @@ async fn _restore_organization_user( |
|
|
org_user_id: &str, |
|
|
org_user_id: &str, |
|
|
headers: &AdminHeaders, |
|
|
headers: &AdminHeaders, |
|
|
conn: &mut DbConn, |
|
|
conn: &mut DbConn, |
|
|
|
|
|
ip: &ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { |
|
|
match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { |
|
|
Some(mut user_org) if user_org.status < UserOrgStatus::Accepted as i32 => { |
|
|
Some(mut user_org) if user_org.status < UserOrgStatus::Accepted as i32 => { |
|
@ -1740,6 +1970,17 @@ async fn _restore_organization_user( |
|
|
|
|
|
|
|
|
user_org.restore(); |
|
|
user_org.restore(); |
|
|
user_org.save(conn).await?; |
|
|
user_org.save(conn).await?; |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUserRestored as i32, |
|
|
|
|
|
&user_org.uuid, |
|
|
|
|
|
org_id.to_string(), |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
} |
|
|
} |
|
|
Some(_) => err!("User is already active"), |
|
|
Some(_) => err!("User is already active"), |
|
|
None => err!("User not found in organization"), |
|
|
None => err!("User not found in organization"), |
|
@ -1828,37 +2069,51 @@ impl SelectionReadOnly { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[post("/organizations/<_org_id>/groups/<group_id>", data = "<data>")] |
|
|
#[post("/organizations/<org_id>/groups/<group_id>", data = "<data>")] |
|
|
async fn post_group( |
|
|
async fn post_group( |
|
|
_org_id: String, |
|
|
org_id: String, |
|
|
group_id: String, |
|
|
group_id: String, |
|
|
data: JsonUpcase<GroupRequest>, |
|
|
data: JsonUpcase<GroupRequest>, |
|
|
_headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
conn: DbConn, |
|
|
conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> JsonResult { |
|
|
) -> JsonResult { |
|
|
put_group(_org_id, group_id, data, _headers, conn).await |
|
|
put_group(org_id, group_id, data, headers, conn, ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[post("/organizations/<org_id>/groups", data = "<data>")] |
|
|
#[post("/organizations/<org_id>/groups", data = "<data>")] |
|
|
async fn post_groups( |
|
|
async fn post_groups( |
|
|
org_id: String, |
|
|
org_id: String, |
|
|
_headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
data: JsonUpcase<GroupRequest>, |
|
|
data: JsonUpcase<GroupRequest>, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> JsonResult { |
|
|
) -> JsonResult { |
|
|
let group_request = data.into_inner().data; |
|
|
let group_request = data.into_inner().data; |
|
|
let group = group_request.to_group(&org_id)?; |
|
|
let group = group_request.to_group(&org_id)?; |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::GroupCreated as i32, |
|
|
|
|
|
&group.uuid, |
|
|
|
|
|
org_id, |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
add_update_group(group, group_request.Collections, &mut conn).await |
|
|
add_update_group(group, group_request.Collections, &mut conn).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[put("/organizations/<_org_id>/groups/<group_id>", data = "<data>")] |
|
|
#[put("/organizations/<org_id>/groups/<group_id>", data = "<data>")] |
|
|
async fn put_group( |
|
|
async fn put_group( |
|
|
_org_id: String, |
|
|
org_id: String, |
|
|
group_id: String, |
|
|
group_id: String, |
|
|
data: JsonUpcase<GroupRequest>, |
|
|
data: JsonUpcase<GroupRequest>, |
|
|
_headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> JsonResult { |
|
|
) -> JsonResult { |
|
|
let group = match Group::find_by_uuid(&group_id, &mut conn).await { |
|
|
let group = match Group::find_by_uuid(&group_id, &mut conn).await { |
|
|
Some(group) => group, |
|
|
Some(group) => group, |
|
@ -1870,6 +2125,17 @@ async fn put_group( |
|
|
|
|
|
|
|
|
CollectionGroup::delete_all_by_group(&group_id, &mut conn).await?; |
|
|
CollectionGroup::delete_all_by_group(&group_id, &mut conn).await?; |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::GroupUpdated as i32, |
|
|
|
|
|
&updated_group.uuid, |
|
|
|
|
|
org_id, |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
add_update_group(updated_group, group_request.Collections, &mut conn).await |
|
|
add_update_group(updated_group, group_request.Collections, &mut conn).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1915,17 +2181,40 @@ async fn get_group_details(_org_id: String, group_id: String, _headers: AdminHea |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[post("/organizations/<org_id>/groups/<group_id>/delete")] |
|
|
#[post("/organizations/<org_id>/groups/<group_id>/delete")] |
|
|
async fn post_delete_group(org_id: String, group_id: String, _headers: AdminHeaders, conn: DbConn) -> EmptyResult { |
|
|
async fn post_delete_group( |
|
|
delete_group(org_id, group_id, _headers, conn).await |
|
|
org_id: String, |
|
|
|
|
|
group_id: String, |
|
|
|
|
|
headers: AdminHeaders, |
|
|
|
|
|
conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
|
|
|
) -> EmptyResult { |
|
|
|
|
|
delete_group(org_id, group_id, headers, conn, ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[delete("/organizations/<_org_id>/groups/<group_id>")] |
|
|
#[delete("/organizations/<org_id>/groups/<group_id>")] |
|
|
async fn delete_group(_org_id: String, group_id: String, _headers: AdminHeaders, mut conn: DbConn) -> EmptyResult { |
|
|
async fn delete_group( |
|
|
|
|
|
org_id: String, |
|
|
|
|
|
group_id: String, |
|
|
|
|
|
headers: AdminHeaders, |
|
|
|
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
|
|
|
) -> EmptyResult { |
|
|
let group = match Group::find_by_uuid(&group_id, &mut conn).await { |
|
|
let group = match Group::find_by_uuid(&group_id, &mut conn).await { |
|
|
Some(group) => group, |
|
|
Some(group) => group, |
|
|
_ => err!("Group not found"), |
|
|
_ => err!("Group not found"), |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::GroupDeleted as i32, |
|
|
|
|
|
&group.uuid, |
|
|
|
|
|
org_id, |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
group.delete(&mut conn).await |
|
|
group.delete(&mut conn).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1955,13 +2244,14 @@ async fn get_group_users(_org_id: String, group_id: String, _headers: AdminHeade |
|
|
Ok(Json(json!(group_users))) |
|
|
Ok(Json(json!(group_users))) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[put("/organizations/<_org_id>/groups/<group_id>/users", data = "<data>")] |
|
|
#[put("/organizations/<org_id>/groups/<group_id>/users", data = "<data>")] |
|
|
async fn put_group_users( |
|
|
async fn put_group_users( |
|
|
_org_id: String, |
|
|
org_id: String, |
|
|
group_id: String, |
|
|
group_id: String, |
|
|
_headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
data: JsonVec<String>, |
|
|
data: JsonVec<String>, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
match Group::find_by_uuid(&group_id, &mut conn).await { |
|
|
match Group::find_by_uuid(&group_id, &mut conn).await { |
|
|
Some(_) => { /* Do nothing */ } |
|
|
Some(_) => { /* Do nothing */ } |
|
@ -1972,8 +2262,19 @@ async fn put_group_users( |
|
|
|
|
|
|
|
|
let assigned_user_ids = data.into_inner(); |
|
|
let assigned_user_ids = data.into_inner(); |
|
|
for assigned_user_id in assigned_user_ids { |
|
|
for assigned_user_id in assigned_user_ids { |
|
|
let mut user_entry = GroupUser::new(group_id.clone(), assigned_user_id); |
|
|
let mut user_entry = GroupUser::new(group_id.clone(), assigned_user_id.clone()); |
|
|
user_entry.save(&mut conn).await?; |
|
|
user_entry.save(&mut conn).await?; |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUserUpdatedGroups as i32, |
|
|
|
|
|
&assigned_user_id, |
|
|
|
|
|
org_id.clone(), |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Ok(()) |
|
|
Ok(()) |
|
@ -1998,61 +2299,76 @@ struct OrganizationUserUpdateGroupsRequest { |
|
|
GroupIds: Vec<String>, |
|
|
GroupIds: Vec<String>, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[post("/organizations/<_org_id>/users/<user_id>/groups", data = "<data>")] |
|
|
#[post("/organizations/<org_id>/users/<org_user_id>/groups", data = "<data>")] |
|
|
async fn post_user_groups( |
|
|
async fn post_user_groups( |
|
|
_org_id: String, |
|
|
org_id: String, |
|
|
user_id: String, |
|
|
org_user_id: String, |
|
|
data: JsonUpcase<OrganizationUserUpdateGroupsRequest>, |
|
|
data: JsonUpcase<OrganizationUserUpdateGroupsRequest>, |
|
|
_headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
conn: DbConn, |
|
|
conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
put_user_groups(_org_id, user_id, data, _headers, conn).await |
|
|
put_user_groups(org_id, org_user_id, data, headers, conn, ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[put("/organizations/<_org_id>/users/<user_id>/groups", data = "<data>")] |
|
|
#[put("/organizations/<org_id>/users/<org_user_id>/groups", data = "<data>")] |
|
|
async fn put_user_groups( |
|
|
async fn put_user_groups( |
|
|
_org_id: String, |
|
|
org_id: String, |
|
|
user_id: String, |
|
|
org_user_id: String, |
|
|
data: JsonUpcase<OrganizationUserUpdateGroupsRequest>, |
|
|
data: JsonUpcase<OrganizationUserUpdateGroupsRequest>, |
|
|
_headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
match UserOrganization::find_by_uuid(&user_id, &mut conn).await { |
|
|
match UserOrganization::find_by_uuid(&org_user_id, &mut conn).await { |
|
|
Some(_) => { /* Do nothing */ } |
|
|
Some(_) => { /* Do nothing */ } |
|
|
_ => err!("User could not be found!"), |
|
|
_ => err!("User could not be found!"), |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
GroupUser::delete_all_by_user(&user_id, &mut conn).await?; |
|
|
GroupUser::delete_all_by_user(&org_user_id, &mut conn).await?; |
|
|
|
|
|
|
|
|
let assigned_group_ids = data.into_inner().data; |
|
|
let assigned_group_ids = data.into_inner().data; |
|
|
for assigned_group_id in assigned_group_ids.GroupIds { |
|
|
for assigned_group_id in assigned_group_ids.GroupIds { |
|
|
let mut group_user = GroupUser::new(assigned_group_id.clone(), user_id.clone()); |
|
|
let mut group_user = GroupUser::new(assigned_group_id.clone(), org_user_id.clone()); |
|
|
group_user.save(&mut conn).await?; |
|
|
group_user.save(&mut conn).await?; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUserUpdatedGroups as i32, |
|
|
|
|
|
&org_user_id, |
|
|
|
|
|
org_id, |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
Ok(()) |
|
|
Ok(()) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[post("/organizations/<org_id>/groups/<group_id>/delete-user/<user_id>")] |
|
|
#[post("/organizations/<org_id>/groups/<group_id>/delete-user/<org_user_id>")] |
|
|
async fn post_delete_group_user( |
|
|
async fn post_delete_group_user( |
|
|
org_id: String, |
|
|
org_id: String, |
|
|
group_id: String, |
|
|
group_id: String, |
|
|
user_id: String, |
|
|
org_user_id: String, |
|
|
headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
conn: DbConn, |
|
|
conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
delete_group_user(org_id, group_id, user_id, headers, conn).await |
|
|
delete_group_user(org_id, group_id, org_user_id, headers, conn, ip).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[delete("/organizations/<_org_id>/groups/<group_id>/users/<user_id>")] |
|
|
#[delete("/organizations/<org_id>/groups/<group_id>/users/<org_user_id>")] |
|
|
async fn delete_group_user( |
|
|
async fn delete_group_user( |
|
|
_org_id: String, |
|
|
org_id: String, |
|
|
group_id: String, |
|
|
group_id: String, |
|
|
user_id: String, |
|
|
org_user_id: String, |
|
|
_headers: AdminHeaders, |
|
|
headers: AdminHeaders, |
|
|
mut conn: DbConn, |
|
|
mut conn: DbConn, |
|
|
|
|
|
ip: ClientIp, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
match UserOrganization::find_by_uuid(&user_id, &mut conn).await { |
|
|
match UserOrganization::find_by_uuid(&org_user_id, &mut conn).await { |
|
|
Some(_) => { /* Do nothing */ } |
|
|
Some(_) => { /* Do nothing */ } |
|
|
_ => err!("User could not be found!"), |
|
|
_ => err!("User could not be found!"), |
|
|
}; |
|
|
}; |
|
@ -2062,7 +2378,18 @@ async fn delete_group_user( |
|
|
_ => err!("Group could not be found!"), |
|
|
_ => err!("Group could not be found!"), |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
GroupUser::delete_by_group_id_and_user_id(&group_id, &user_id, &mut conn).await |
|
|
log_event( |
|
|
|
|
|
EventType::OrganizationUserUpdatedGroups as i32, |
|
|
|
|
|
&org_user_id, |
|
|
|
|
|
org_id, |
|
|
|
|
|
headers.user.uuid.clone(), |
|
|
|
|
|
headers.device.atype, |
|
|
|
|
|
&ip.ip, |
|
|
|
|
|
&mut conn, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
|
|
|
GroupUser::delete_by_group_id_and_user_id(&group_id, &org_user_id, &mut conn).await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// This is a new function active since the v2022.9.x clients.
|
|
|
// This is a new function active since the v2022.9.x clients.
|
|
|