add collection_membership type

Stefan Melmuk 1 week ago
parent 6355985539
commit 3d42b66a10
No known key found for this signature in database
GPG Key ID: 817020C608FE9C09

@ -43,13 +43,13 @@ pub fn routes() -> Vec<Route> {
get_org_details, get_org_details,
get_members, get_members,
send_invite, send_invite,
reinvite_user, reinvite_member,
bulk_reinvite_user, bulk_reinvite_member,
confirm_invite, confirm_invite,
bulk_confirm_invite, bulk_confirm_invite,
accept_invite, accept_invite,
get_user, get_user,
edit_user, edit_membership,
put_membership, put_membership,
delete_user, delete_user,
bulk_delete_user, bulk_delete_user,
@ -340,7 +340,8 @@ async fn get_org_collections_details(
}; };
// get all collection memberships for the current organization // get all collection memberships for the current organization
let col_users = CollectionUser::find_by_organization(&org_id, &mut conn).await; // NOTE: the loaded col_users have a MembershipId
let col_users = CollectionUser::find_by_organization_swap_user_uuid_with_member_uuid(&org_id, &mut conn).await;
// check if current user has full access to the organization (either directly or via any group) // check if current user has full access to the organization (either directly or via any group)
let has_full_access_to_org = member.access_all let has_full_access_to_org = member.access_all
@ -688,9 +689,9 @@ async fn get_collection_users(
err!("Collection not found in Organization") err!("Collection not found in Organization")
}; };
let mut user_list = Vec::new(); let mut member_list = Vec::new();
for col_user in CollectionUser::find_by_collection(&collection.uuid, &mut conn).await { for col_user in CollectionUser::find_by_collection(&collection.uuid, &mut conn).await {
user_list.push( member_list.push(
Membership::find_by_user_and_org(&col_user.user_uuid, &org_id, &mut conn) Membership::find_by_user_and_org(&col_user.user_uuid, &org_id, &mut conn)
.await .await
.unwrap() .unwrap()
@ -698,7 +699,7 @@ async fn get_collection_users(
); );
} }
Ok(Json(json!(user_list))) Ok(Json(json!(member_list)))
} }
#[put("/organizations/<org_id>/collections/<col_id>/users", data = "<data>")] #[put("/organizations/<org_id>/collections/<col_id>/users", data = "<data>")]
@ -972,7 +973,7 @@ async fn send_invite(
} }
#[post("/organizations/<org_id>/users/reinvite", data = "<data>")] #[post("/organizations/<org_id>/users/reinvite", data = "<data>")]
async fn bulk_reinvite_user( async fn bulk_reinvite_member(
org_id: OrganizationId, org_id: OrganizationId,
data: Json<BulkMembershipIds>, data: Json<BulkMembershipIds>,
headers: AdminHeaders, headers: AdminHeaders,
@ -982,7 +983,7 @@ async fn bulk_reinvite_user(
let mut bulk_response = Vec::new(); let mut bulk_response = Vec::new();
for member_id in data.ids { for member_id in data.ids {
let err_msg = match _reinvite_user(&org_id, &member_id, &headers.user.email, &mut conn).await { let err_msg = match _reinvite_member(&org_id, &member_id, &headers.user.email, &mut conn).await {
Ok(_) => String::new(), Ok(_) => String::new(),
Err(e) => format!("{e:?}"), Err(e) => format!("{e:?}"),
}; };
@ -1004,16 +1005,16 @@ async fn bulk_reinvite_user(
} }
#[post("/organizations/<org_id>/users/<member_id>/reinvite")] #[post("/organizations/<org_id>/users/<member_id>/reinvite")]
async fn reinvite_user( async fn reinvite_member(
org_id: OrganizationId, org_id: OrganizationId,
member_id: MembershipId, member_id: MembershipId,
headers: AdminHeaders, headers: AdminHeaders,
mut conn: DbConn, mut conn: DbConn,
) -> EmptyResult { ) -> EmptyResult {
_reinvite_user(&org_id, &member_id, &headers.user.email, &mut conn).await _reinvite_member(&org_id, &member_id, &headers.user.email, &mut conn).await
} }
async fn _reinvite_user( async fn _reinvite_member(
org_id: &OrganizationId, org_id: &OrganizationId,
member_id: &MembershipId, member_id: &MembershipId,
invited_by_email: &str, invited_by_email: &str,
@ -1104,7 +1105,7 @@ async fn accept_invite(
err!("Reset password key is required, but not provided."); err!("Reset password key is required, but not provided.");
} }
// This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_membership_type // This check is also done at accept_invite(), _confirm_invite, _activate_membership(), edit_membership(), admin::update_membership_type
// It returns different error messages per function. // It returns different error messages per function.
if member.atype < MembershipType::Admin { if member.atype < MembershipType::Admin {
match OrgPolicy::is_user_allowed(&member.user_uuid, &org_id, false, &mut conn).await { match OrgPolicy::is_user_allowed(&member.user_uuid, &org_id, false, &mut conn).await {
@ -1245,7 +1246,7 @@ async fn _confirm_invite(
err!("User in invalid state") err!("User in invalid state")
} }
// This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_membership_type // This check is also done at accept_invite(), _confirm_invite, _activate_membership(), edit_membership(), admin::update_membership_type
// It returns different error messages per function. // It returns different error messages per function.
if member_to_confirm.atype < MembershipType::Admin { if member_to_confirm.atype < MembershipType::Admin {
match OrgPolicy::is_user_allowed(&member_to_confirm.user_uuid, org_id, true, conn).await { match OrgPolicy::is_user_allowed(&member_to_confirm.user_uuid, org_id, true, conn).await {
@ -1336,11 +1337,11 @@ async fn put_membership(
headers: AdminHeaders, headers: AdminHeaders,
conn: DbConn, conn: DbConn,
) -> EmptyResult { ) -> EmptyResult {
edit_user(org_id, member_id, data, headers, conn).await edit_membership(org_id, member_id, data, headers, conn).await
} }
#[post("/organizations/<org_id>/users/<member_id>", data = "<data>", rank = 1)] #[post("/organizations/<org_id>/users/<member_id>", data = "<data>", rank = 1)]
async fn edit_user( async fn edit_membership(
org_id: OrganizationId, org_id: OrganizationId,
member_id: MembershipId, member_id: MembershipId,
data: Json<EditUserData>, data: Json<EditUserData>,
@ -1378,7 +1379,7 @@ async fn edit_user(
} }
} }
// This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_membership_type // This check is also done at accept_invite(), _confirm_invite, _activate_membership(), edit_membership(), admin::update_membership_type
// It returns different error messages per function. // It returns different error messages per function.
if new_type < MembershipType::Admin { if new_type < MembershipType::Admin {
match OrgPolicy::is_user_allowed(&member_to_edit.user_uuid, &org_id, true, &mut conn).await { match OrgPolicy::is_user_allowed(&member_to_edit.user_uuid, &org_id, true, &mut conn).await {
@ -2282,7 +2283,7 @@ async fn _restore_membership(
err!("Only owners can restore other owners") err!("Only owners can restore other owners")
} }
// This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_membership_type // This check is also done at accept_invite(), _confirm_invite, _activate_membership(), edit_membership(), admin::update_membership_type
// It returns different error messages per function. // It returns different error messages per function.
if member.atype < MembershipType::Admin { if member.atype < MembershipType::Admin {
match OrgPolicy::is_user_allowed(&member.user_uuid, org_id, false, conn).await { match OrgPolicy::is_user_allowed(&member.user_uuid, org_id, false, conn).await {

@ -3,7 +3,8 @@ use rocket::request::FromParam;
use serde_json::Value; use serde_json::Value;
use super::{ use super::{
CipherId, CollectionGroup, GroupUser, Membership, MembershipStatus, MembershipType, OrganizationId, User, UserId, CipherId, CollectionGroup, GroupUser, Membership, MembershipId, MembershipStatus, MembershipType, OrganizationId,
User, UserId,
}; };
use crate::CONFIG; use crate::CONFIG;
@ -527,8 +528,11 @@ impl CollectionUser {
}} }}
} }
pub async fn find_by_organization(org_uuid: &OrganizationId, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_organization_swap_user_uuid_with_member_uuid(
db_run! { conn: { org_uuid: &OrganizationId,
conn: &mut DbConn,
) -> Vec<CollectionMembership> {
let col_users = db_run! { conn: {
users_collections::table users_collections::table
.inner_join(collections::table.on(collections::uuid.eq(users_collections::collection_uuid))) .inner_join(collections::table.on(collections::uuid.eq(users_collections::collection_uuid)))
.filter(collections::org_uuid.eq(org_uuid)) .filter(collections::org_uuid.eq(org_uuid))
@ -537,7 +541,8 @@ impl CollectionUser {
.load::<CollectionUserDb>(conn) .load::<CollectionUserDb>(conn)
.expect("Error loading users_collections") .expect("Error loading users_collections")
.from_db() .from_db()
}} }};
col_users.into_iter().map(|c| c.into()).collect()
} }
pub async fn save( pub async fn save(
@ -626,8 +631,8 @@ impl CollectionUser {
pub async fn find_by_collection_swap_user_uuid_with_member_uuid( pub async fn find_by_collection_swap_user_uuid_with_member_uuid(
collection_uuid: &CollectionId, collection_uuid: &CollectionId,
conn: &mut DbConn, conn: &mut DbConn,
) -> Vec<Self> { ) -> Vec<CollectionMembership> {
db_run! { conn: { let col_users = db_run! { conn: {
users_collections::table users_collections::table
.filter(users_collections::collection_uuid.eq(collection_uuid)) .filter(users_collections::collection_uuid.eq(collection_uuid))
.inner_join(users_organizations::table.on(users_organizations::user_uuid.eq(users_collections::user_uuid))) .inner_join(users_organizations::table.on(users_organizations::user_uuid.eq(users_collections::user_uuid)))
@ -635,7 +640,8 @@ impl CollectionUser {
.load::<CollectionUserDb>(conn) .load::<CollectionUserDb>(conn)
.expect("Error loading users_collections") .expect("Error loading users_collections")
.from_db() .from_db()
}} }};
col_users.into_iter().map(|c| c.into()).collect()
} }
pub async fn find_by_collection_and_user( pub async fn find_by_collection_and_user(
@ -775,10 +781,18 @@ impl CollectionCipher {
} }
} }
impl CollectionUser { // Added in case we need the membership_uuid instead of the user_uuid
pub struct CollectionMembership {
pub membership_uuid: MembershipId,
pub collection_uuid: CollectionId,
pub read_only: bool,
pub hide_passwords: bool,
}
impl CollectionMembership {
pub fn to_json_details_for_user(&self) -> Value { pub fn to_json_details_for_user(&self) -> Value {
json!({ json!({
"id": self.user_uuid, "id": self.membership_uuid,
"readOnly": self.read_only, "readOnly": self.read_only,
"hidePasswords": self.hide_passwords, "hidePasswords": self.hide_passwords,
"manage": false "manage": false
@ -786,6 +800,17 @@ impl CollectionUser {
} }
} }
impl From<CollectionUser> for CollectionMembership {
fn from(c: CollectionUser) -> Self {
Self {
membership_uuid: c.user_uuid.to_string().into(),
collection_uuid: c.collection_uuid,
read_only: c.read_only,
hide_passwords: c.hide_passwords,
}
}
}
#[derive( #[derive(
Clone, Debug, AsRef, Deref, DieselNewType, Display, From, FromForm, Hash, PartialEq, Eq, Serialize, Deserialize, Clone, Debug, AsRef, Deref, DieselNewType, Display, From, FromForm, Hash, PartialEq, Eq, Serialize, Deserialize,
)] )]

Loading…
Cancel
Save