(ns metabase-enterprise.advanced-permissions.models.permissions.group-manager (:require [clojure.data :as data] [clojure.set :as set] [metabase.api.common :as api] [metabase.util :as u] [metabase.util.i18n :refer [tru]] [toucan2.core :as t2])) | |
Return a list of group memberships a User belongs to. Group Membership is a map with 2 keys [:id :isgroupmanager]. | (defn user-group-memberships [user-or-id] (when user-or-id (t2/select [:model/PermissionsGroupMembership [:group_id :id] :is_group_manager] :user_id (u/the-id user-or-id)))) |
Transform user-group-memberships to a map in which keys are group-ids and values are maps containing membership info. [{:id 1, :isgroupmanager true}] => {1 {:isgroupmanager true}} We can diff this map to decide which membership to add/remove. | (defn- user-group-memberships->map [user-group-memberships] (into {} (map (fn [x] [(:id x) (dissoc x :id)]) user-group-memberships))) |
Fill in missing :isgroupmanager values to be based on existing values, or 'false' if not set | (defn- complete-membership-info [new-user-info old-user-info] (map #(cond-> % (nil? (:is_group_manager %)) (assoc :is_group_manager (boolean (-> % :id old-user-info :is_group_manager)))) new-user-info)) |
Update Groups Memberships of a User when | (defn set-user-group-memberships! [user-or-id new-user-group-memberships] (let [user-id (u/the-id user-or-id) old-user-group-memberships (user-group-memberships user-id) old-group-id->membership-info (user-group-memberships->map old-user-group-memberships) new-group-id->membership-info (user-group-memberships->map (complete-membership-info new-user-group-memberships old-group-id->membership-info)) [to-remove to-add] (data/diff old-group-id->membership-info new-group-id->membership-info) to-remove-group-ids (keys to-remove) to-add-group-ids (keys to-add)] (when (or (seq to-remove-group-ids) (seq to-add-group-ids)) ;; TODO: Should do this check in the API layer (when-not api/*is-superuser?* ;; prevent groups manager from update membership of groups that they're not manager of (when-not (and api/*is-group-manager?* (set/subset? (set (concat to-remove-group-ids to-add-group-ids)) (t2/select-fn-set :group_id :model/PermissionsGroupMembership :user_id api/*current-user-id* :is_group_manager true))) (throw (ex-info (tru "Not allowed to edit group memberships") {:status-code 403})))) (t2/with-transaction [_conn] (when (seq to-remove-group-ids) (t2/delete! :model/PermissionsGroupMembership :user_id user-id, :group_id [:in to-remove-group-ids])) (when (seq to-add-group-ids) ;; do multiple single inserts because insert-many! does not call post-insert! hook (doseq [group-id to-add-group-ids] (t2/insert! :model/PermissionsGroupMembership {:user_id user-id :group_id group-id :is_group_manager (:is_group_manager (new-group-id->membership-info group-id))}))))))) |