Spiegel von
https://github.com/dani-garcia/vaultwarden.git
synchronisiert 2025-01-08 11:55:42 +01:00
add collection_membership type
Dieser Commit ist enthalten in:
Ursprung
6355985539
Commit
3d42b66a10
2 geänderte Dateien mit 53 neuen und 27 gelöschten Zeilen
|
@ -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,
|
||||||
)]
|
)]
|
||||||
|
|
Laden …
In neuem Issue referenzieren