|
@@ -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")
|
|
|
+ }}
|
|
|
+ }
|
|
|
+}
|