17 changed files with 1188 additions and 19 deletions
			
			
		| @ -0,0 +1,3 @@ | |||||
|  | DROP TABLE `groups`; | ||||
|  | DROP TABLE groups_users; | ||||
|  | DROP TABLE collections_groups; | ||||
| @ -0,0 +1,23 @@ | |||||
|  | CREATE TABLE `groups` ( | ||||
|  |   uuid                              CHAR(36) NOT NULL PRIMARY KEY, | ||||
|  |   organizations_uuid                VARCHAR(40) NOT NULL REFERENCES organizations (uuid), | ||||
|  |   name                              VARCHAR(100) NOT NULL, | ||||
|  |   access_all                        BOOLEAN NOT NULL, | ||||
|  |   external_id                       VARCHAR(300) NULL, | ||||
|  |   creation_date                     DATETIME NOT NULL, | ||||
|  |   revision_date                     DATETIME NOT NULL | ||||
|  | ); | ||||
|  | 
 | ||||
|  | CREATE TABLE groups_users ( | ||||
|  |   groups_uuid                       CHAR(36) NOT NULL REFERENCES `groups` (uuid), | ||||
|  |   users_organizations_uuid          VARCHAR(36) NOT NULL REFERENCES users_organizations (uuid), | ||||
|  |   UNIQUE (groups_uuid, users_organizations_uuid) | ||||
|  | ); | ||||
|  | 
 | ||||
|  | CREATE TABLE collections_groups ( | ||||
|  |   collections_uuid                  VARCHAR(40) NOT NULL REFERENCES collections (uuid), | ||||
|  |   groups_uuid                       CHAR(36) NOT NULL REFERENCES `groups` (uuid), | ||||
|  |   read_only                         BOOLEAN NOT NULL, | ||||
|  |   hide_passwords                    BOOLEAN NOT NULL, | ||||
|  |   UNIQUE (collections_uuid, groups_uuid) | ||||
|  | ); | ||||
| @ -0,0 +1,3 @@ | |||||
|  | DROP TABLE groups; | ||||
|  | DROP TABLE groups_users; | ||||
|  | DROP TABLE collections_groups; | ||||
| @ -0,0 +1,23 @@ | |||||
|  | CREATE TABLE groups ( | ||||
|  |   uuid                              CHAR(36) NOT NULL PRIMARY KEY, | ||||
|  |   organizations_uuid                 VARCHAR(40) NOT NULL REFERENCES organizations (uuid), | ||||
|  |   name                              VARCHAR(100) NOT NULL, | ||||
|  |   access_all                        BOOLEAN NOT NULL, | ||||
|  |   external_id                       VARCHAR(300) NULL, | ||||
|  |   creation_date                     TIMESTAMP NOT NULL, | ||||
|  |   revision_date                     TIMESTAMP NOT NULL | ||||
|  | ); | ||||
|  | 
 | ||||
|  | CREATE TABLE groups_users ( | ||||
|  |   groups_uuid                       CHAR(36) NOT NULL REFERENCES groups (uuid), | ||||
|  |   users_organizations_uuid          VARCHAR(36) NOT NULL REFERENCES users_organizations (uuid), | ||||
|  |   PRIMARY KEY (groups_uuid, users_organizations_uuid) | ||||
|  | ); | ||||
|  | 
 | ||||
|  | CREATE TABLE collections_groups ( | ||||
|  |   collections_uuid                  VARCHAR(40) NOT NULL REFERENCES collections (uuid), | ||||
|  |   groups_uuid                       CHAR(36) NOT NULL REFERENCES groups (uuid), | ||||
|  |   read_only                         BOOLEAN NOT NULL, | ||||
|  |   hide_passwords                    BOOLEAN NOT NULL, | ||||
|  |   PRIMARY KEY (collections_uuid, groups_uuid) | ||||
|  | ); | ||||
| @ -0,0 +1,3 @@ | |||||
|  | DROP TABLE groups; | ||||
|  | DROP TABLE groups_users; | ||||
|  | DROP TABLE collections_groups; | ||||
| @ -0,0 +1,23 @@ | |||||
|  | CREATE TABLE groups ( | ||||
|  |   uuid                              TEXT NOT NULL PRIMARY KEY, | ||||
|  |   organizations_uuid                TEXT NOT NULL REFERENCES organizations (uuid), | ||||
|  |   name                              TEXT NOT NULL, | ||||
|  |   access_all                        BOOLEAN NOT NULL, | ||||
|  |   external_id                       TEXT NULL, | ||||
|  |   creation_date                     TIMESTAMP NOT NULL, | ||||
|  |   revision_date                     TIMESTAMP NOT NULL | ||||
|  | ); | ||||
|  | 
 | ||||
|  | CREATE TABLE groups_users ( | ||||
|  |   groups_uuid                       TEXT NOT NULL REFERENCES groups (uuid), | ||||
|  |   users_organizations_uuid          TEXT NOT NULL REFERENCES users_organizations (uuid), | ||||
|  |   UNIQUE (groups_uuid, users_organizations_uuid) | ||||
|  | ); | ||||
|  | 
 | ||||
|  | CREATE TABLE collections_groups ( | ||||
|  |   collections_uuid                  TEXT NOT NULL REFERENCES collections (uuid), | ||||
|  |   groups_uuid                       TEXT NOT NULL REFERENCES groups (uuid), | ||||
|  |   read_only                         BOOLEAN NOT NULL, | ||||
|  |   hide_passwords                    BOOLEAN NOT NULL, | ||||
|  |   UNIQUE (collections_uuid, groups_uuid) | ||||
|  | ); | ||||
| @ -0,0 +1,501 @@ | |||||
|  | use chrono::{NaiveDateTime, Utc}; | ||||
|  | use serde_json::Value; | ||||
|  | 
 | ||||
|  | db_object! { | ||||
|  |     #[derive(Identifiable, Queryable, Insertable, AsChangeset)] | ||||
|  |     #[table_name = "groups"] | ||||
|  |     #[primary_key(uuid)] | ||||
|  |     pub struct Group { | ||||
|  |         pub uuid: String, | ||||
|  |         pub organizations_uuid: String, | ||||
|  |         pub name: String, | ||||
|  |         pub access_all: bool, | ||||
|  |         external_id: Option<String>, | ||||
|  |         pub creation_date: NaiveDateTime, | ||||
|  |         pub revision_date: NaiveDateTime, | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     #[derive(Identifiable, Queryable, Insertable)] | ||||
|  |     #[table_name = "collections_groups"] | ||||
|  |     #[primary_key(collections_uuid, groups_uuid)] | ||||
|  |     pub struct CollectionGroup { | ||||
|  |         pub collections_uuid: String, | ||||
|  |         pub groups_uuid: String, | ||||
|  |         pub read_only: bool, | ||||
|  |         pub hide_passwords: bool, | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     #[derive(Identifiable, Queryable, Insertable)] | ||||
|  |     #[table_name = "groups_users"] | ||||
|  |     #[primary_key(groups_uuid, users_organizations_uuid)] | ||||
|  |     pub struct GroupUser { | ||||
|  |         pub groups_uuid: String, | ||||
|  |         pub users_organizations_uuid: String | ||||
|  |     } | ||||
|  | } | ||||
|  | 
 | ||||
|  | /// Local methods
 | ||||
|  | impl Group { | ||||
|  |     pub fn new(organizations_uuid: String, name: String, access_all: bool, external_id: Option<String>) -> Self { | ||||
|  |         let now = Utc::now().naive_utc(); | ||||
|  | 
 | ||||
|  |         let mut new_model = Self { | ||||
|  |             uuid: crate::util::get_uuid(), | ||||
|  |             organizations_uuid, | ||||
|  |             name, | ||||
|  |             access_all, | ||||
|  |             external_id: None, | ||||
|  |             creation_date: now, | ||||
|  |             revision_date: now, | ||||
|  |         }; | ||||
|  | 
 | ||||
|  |         new_model.set_external_id(external_id); | ||||
|  | 
 | ||||
|  |         new_model | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub fn to_json(&self) -> Value { | ||||
|  |         use crate::util::format_date; | ||||
|  | 
 | ||||
|  |         json!({ | ||||
|  |             "Id": self.uuid, | ||||
|  |             "OrganizationId": self.organizations_uuid, | ||||
|  |             "Name": self.name, | ||||
|  |             "AccessAll": self.access_all, | ||||
|  |             "ExternalId": self.external_id, | ||||
|  |             "CreationDate": format_date(&self.creation_date), | ||||
|  |             "RevisionDate": format_date(&self.revision_date) | ||||
|  |         }) | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub fn set_external_id(&mut self, external_id: Option<String>) { | ||||
|  |         //Check if external id is empty. We don't want to have
 | ||||
|  |         //empty strings in the database
 | ||||
|  |         match external_id { | ||||
|  |             Some(external_id) => { | ||||
|  |                 if external_id.is_empty() { | ||||
|  |                     self.external_id = None; | ||||
|  |                 } else { | ||||
|  |                     self.external_id = Some(external_id) | ||||
|  |                 } | ||||
|  |             } | ||||
|  |             None => self.external_id = None, | ||||
|  |         } | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub fn get_external_id(&self) -> Option<String> { | ||||
|  |         self.external_id.clone() | ||||
|  |     } | ||||
|  | } | ||||
|  | 
 | ||||
|  | impl CollectionGroup { | ||||
|  |     pub fn new(collections_uuid: String, groups_uuid: String, read_only: bool, hide_passwords: bool) -> Self { | ||||
|  |         Self { | ||||
|  |             collections_uuid, | ||||
|  |             groups_uuid, | ||||
|  |             read_only, | ||||
|  |             hide_passwords, | ||||
|  |         } | ||||
|  |     } | ||||
|  | } | ||||
|  | 
 | ||||
|  | impl GroupUser { | ||||
|  |     pub fn new(groups_uuid: String, users_organizations_uuid: String) -> Self { | ||||
|  |         Self { | ||||
|  |             groups_uuid, | ||||
|  |             users_organizations_uuid, | ||||
|  |         } | ||||
|  |     } | ||||
|  | } | ||||
|  | 
 | ||||
|  | use crate::db::DbConn; | ||||
|  | 
 | ||||
|  | use crate::api::EmptyResult; | ||||
|  | use crate::error::MapResult; | ||||
|  | 
 | ||||
|  | use super::{User, UserOrganization}; | ||||
|  | 
 | ||||
|  | /// Database methods
 | ||||
|  | impl Group { | ||||
|  |     pub async fn save(&mut self, conn: &DbConn) -> EmptyResult { | ||||
|  |         self.revision_date = Utc::now().naive_utc(); | ||||
|  | 
 | ||||
|  |         db_run! { conn: | ||||
|  |             sqlite, mysql { | ||||
|  |                 match diesel::replace_into(groups::table) | ||||
|  |                     .values(GroupDb::to_db(self)) | ||||
|  |                     .execute(conn) | ||||
|  |                 { | ||||
|  |                     Ok(_) => Ok(()), | ||||
|  |                     // Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
 | ||||
|  |                     Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => { | ||||
|  |                         diesel::update(groups::table) | ||||
|  |                             .filter(groups::uuid.eq(&self.uuid)) | ||||
|  |                             .set(GroupDb::to_db(self)) | ||||
|  |                             .execute(conn) | ||||
|  |                             .map_res("Error saving group") | ||||
|  |                     } | ||||
|  |                     Err(e) => Err(e.into()), | ||||
|  |                 }.map_res("Error saving group") | ||||
|  |             } | ||||
|  |             postgresql { | ||||
|  |                 let value = GroupDb::to_db(self); | ||||
|  |                 diesel::insert_into(groups::table) | ||||
|  |                     .values(&value) | ||||
|  |                     .on_conflict(groups::uuid) | ||||
|  |                     .do_update() | ||||
|  |                     .set(&value) | ||||
|  |                     .execute(conn) | ||||
|  |                     .map_res("Error saving group") | ||||
|  |             } | ||||
|  |         } | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn find_by_organization(organizations_uuid: &str, conn: &DbConn) -> Vec<Self> { | ||||
|  |         db_run! { conn: { | ||||
|  |             groups::table | ||||
|  |                 .filter(groups::organizations_uuid.eq(organizations_uuid)) | ||||
|  |                 .load::<GroupDb>(conn) | ||||
|  |                 .expect("Error loading groups") | ||||
|  |                 .from_db() | ||||
|  |         }} | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Self> { | ||||
|  |         db_run! { conn: { | ||||
|  |             groups::table | ||||
|  |                 .filter(groups::uuid.eq(uuid)) | ||||
|  |                 .first::<GroupDb>(conn) | ||||
|  |                 .ok() | ||||
|  |                 .from_db() | ||||
|  |         }} | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     //Returns all organizations the user has full access to
 | ||||
|  |     pub async fn gather_user_organizations_full_access(user_uuid: &str, conn: &DbConn) -> Vec<String> { | ||||
|  |         db_run! { conn: { | ||||
|  |             groups_users::table | ||||
|  |                 .inner_join(users_organizations::table.on( | ||||
|  |                     users_organizations::uuid.eq(groups_users::users_organizations_uuid) | ||||
|  |                 )) | ||||
|  |                 .inner_join(groups::table.on( | ||||
|  |                     groups::uuid.eq(groups_users::groups_uuid) | ||||
|  |                 )) | ||||
|  |                 .filter(users_organizations::user_uuid.eq(user_uuid)) | ||||
|  |                 .filter(groups::access_all.eq(true)) | ||||
|  |                 .select(groups::organizations_uuid) | ||||
|  |                 .distinct() | ||||
|  |                 .load::<String>(conn) | ||||
|  |                 .expect("Error loading organization group full access information for user") | ||||
|  |         }} | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn is_in_full_access_group(user_uuid: &str, org_uuid: &str, conn: &DbConn) -> bool { | ||||
|  |         db_run! { conn: { | ||||
|  |             groups::table | ||||
|  |                 .inner_join(groups_users::table.on( | ||||
|  |                     groups_users::groups_uuid.eq(groups::uuid) | ||||
|  |                 )) | ||||
|  |                 .inner_join(users_organizations::table.on( | ||||
|  |                     users_organizations::uuid.eq(groups_users::users_organizations_uuid) | ||||
|  |                 )) | ||||
|  |                 .filter(users_organizations::user_uuid.eq(user_uuid)) | ||||
|  |                 .filter(groups::organizations_uuid.eq(org_uuid)) | ||||
|  |                 .filter(groups::access_all.eq(true)) | ||||
|  |                 .select(groups::access_all) | ||||
|  |                 .first::<bool>(conn) | ||||
|  |                 .unwrap_or_default() | ||||
|  |         }} | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn delete(&self, conn: &DbConn) -> EmptyResult { | ||||
|  |         CollectionGroup::delete_all_by_group(&self.uuid, conn).await?; | ||||
|  |         GroupUser::delete_all_by_group(&self.uuid, conn).await?; | ||||
|  | 
 | ||||
|  |         db_run! { conn: { | ||||
|  |             diesel::delete(groups::table.filter(groups::uuid.eq(&self.uuid))) | ||||
|  |                 .execute(conn) | ||||
|  |                 .map_res("Error deleting group") | ||||
|  |         }} | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn update_revision(uuid: &str, conn: &DbConn) { | ||||
|  |         if let Err(e) = Self::_update_revision(uuid, &Utc::now().naive_utc(), conn).await { | ||||
|  |             warn!("Failed to update revision for {}: {:#?}", uuid, e); | ||||
|  |         } | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     async fn _update_revision(uuid: &str, date: &NaiveDateTime, conn: &DbConn) -> EmptyResult { | ||||
|  |         db_run! {conn: { | ||||
|  |             crate::util::retry(|| { | ||||
|  |                 diesel::update(groups::table.filter(groups::uuid.eq(uuid))) | ||||
|  |                     .set(groups::revision_date.eq(date)) | ||||
|  |                     .execute(conn) | ||||
|  |             }, 10) | ||||
|  |             .map_res("Error updating group revision") | ||||
|  |         }} | ||||
|  |     } | ||||
|  | } | ||||
|  | 
 | ||||
|  | impl CollectionGroup { | ||||
|  |     pub async fn save(&mut self, conn: &DbConn) -> EmptyResult { | ||||
|  |         let group_users = GroupUser::find_by_group(&self.groups_uuid, conn).await; | ||||
|  |         for group_user in group_users { | ||||
|  |             group_user.update_user_revision(conn).await; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         db_run! { conn: | ||||
|  |             sqlite, mysql { | ||||
|  |                 match diesel::replace_into(collections_groups::table) | ||||
|  |                     .values(( | ||||
|  |                         collections_groups::collections_uuid.eq(&self.collections_uuid), | ||||
|  |                         collections_groups::groups_uuid.eq(&self.groups_uuid), | ||||
|  |                         collections_groups::read_only.eq(&self.read_only), | ||||
|  |                         collections_groups::hide_passwords.eq(&self.hide_passwords), | ||||
|  |                     )) | ||||
|  |                     .execute(conn) | ||||
|  |                 { | ||||
|  |                     Ok(_) => Ok(()), | ||||
|  |                     // Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
 | ||||
|  |                     Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => { | ||||
|  |                         diesel::update(collections_groups::table) | ||||
|  |                             .filter(collections_groups::collections_uuid.eq(&self.collections_uuid)) | ||||
|  |                             .filter(collections_groups::groups_uuid.eq(&self.groups_uuid)) | ||||
|  |                             .set(( | ||||
|  |                                 collections_groups::collections_uuid.eq(&self.collections_uuid), | ||||
|  |                                 collections_groups::groups_uuid.eq(&self.groups_uuid), | ||||
|  |                                 collections_groups::read_only.eq(&self.read_only), | ||||
|  |                                 collections_groups::hide_passwords.eq(&self.hide_passwords), | ||||
|  |                             )) | ||||
|  |                             .execute(conn) | ||||
|  |                             .map_res("Error adding group to collection") | ||||
|  |                     } | ||||
|  |                     Err(e) => Err(e.into()), | ||||
|  |                 }.map_res("Error adding group to collection") | ||||
|  |             } | ||||
|  |             postgresql { | ||||
|  |                 diesel::insert_into(collections_groups::table) | ||||
|  |                     .values(( | ||||
|  |                         collections_groups::collections_uuid.eq(&self.collections_uuid), | ||||
|  |                         collections_groups::groups_uuid.eq(&self.groups_uuid), | ||||
|  |                         collections_groups::read_only.eq(self.read_only), | ||||
|  |                         collections_groups::hide_passwords.eq(self.hide_passwords), | ||||
|  |                     )) | ||||
|  |                     .on_conflict((collections_groups::collections_uuid, collections_groups::groups_uuid)) | ||||
|  |                     .do_update() | ||||
|  |                     .set(( | ||||
|  |                         collections_groups::read_only.eq(self.read_only), | ||||
|  |                         collections_groups::hide_passwords.eq(self.hide_passwords), | ||||
|  |                     )) | ||||
|  |                     .execute(conn) | ||||
|  |                     .map_res("Error adding group to collection") | ||||
|  |             } | ||||
|  |         } | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn find_by_group(group_uuid: &str, conn: &DbConn) -> Vec<Self> { | ||||
|  |         db_run! { conn: { | ||||
|  |             collections_groups::table | ||||
|  |                 .filter(collections_groups::groups_uuid.eq(group_uuid)) | ||||
|  |                 .load::<CollectionGroupDb>(conn) | ||||
|  |                 .expect("Error loading collection groups") | ||||
|  |                 .from_db() | ||||
|  |         }} | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn find_by_user(user_uuid: &str, conn: &DbConn) -> Vec<Self> { | ||||
|  |         db_run! { conn: { | ||||
|  |             collections_groups::table | ||||
|  |                 .inner_join(groups_users::table.on( | ||||
|  |                     groups_users::groups_uuid.eq(collections_groups::groups_uuid) | ||||
|  |                 )) | ||||
|  |                 .inner_join(users_organizations::table.on( | ||||
|  |                     users_organizations::uuid.eq(groups_users::users_organizations_uuid) | ||||
|  |                 )) | ||||
|  |                 .filter(users_organizations::user_uuid.eq(user_uuid)) | ||||
|  |                 .select(collections_groups::all_columns) | ||||
|  |                 .load::<CollectionGroupDb>(conn) | ||||
|  |                 .expect("Error loading user collection groups") | ||||
|  |                 .from_db() | ||||
|  |         }} | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn find_by_collection(collection_uuid: &str, conn: &DbConn) -> Vec<Self> { | ||||
|  |         db_run! { conn: { | ||||
|  |             collections_groups::table | ||||
|  |                 .filter(collections_groups::collections_uuid.eq(collection_uuid)) | ||||
|  |                 .select(collections_groups::all_columns) | ||||
|  |                 .load::<CollectionGroupDb>(conn) | ||||
|  |                 .expect("Error loading collection groups") | ||||
|  |                 .from_db() | ||||
|  |         }} | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn delete(&self, conn: &DbConn) -> EmptyResult { | ||||
|  |         let group_users = GroupUser::find_by_group(&self.groups_uuid, conn).await; | ||||
|  |         for group_user in group_users { | ||||
|  |             group_user.update_user_revision(conn).await; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         db_run! { conn: { | ||||
|  |             diesel::delete(collections_groups::table) | ||||
|  |                 .filter(collections_groups::collections_uuid.eq(&self.collections_uuid)) | ||||
|  |                 .filter(collections_groups::groups_uuid.eq(&self.groups_uuid)) | ||||
|  |                 .execute(conn) | ||||
|  |                 .map_res("Error deleting collection group") | ||||
|  |         }} | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn delete_all_by_group(group_uuid: &str, conn: &DbConn) -> EmptyResult { | ||||
|  |         let group_users = GroupUser::find_by_group(group_uuid, conn).await; | ||||
|  |         for group_user in group_users { | ||||
|  |             group_user.update_user_revision(conn).await; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         db_run! { conn: { | ||||
|  |             diesel::delete(collections_groups::table) | ||||
|  |                 .filter(collections_groups::groups_uuid.eq(group_uuid)) | ||||
|  |                 .execute(conn) | ||||
|  |                 .map_res("Error deleting collection group") | ||||
|  |         }} | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn delete_all_by_collection(collection_uuid: &str, conn: &DbConn) -> EmptyResult { | ||||
|  |         let collection_assigned_to_groups = CollectionGroup::find_by_collection(collection_uuid, conn).await; | ||||
|  |         for collection_assigned_to_group in collection_assigned_to_groups { | ||||
|  |             let group_users = GroupUser::find_by_group(&collection_assigned_to_group.groups_uuid, conn).await; | ||||
|  |             for group_user in group_users { | ||||
|  |                 group_user.update_user_revision(conn).await; | ||||
|  |             } | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         db_run! { conn: { | ||||
|  |             diesel::delete(collections_groups::table) | ||||
|  |                 .filter(collections_groups::collections_uuid.eq(collection_uuid)) | ||||
|  |                 .execute(conn) | ||||
|  |                 .map_res("Error deleting collection group") | ||||
|  |         }} | ||||
|  |     } | ||||
|  | } | ||||
|  | 
 | ||||
|  | impl GroupUser { | ||||
|  |     pub async fn save(&mut self, conn: &DbConn) -> EmptyResult { | ||||
|  |         self.update_user_revision(conn).await; | ||||
|  | 
 | ||||
|  |         db_run! { conn: | ||||
|  |             sqlite, mysql { | ||||
|  |                 match diesel::replace_into(groups_users::table) | ||||
|  |                     .values(( | ||||
|  |                         groups_users::users_organizations_uuid.eq(&self.users_organizations_uuid), | ||||
|  |                         groups_users::groups_uuid.eq(&self.groups_uuid), | ||||
|  |                     )) | ||||
|  |                     .execute(conn) | ||||
|  |                 { | ||||
|  |                     Ok(_) => Ok(()), | ||||
|  |                     // Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
 | ||||
|  |                     Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => { | ||||
|  |                         diesel::update(groups_users::table) | ||||
|  |                             .filter(groups_users::users_organizations_uuid.eq(&self.users_organizations_uuid)) | ||||
|  |                             .filter(groups_users::groups_uuid.eq(&self.groups_uuid)) | ||||
|  |                             .set(( | ||||
|  |                                 groups_users::users_organizations_uuid.eq(&self.users_organizations_uuid), | ||||
|  |                                 groups_users::groups_uuid.eq(&self.groups_uuid), | ||||
|  |                             )) | ||||
|  |                             .execute(conn) | ||||
|  |                             .map_res("Error adding user to group") | ||||
|  |                     } | ||||
|  |                     Err(e) => Err(e.into()), | ||||
|  |                 }.map_res("Error adding user to group") | ||||
|  |             } | ||||
|  |             postgresql { | ||||
|  |                 diesel::insert_into(groups_users::table) | ||||
|  |                     .values(( | ||||
|  |                         groups_users::users_organizations_uuid.eq(&self.users_organizations_uuid), | ||||
|  |                         groups_users::groups_uuid.eq(&self.groups_uuid), | ||||
|  |                     )) | ||||
|  |                     .on_conflict((groups_users::users_organizations_uuid, groups_users::groups_uuid)) | ||||
|  |                     .do_update() | ||||
|  |                     .set(( | ||||
|  |                         groups_users::users_organizations_uuid.eq(&self.users_organizations_uuid), | ||||
|  |                         groups_users::groups_uuid.eq(&self.groups_uuid), | ||||
|  |                     )) | ||||
|  |                     .execute(conn) | ||||
|  |                     .map_res("Error adding user to group") | ||||
|  |             } | ||||
|  |         } | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn find_by_group(group_uuid: &str, conn: &DbConn) -> Vec<Self> { | ||||
|  |         db_run! { conn: { | ||||
|  |             groups_users::table | ||||
|  |                 .filter(groups_users::groups_uuid.eq(group_uuid)) | ||||
|  |                 .load::<GroupUserDb>(conn) | ||||
|  |                 .expect("Error loading group users") | ||||
|  |                 .from_db() | ||||
|  |         }} | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn find_by_user(users_organizations_uuid: &str, conn: &DbConn) -> Vec<Self> { | ||||
|  |         db_run! { conn: { | ||||
|  |             groups_users::table | ||||
|  |                 .filter(groups_users::users_organizations_uuid.eq(users_organizations_uuid)) | ||||
|  |                 .load::<GroupUserDb>(conn) | ||||
|  |                 .expect("Error loading groups for user") | ||||
|  |                 .from_db() | ||||
|  |         }} | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn update_user_revision(&self, conn: &DbConn) { | ||||
|  |         match UserOrganization::find_by_uuid(&self.users_organizations_uuid, conn).await { | ||||
|  |             Some(user) => User::update_uuid_revision(&user.user_uuid, conn).await, | ||||
|  |             None => warn!("User could not be found!"), | ||||
|  |         } | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn delete_by_group_id_and_user_id( | ||||
|  |         group_uuid: &str, | ||||
|  |         users_organizations_uuid: &str, | ||||
|  |         conn: &DbConn, | ||||
|  |     ) -> EmptyResult { | ||||
|  |         match UserOrganization::find_by_uuid(users_organizations_uuid, conn).await { | ||||
|  |             Some(user) => User::update_uuid_revision(&user.user_uuid, conn).await, | ||||
|  |             None => warn!("User could not be found!"), | ||||
|  |         }; | ||||
|  | 
 | ||||
|  |         db_run! { conn: { | ||||
|  |             diesel::delete(groups_users::table) | ||||
|  |                 .filter(groups_users::groups_uuid.eq(group_uuid)) | ||||
|  |                 .filter(groups_users::users_organizations_uuid.eq(users_organizations_uuid)) | ||||
|  |                 .execute(conn) | ||||
|  |                 .map_res("Error deleting group users") | ||||
|  |         }} | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn delete_all_by_group(group_uuid: &str, conn: &DbConn) -> EmptyResult { | ||||
|  |         let group_users = GroupUser::find_by_group(group_uuid, conn).await; | ||||
|  |         for group_user in group_users { | ||||
|  |             group_user.update_user_revision(conn).await; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         db_run! { conn: { | ||||
|  |             diesel::delete(groups_users::table) | ||||
|  |                 .filter(groups_users::groups_uuid.eq(group_uuid)) | ||||
|  |                 .execute(conn) | ||||
|  |                 .map_res("Error deleting group users") | ||||
|  |         }} | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     pub async fn delete_all_by_user(users_organizations_uuid: &str, conn: &DbConn) -> EmptyResult { | ||||
|  |         match UserOrganization::find_by_uuid(users_organizations_uuid, conn).await { | ||||
|  |             Some(user) => User::update_uuid_revision(&user.user_uuid, conn).await, | ||||
|  |             None => warn!("User could not be found!"), | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         db_run! { conn: { | ||||
|  |             diesel::delete(groups_users::table) | ||||
|  |                 .filter(groups_users::users_organizations_uuid.eq(users_organizations_uuid)) | ||||
|  |                 .execute(conn) | ||||
|  |                 .map_res("Error deleting user groups") | ||||
|  |         }} | ||||
|  |     } | ||||
|  | } | ||||
					Loading…
					
					
				
		Reference in new issue