mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2024-11-10 13:02:41 +01:00
Delete associated favorites when deleting a cipher or user
This prevents foreign key constraint violations.
This commit is contained in:
parent
4c324e1160
commit
175d647e47
@ -2,7 +2,15 @@ use chrono::{NaiveDateTime, Utc};
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Attachment, CollectionCipher, FolderCipher, Organization, User, UserOrgStatus, UserOrgType, UserOrganization,
|
Attachment,
|
||||||
|
CollectionCipher,
|
||||||
|
Favorite,
|
||||||
|
FolderCipher,
|
||||||
|
Organization,
|
||||||
|
User,
|
||||||
|
UserOrgStatus,
|
||||||
|
UserOrgType,
|
||||||
|
UserOrganization,
|
||||||
};
|
};
|
||||||
|
|
||||||
db_object! {
|
db_object! {
|
||||||
@ -213,6 +221,7 @@ impl Cipher {
|
|||||||
FolderCipher::delete_all_by_cipher(&self.uuid, conn)?;
|
FolderCipher::delete_all_by_cipher(&self.uuid, conn)?;
|
||||||
CollectionCipher::delete_all_by_cipher(&self.uuid, conn)?;
|
CollectionCipher::delete_all_by_cipher(&self.uuid, conn)?;
|
||||||
Attachment::delete_all_by_cipher(&self.uuid, conn)?;
|
Attachment::delete_all_by_cipher(&self.uuid, conn)?;
|
||||||
|
Favorite::delete_all_by_cipher(&self.uuid, conn)?;
|
||||||
|
|
||||||
db_run! { conn: {
|
db_run! { conn: {
|
||||||
diesel::delete(ciphers::table.filter(ciphers::uuid.eq(&self.uuid)))
|
diesel::delete(ciphers::table.filter(ciphers::uuid.eq(&self.uuid)))
|
||||||
@ -340,51 +349,14 @@ impl Cipher {
|
|||||||
|
|
||||||
// Returns whether this cipher is a favorite of the specified user.
|
// Returns whether this cipher is a favorite of the specified user.
|
||||||
pub fn is_favorite(&self, user_uuid: &str, conn: &DbConn) -> bool {
|
pub fn is_favorite(&self, user_uuid: &str, conn: &DbConn) -> bool {
|
||||||
db_run!{ conn: {
|
Favorite::is_favorite(&self.uuid, user_uuid, conn)
|
||||||
let query = favorites::table
|
|
||||||
.filter(favorites::user_uuid.eq(user_uuid))
|
|
||||||
.filter(favorites::cipher_uuid.eq(&self.uuid))
|
|
||||||
.count();
|
|
||||||
|
|
||||||
query.first::<i64>(conn).ok().unwrap_or(0) != 0
|
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates whether this cipher is a favorite of the specified user.
|
// Sets whether this cipher is a favorite of the specified user.
|
||||||
pub fn set_favorite(&self, favorite: Option<bool>, user_uuid: &str, conn: &DbConn) -> EmptyResult {
|
pub fn set_favorite(&self, favorite: Option<bool>, user_uuid: &str, conn: &DbConn) -> EmptyResult {
|
||||||
if favorite.is_none() {
|
match favorite {
|
||||||
// No change requested.
|
None => Ok(()), // No change requested.
|
||||||
return Ok(());
|
Some(status) => Favorite::set_favorite(status, &self.uuid, user_uuid, conn),
|
||||||
}
|
|
||||||
|
|
||||||
let (old, new) = (self.is_favorite(user_uuid, &conn), favorite.unwrap());
|
|
||||||
match (old, new) {
|
|
||||||
(false, true) => {
|
|
||||||
User::update_uuid_revision(user_uuid, &conn);
|
|
||||||
db_run!{ conn: {
|
|
||||||
diesel::insert_into(favorites::table)
|
|
||||||
.values((
|
|
||||||
favorites::user_uuid.eq(user_uuid),
|
|
||||||
favorites::cipher_uuid.eq(&self.uuid),
|
|
||||||
))
|
|
||||||
.execute(conn)
|
|
||||||
.map_res("Error adding favorite")
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
(true, false) => {
|
|
||||||
User::update_uuid_revision(user_uuid, &conn);
|
|
||||||
db_run!{ conn: {
|
|
||||||
diesel::delete(
|
|
||||||
favorites::table
|
|
||||||
.filter(favorites::user_uuid.eq(user_uuid))
|
|
||||||
.filter(favorites::cipher_uuid.eq(&self.uuid))
|
|
||||||
)
|
|
||||||
.execute(conn)
|
|
||||||
.map_res("Error removing favorite")
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
// Otherwise, the favorite status is already what it should be.
|
|
||||||
_ => Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
83
src/db/models/favorite.rs
Normal file
83
src/db/models/favorite.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
use super::{Cipher, User};
|
||||||
|
|
||||||
|
db_object! {
|
||||||
|
#[derive(Debug, Identifiable, Queryable, Insertable, Associations)]
|
||||||
|
#[table_name = "favorites"]
|
||||||
|
#[belongs_to(User, foreign_key = "user_uuid")]
|
||||||
|
#[belongs_to(Cipher, foreign_key = "cipher_uuid")]
|
||||||
|
#[primary_key(user_uuid, cipher_uuid)]
|
||||||
|
pub struct Favorite {
|
||||||
|
pub user_uuid: String,
|
||||||
|
pub cipher_uuid: String,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::db::DbConn;
|
||||||
|
|
||||||
|
use crate::api::EmptyResult;
|
||||||
|
use crate::error::MapResult;
|
||||||
|
|
||||||
|
impl Favorite {
|
||||||
|
// Returns whether the specified cipher is a favorite of the specified user.
|
||||||
|
pub fn is_favorite(cipher_uuid: &str, user_uuid: &str, conn: &DbConn) -> bool {
|
||||||
|
db_run!{ conn: {
|
||||||
|
let query = favorites::table
|
||||||
|
.filter(favorites::cipher_uuid.eq(cipher_uuid))
|
||||||
|
.filter(favorites::user_uuid.eq(user_uuid))
|
||||||
|
.count();
|
||||||
|
|
||||||
|
query.first::<i64>(conn).ok().unwrap_or(0) != 0
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets whether the specified cipher is a favorite of the specified user.
|
||||||
|
pub fn set_favorite(favorite: bool, cipher_uuid: &str, user_uuid: &str, conn: &DbConn) -> EmptyResult {
|
||||||
|
let (old, new) = (Self::is_favorite(cipher_uuid, user_uuid, &conn), favorite);
|
||||||
|
match (old, new) {
|
||||||
|
(false, true) => {
|
||||||
|
User::update_uuid_revision(user_uuid, &conn);
|
||||||
|
db_run!{ conn: {
|
||||||
|
diesel::insert_into(favorites::table)
|
||||||
|
.values((
|
||||||
|
favorites::user_uuid.eq(user_uuid),
|
||||||
|
favorites::cipher_uuid.eq(cipher_uuid),
|
||||||
|
))
|
||||||
|
.execute(conn)
|
||||||
|
.map_res("Error adding favorite")
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
(true, false) => {
|
||||||
|
User::update_uuid_revision(user_uuid, &conn);
|
||||||
|
db_run!{ conn: {
|
||||||
|
diesel::delete(
|
||||||
|
favorites::table
|
||||||
|
.filter(favorites::user_uuid.eq(user_uuid))
|
||||||
|
.filter(favorites::cipher_uuid.eq(cipher_uuid))
|
||||||
|
)
|
||||||
|
.execute(conn)
|
||||||
|
.map_res("Error removing favorite")
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
// Otherwise, the favorite status is already what it should be.
|
||||||
|
_ => Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete all favorite entries associated with the specified cipher.
|
||||||
|
pub fn delete_all_by_cipher(cipher_uuid: &str, conn: &DbConn) -> EmptyResult {
|
||||||
|
db_run! { conn: {
|
||||||
|
diesel::delete(favorites::table.filter(favorites::cipher_uuid.eq(cipher_uuid)))
|
||||||
|
.execute(conn)
|
||||||
|
.map_res("Error removing favorites by cipher")
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete all favorite entries associated with the specified user.
|
||||||
|
pub fn delete_all_by_user(user_uuid: &str, conn: &DbConn) -> EmptyResult {
|
||||||
|
db_run! { conn: {
|
||||||
|
diesel::delete(favorites::table.filter(favorites::user_uuid.eq(user_uuid)))
|
||||||
|
.execute(conn)
|
||||||
|
.map_res("Error removing favorites by user")
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
}
|
@ -1,21 +1,21 @@
|
|||||||
mod attachment;
|
mod attachment;
|
||||||
mod cipher;
|
mod cipher;
|
||||||
mod device;
|
|
||||||
mod folder;
|
|
||||||
mod user;
|
|
||||||
|
|
||||||
mod collection;
|
mod collection;
|
||||||
|
mod device;
|
||||||
|
mod favorite;
|
||||||
|
mod folder;
|
||||||
|
mod org_policy;
|
||||||
mod organization;
|
mod organization;
|
||||||
mod two_factor;
|
mod two_factor;
|
||||||
mod org_policy;
|
mod user;
|
||||||
|
|
||||||
pub use self::attachment::Attachment;
|
pub use self::attachment::Attachment;
|
||||||
pub use self::cipher::Cipher;
|
pub use self::cipher::Cipher;
|
||||||
pub use self::collection::{Collection, CollectionCipher, CollectionUser};
|
pub use self::collection::{Collection, CollectionCipher, CollectionUser};
|
||||||
pub use self::device::Device;
|
pub use self::device::Device;
|
||||||
|
pub use self::favorite::Favorite;
|
||||||
pub use self::folder::{Folder, FolderCipher};
|
pub use self::folder::{Folder, FolderCipher};
|
||||||
pub use self::organization::Organization;
|
pub use self::org_policy::{OrgPolicy, OrgPolicyType};
|
||||||
pub use self::organization::{UserOrgStatus, UserOrgType, UserOrganization};
|
pub use self::organization::{Organization, UserOrgStatus, UserOrgType, UserOrganization};
|
||||||
pub use self::two_factor::{TwoFactor, TwoFactorType};
|
pub use self::two_factor::{TwoFactor, TwoFactorType};
|
||||||
pub use self::user::{Invitation, User};
|
pub use self::user::{Invitation, User};
|
||||||
pub use self::org_policy::{OrgPolicy, OrgPolicyType};
|
|
@ -128,7 +128,7 @@ impl User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use super::{Cipher, Device, Folder, TwoFactor, UserOrgType, UserOrganization};
|
use super::{Cipher, Device, Favorite, Folder, TwoFactor, UserOrgType, UserOrganization};
|
||||||
use crate::db::DbConn;
|
use crate::db::DbConn;
|
||||||
|
|
||||||
use crate::api::EmptyResult;
|
use crate::api::EmptyResult;
|
||||||
@ -205,6 +205,7 @@ impl User {
|
|||||||
|
|
||||||
UserOrganization::delete_all_by_user(&self.uuid, conn)?;
|
UserOrganization::delete_all_by_user(&self.uuid, conn)?;
|
||||||
Cipher::delete_all_by_user(&self.uuid, conn)?;
|
Cipher::delete_all_by_user(&self.uuid, conn)?;
|
||||||
|
Favorite::delete_all_by_user(&self.uuid, conn)?;
|
||||||
Folder::delete_all_by_user(&self.uuid, conn)?;
|
Folder::delete_all_by_user(&self.uuid, conn)?;
|
||||||
Device::delete_all_by_user(&self.uuid, conn)?;
|
Device::delete_all_by_user(&self.uuid, conn)?;
|
||||||
TwoFactor::delete_all_by_user(&self.uuid, conn)?;
|
TwoFactor::delete_all_by_user(&self.uuid, conn)?;
|
||||||
|
Loading…
Reference in New Issue
Block a user