A A few 'magic' groups exist: [[all-users]], which predicably contains All Users; and [[admin]], which contains all superusers. These groups are 'magic' in the sense that you cannot add users to them yourself, nor can you delete them; they are created automatically. You can, however, set permissions for them. See documentation in [[metabase.permissions.models.permissions]] for more information about the Metabase permissions system. | (ns metabase.permissions.models.permissions-group (:require [metabase.db :as mdb] [metabase.models.interface :as mi] [metabase.models.serialization :as serdes] [metabase.models.setting :as setting] [metabase.permissions.models.data-permissions :as data-perms] [metabase.premium-features.core :as premium-features] [metabase.util :as u] [metabase.util.i18n :refer [tru]] [methodical.core :as methodical] [toucan2.core :as t2] [toucan2.tools.hydrate :as t2.hydrate])) |
(methodical/defmethod t2/table-name :model/PermissionsGroup [_model] :permissions_group) (methodical/defmethod t2/model-for-automagic-hydration [:default :permissions_group] [_original-model _k] :model/PermissionsGroup) (methodical/defmethod t2.hydrate/fk-keys-for-automagic-hydration [:default :permissions_group :default] [_original-model _dest-key _hydrating-model] [:permissions_group_id]) | |
(doto :model/PermissionsGroup (derive :metabase/model) (derive :hook/entity-id)) | |
(defmethod serdes/hash-fields :model/PermissionsGroup [_user] [:name]) | |
-------------------------------------------- Magic Groups Getter Fns --------------------------------------------- | |
(defn- magic-group [group-name]
(mdb/memoize-for-application-db
(fn []
(u/prog1 (t2/select-one [:model/PermissionsGroup :id :name] :name group-name)
;; normally it is impossible to delete the magic [[all-users]] or [[admin]] Groups -- see
;; [[check-not-magic-group]]. This assertion is here to catch us if we do something dumb when hacking on
;; the MB code -- to make tests fail fast. For that reason it's not i18n'ed.
(when-not <>
(throw (ex-info (format "Fatal error: magic Permissions Group %s has gone missing." (pr-str group-name))
{:name group-name}))))))) | |
The name of the "All Users" magic group. | (def all-users-group-name "All Users") |
Fetch the | (def ^{:arglists '([])} all-users
(magic-group all-users-group-name)) |
The name of the "Administrators" magic group. | (def admin-group-name "Administrators") |
Fetch the | (def ^{:arglists '([])} admin
(magic-group admin-group-name)) |
--------------------------------------------------- Validation --------------------------------------------------- | |
Does a | (defn exists-with-name?
^Boolean [group-name]
{:pre [((some-fn keyword? string?) group-name)]}
(t2/exists? :model/PermissionsGroup
:%lower.name (u/lower-case-en (name group-name)))) |
(defn- check-name-not-already-taken
[group-name]
(when (exists-with-name? group-name)
(throw (ex-info (tru "A group with that name already exists.") {:status-code 400})))) | |
Make sure we're not trying to edit/delete one of the magic groups, or throw an exception. | (defn- check-not-magic-group
[{id :id}]
{:pre [(integer? id)]}
(doseq [magic-group [(all-users)
(admin)]]
(when (= id (:id magic-group))
(throw (ex-info (tru "You cannot edit or delete the ''{0}'' permissions group!" (:name magic-group))
{:status-code 400}))))) |
--------------------------------------------------- Lifecycle ---------------------------------------------------- | |
(t2/define-before-insert :model/PermissionsGroup
[{group-name :name, :as group}]
(u/prog1 group
(check-name-not-already-taken group-name))) | |
(defn- set-default-permission-values!
[group]
(t2/with-transaction [_conn]
(doseq [db-id (t2/select-pks-vec :model/Database)]
(data-perms/set-new-group-permissions! group db-id (u/the-id (all-users)))))) | |
(t2/define-after-insert :model/PermissionsGroup
[group]
(u/prog1 group
(set-default-permission-values! group))) | |
(t2/define-before-delete :model/PermissionsGroup
[{id :id, :as group}]
(check-not-magic-group group)
(setting/set-value-of-type!
:json :ldap-group-mappings
(when-let [mappings (setting/get :ldap-group-mappings)]
(zipmap (keys mappings)
(for [val (vals mappings)]
(remove (partial = id) val)))))) | |
(t2/define-before-update :model/PermissionsGroup
[group]
(let [changes (t2/changes group)]
(u/prog1 group
(when (contains? changes :name)
;; Allow backfilling the entity ID for magic groups, but not changing anything else
(check-not-magic-group group))
(when-let [group-name (:name changes)]
(check-name-not-already-taken group-name))))) | |
---------------------------------------------------- Util Fns ---------------------------------------------------- | |
(methodical/defmethod t2/batched-hydrate [:model/PermissionsGroup :members]
"Batch hydration Users for a list of PermissionsGroups"
[_model k groups]
(mi/instances-with-hydrated-data
groups k
#(group-by :group_id (t2/select :model/User {:select [:u.id
;; user_id is for legacy reasons, we should remove it
[:u.id :user_id]
:u.first_name
:u.last_name
:u.email
:pgm.group_id
[:pgm.id :membership_id]
(when (premium-features/enable-advanced-permissions?)
[:pgm.is_group_manager :is_group_manager])]
:from [[:core_user :u]]
:left-join [[:permissions_group_membership :pgm] [:= :u.id :pgm.user_id]]
:where [:and
[:= :u.is_active true]
[:in :pgm.group_id (map :id groups)]]
:order-by [[[:lower :u.first_name] :asc]
[[:lower :u.last_name] :asc]]}))
:id
{:default []})) | |
Return a set of the IDs of all | (defn non-admin-groups [] (t2/select :model/PermissionsGroup :name [:not= admin-group-name])) |
Return a set of the IDs of all | (defn non-magic-groups
[]
(t2/select :model/PermissionsGroup {:where [:and [:not= :name admin-group-name]
[:not= :name all-users-group-name]]})) |