Collections are used to organize Cards, Dashboards, and Pulses; as of v0.30, they are the primary way we determine permissions for these objects.
TODO - I think this namespace is too big now! Maybe move the graph stuff into somewhere like
metabase.models.collection.graph
Collections are used to organize Cards, Dashboards, and Pulses; as of v0.30, they are the primary way we determine permissions for these objects. TODO - I think this namespace is too big now! Maybe move the graph stuff into somewhere like `metabase.models.collection.graph`
Whether to allow deleting Personal Collections. Normally we should never allow this, but
in the single case of deleting a User themselves, we need to allow this. (Note that in normal usage, Users never get
deleted, but rather archived; thus this code is used solely by our test suite, by things such as the with-temp
macros.)
Whether to allow deleting Personal Collections. Normally we should *never* allow this, but in the single case of deleting a User themselves, we need to allow this. (Note that in normal usage, Users never get deleted, but rather archived; thus this code is used solely by our test suite, by things such as the `with-temp` macros.)
(all-ids-in-location-path-are-valid? location-path)
Inputs: [location-path :- LocationPath] Returns: s/Bool
Do all the IDs in location-path
belong to actual Collections? (This requires a DB call to check this, so this
should only be used when creating/updating a Collection. Don't use this for casual schema validation.)
Inputs: [location-path :- LocationPath] Returns: s/Bool Do all the IDs in `location-path` belong to actual Collections? (This requires a DB call to check this, so this should only be used when creating/updating a Collection. Don't use this for casual schema validation.)
(check-allowed-to-change-collection object-before-update object-updates)
If we're changing the collection_id
of an object, make sure we have write permissions for both the old and new
Collections, or throw a 403 if not. If collection_id
isn't present in object-updates
, or the value is the same
as the original, this check is a no-op.
As usual, an collection-id
of nil
represents the Root Collection.
Intended for use with PUT
or PATCH
-style operations. Usage should look something like:
;; object-before-update
is the object as it currently exists in the application DB
;; object-updates
is a map of updated values for the object
(check-allowed-to-change-collection (Card 100) http-request-body)
If we're changing the `collection_id` of an object, make sure we have write permissions for both the old and new Collections, or throw a 403 if not. If `collection_id` isn't present in `object-updates`, or the value is the same as the original, this check is a no-op. As usual, an `collection-id` of `nil` represents the Root Collection. Intended for use with `PUT` or `PATCH`-style operations. Usage should look something like: ;; `object-before-update` is the object as it currently exists in the application DB ;; `object-updates` is a map of updated values for the object (check-allowed-to-change-collection (Card 100) http-request-body)
(check-write-perms-for-collection collection-or-id-or-nil)
Check that we have write permissions for Collection with collection-id
, or throw a 403 Exception. If
collection-id
is nil
, this check is done for the Root Collection.
Check that we have write permissions for Collection with `collection-id`, or throw a 403 Exception. If `collection-id` is `nil`, this check is done for the Root Collection.
(children-location {:keys [location] :as collection})
Inputs: [{:keys [location], :as collection} :- CollectionWithLocationAndIDOrRoot] Returns: LocationPath
Given a collection
return a location path that should match the :location
value of all the children of the
Collection.
(children-location collection) ; -> "/10/20/30/;
;; To get children of this collection: (db/select Collection :location "/10/20/30/")
Inputs: [{:keys [location], :as collection} :- CollectionWithLocationAndIDOrRoot] Returns: LocationPath Given a `collection` return a location path that should match the `:location` value of all the children of the Collection. (children-location collection) ; -> "/10/20/30/; ;; To get children of this collection: (db/select Collection :location "/10/20/30/")
(Collection)
(Collection id)
(Collection & kvs)
Entity for 'collection' table; instance of CollectionInstance.
Entity for 'collection' table; instance of CollectionInstance.
Schema for a valid CollectionInstance
that has valid :location
and :id
properties, or the special
root-collection
placeholder object.
Schema for a valid `CollectionInstance` that has valid `:location` and `:id` properties, or the special `root-collection` placeholder object.
(effective-ancestors collection)
Inputs: [collection :- CollectionWithLocationAndIDOrRoot] Returns: [(s/cond-pre RootCollection CollectionInstance)]
Fetch the ancestors of a collection
, filtering out any ones the current User isn't allowed to see. This is used
in the UI to power the 'breadcrumb' path to the location of a given Collection. For example, suppose we have four
Collections, nested like:
A > B > C > D
The ancestors of D are:
[Root] > A > B > C
If the current User is allowed to see A and C, but not B, effective-ancestors
of D will be:
[Root] > A > C
Thus the existence of C will be kept hidden from the current User, and for all intents and purposes the current User can effectively treat A as the parent of C.
Inputs: [collection :- CollectionWithLocationAndIDOrRoot] Returns: [(s/cond-pre RootCollection CollectionInstance)] Fetch the ancestors of a `collection`, filtering out any ones the current User isn't allowed to see. This is used in the UI to power the 'breadcrumb' path to the location of a given Collection. For example, suppose we have four Collections, nested like: A > B > C > D The ancestors of D are: [Root] > A > B > C If the current User is allowed to see A and C, but not B, `effective-ancestors` of D will be: [Root] > A > C Thus the existence of C will be kept hidden from the current User, and for all intents and purposes the current User can effectively treat A as the parent of C.
(effective-children collection & additional-honeysql-where-clauses)
Inputs: [collection :- CollectionWithLocationAndIDOrRoot & additional-honeysql-where-clauses] Returns: #{CollectionInstance}
Return the descendant Collections of a collection
that should be presented to the current user as the children of
this Collection. This takes into account descendants that get filtered out when the current user can't see them. For
example, suppose we have some Collections with a hierarchy like this:
+-> B
|
A -+-> C -+-> D -> E | +-> F -> G
Suppose the current User can see A, B, E, F, and G, but not C, or D. The 'effective' children of A would be B, E, and F, and the current user would be presented with a hierarchy like:
+-> B
|
A -+-> E | +-> F -> G
You can think of this process as 'collapsing' the Collection hierarchy and removing nodes that aren't visible to the current User. This needs to be done so we can give a User a way to navigate to nodes that they are allowed to access, but that are children of Collections they cannot access; in the example above, E and F are such nodes.
Inputs: [collection :- CollectionWithLocationAndIDOrRoot & additional-honeysql-where-clauses] Returns: #{CollectionInstance} Return the descendant Collections of a `collection` that should be presented to the current user as the children of this Collection. This takes into account descendants that get filtered out when the current user can't see them. For example, suppose we have some Collections with a hierarchy like this: +-> B | A -+-> C -+-> D -> E | +-> F -> G Suppose the current User can see A, B, E, F, and G, but not C, or D. The 'effective' children of A would be B, E, and F, and the current user would be presented with a hierarchy like: +-> B | A -+-> E | +-> F -> G You can think of this process as 'collapsing' the Collection hierarchy and removing nodes that aren't visible to the current User. This needs to be done so we can give a User a way to navigate to nodes that they are allowed to access, but that are children of Collections they cannot access; in the example above, E and F are such nodes.
(effective-location-path collection)
(effective-location-path real-location-path allowed-collection-ids)
Inputs: ([collection :- CollectionWithLocationOrRoot] [real-location-path :- LocationPath allowed-collection-ids :- VisibleCollections]) Returns: (s/maybe LocationPath)
Given a location-path
and a set of Collection IDs one is allowed to view (obtained from
permissions-set->visible-collection-ids
above), calculate the 'effective' location path (excluding IDs of
Collections for which we do not have read perms) we should show to the User.
When called with a single argument, collection
, this is used as a hydration function to hydrate
:effective_location
.
Inputs: ([collection :- CollectionWithLocationOrRoot] [real-location-path :- LocationPath allowed-collection-ids :- VisibleCollections]) Returns: (s/maybe LocationPath) Given a `location-path` and a set of Collection IDs one is allowed to view (obtained from `permissions-set->visible-collection-ids` above), calculate the 'effective' location path (excluding IDs of Collections for which we do not have read perms) we should show to the User. When called with a single argument, `collection`, this is used as a hydration function to hydrate `:effective_location`.
(graph)
Inputs: [] Returns: PermissionsGraph
Fetch a graph representing the current permissions status for every group and all permissioned collections. This
works just like the function of the same name in metabase.models.permissions
; see also the documentation for that
function.
Inputs: [] Returns: PermissionsGraph Fetch a graph representing the current permissions status for every group and all permissioned collections. This works just like the function of the same name in `metabase.models.permissions`; see also the documentation for that function.
Regex for a valid value of :color
, a 7-character hex string including the preceding hash sign.
Regex for a valid value of `:color`, a 7-character hex string including the preceding hash sign.
(include-personal-collection-ids users)
Efficiently hydrate the :personal_collection_id
property of a sequence of Users. (This is, predictably, the ID of
their Personal Collection.)
Efficiently hydrate the `:personal_collection_id` property of a sequence of Users. (This is, predictably, the ID of their Personal Collection.)
(location-path & collections-or-ids)
Inputs: [& collections-or-ids :- [(s/cond-pre su/IntGreaterThanZero su/Map)]] Returns: LocationPath
Build a 'location path' from a sequence of collections-or-ids
.
(location-path 10 20) ; -> "/10/20/"
Inputs: [& collections-or-ids :- [(s/cond-pre su/IntGreaterThanZero su/Map)]] Returns: LocationPath Build a 'location path' from a sequence of `collections-or-ids`. (location-path 10 20) ; -> "/10/20/"
(location-path->ids location-path)
Inputs: [location-path :- LocationPath] Returns: [su/IntGreaterThanZero]
'Explode' a location-path
into a sequence of Collection IDs, and parse them as integers.
(location-path->ids "/10/20/") ; -> [10 20]
Inputs: [location-path :- LocationPath] Returns: [su/IntGreaterThanZero] 'Explode' a `location-path` into a sequence of Collection IDs, and parse them as integers. (location-path->ids "/10/20/") ; -> [10 20]
(location-path->parent-id location-path)
Inputs: [location-path :- LocationPath] Returns: (s/maybe su/IntGreaterThanZero)
Given a location-path
fetch the ID of the direct of a Collection.
(location-path->parent-id "/10/20/") ; -> 20
Inputs: [location-path :- LocationPath] Returns: (s/maybe su/IntGreaterThanZero) Given a `location-path` fetch the ID of the direct of a Collection. (location-path->parent-id "/10/20/") ; -> 20
Schema for a directory-style 'path' to the location of a Collection.
Schema for a directory-style 'path' to the location of a Collection.
(move-collection! collection new-location)
Inputs: [collection :- CollectionWithLocationAndIDOrRoot new-location :- LocationPath]
Move a Collection and all its descendant Collections from its current location
to a new-location
.
Inputs: [collection :- CollectionWithLocationAndIDOrRoot new-location :- LocationPath] Move a Collection and all its descendant Collections from its current `location` to a `new-location`.
(parent-id {:keys [location]})
Inputs: [{:keys [location]} :- CollectionWithLocationOrRoot] Returns: (s/maybe su/IntGreaterThanZero)
Get the immediate parent collection
id, if set.
Inputs: [{:keys [location]} :- CollectionWithLocationOrRoot] Returns: (s/maybe su/IntGreaterThanZero) Get the immediate parent `collection` id, if set.
(permissions-set->visible-collection-ids permissions-set)
Inputs: [permissions-set :- #{perms/UserPath}] Returns: VisibleCollections
Given a permissions-set
(presumably those of the current user), return a set of IDs of Collections that the
permissions set allows you to view. For those with root permissions (e.g., an admin), this function will return
:all
, signifying that you are allowed to view all Collections. For Root Collection permissions, the response
will include "root".
(permissions-set->visible-collection-ids #{"/collection/10/"}) ; -> #{10} (permissions-set->visible-collection-ids #{"/"}) ; -> :all (permissions-set->visible-collection-ids #{"/collection/root/"}) ; -> #{"root"}
You probably don't want to consume the results of this function directly -- most of the time, the reason you are
calling this function in the first place is because you want add a FILTER
clause to an application DB query (e.g.
to only fetch Cards that belong to Collections visible to the current User). Use
visible-collection-ids->honeysql-filter-clause
to generate a filter clause that handles all possible outputs of
this function correctly.
!!! IMPORTANT NOTE !!!
Because the result may include nil
for the Root Collection, or may be :all
, MAKE SURE YOU HANDLE THOSE
SITUATIONS CORRECTLY before using these IDs to make a DB call. Better yet, use
collection-ids->honeysql-filter-clause
to generate appropriate HoneySQL.
Inputs: [permissions-set :- #{perms/UserPath}] Returns: VisibleCollections Given a `permissions-set` (presumably those of the current user), return a set of IDs of Collections that the permissions set allows you to view. For those with *root* permissions (e.g., an admin), this function will return `:all`, signifying that you are allowed to view all Collections. For *Root Collection* permissions, the response will include "root". (permissions-set->visible-collection-ids #{"/collection/10/"}) ; -> #{10} (permissions-set->visible-collection-ids #{"/"}) ; -> :all (permissions-set->visible-collection-ids #{"/collection/root/"}) ; -> #{"root"} You probably don't want to consume the results of this function directly -- most of the time, the reason you are calling this function in the first place is because you want add a `FILTER` clause to an application DB query (e.g. to only fetch Cards that belong to Collections visible to the current User). Use `visible-collection-ids->honeysql-filter-clause` to generate a filter clause that handles all possible outputs of this function correctly. !!! IMPORTANT NOTE !!! Because the result may include `nil` for the Root Collection, or may be `:all`, MAKE SURE YOU HANDLE THOSE SITUATIONS CORRECTLY before using these IDs to make a DB call. Better yet, use `collection-ids->honeysql-filter-clause` to generate appropriate HoneySQL.
(perms-for-archiving collection)
Inputs: [collection :- CollectionWithLocationAndIDOrRoot] Returns: #{perms/ObjectPath}
Return the set of Permissions needed to archive or unarchive a collection
. Since archiving a Collection is
recursive (i.e., it applies to all the descendant Collections of that Collection), we require write ('curate')
permissions for the Collection itself and all its descendants, but not for its parent Collection.
For example, suppose we have a Collection hierarchy like:
A > B > C
To move or archive B, you need write permissions for A, B, and C:
Inputs: [collection :- CollectionWithLocationAndIDOrRoot] Returns: #{perms/ObjectPath} Return the set of Permissions needed to archive or unarchive a `collection`. Since archiving a Collection is *recursive* (i.e., it applies to all the descendant Collections of that Collection), we require write ('curate') permissions for the Collection itself and all its descendants, but not for its parent Collection. For example, suppose we have a Collection hierarchy like: A > B > C To move or archive B, you need write permissions for A, B, and C: * A, because you are taking something out of it (by archiving it) * B, because you are archiving it * C, because by archiving its parent, you are archiving it as well
(perms-for-moving collection new-parent)
Inputs: [collection :- CollectionWithLocationAndIDOrRoot new-parent :- CollectionWithLocationAndIDOrRoot] Returns: #{perms/ObjectPath}
Return the set of Permissions needed to move a collection
. Like archiving, moving is recursive, so we require
perms for both the Collection and its descendants; we additionally require permissions for its new parent Collection.
For example, suppose we have a Collection hierarchy of three Collections, A, B, and C, and a forth Collection, D, and we want to move B from A to D:
A > B > C A ===> D D > B > C
To move or archive B, you would need write permissions for A, B, C, and D:
Inputs: [collection :- CollectionWithLocationAndIDOrRoot new-parent :- CollectionWithLocationAndIDOrRoot] Returns: #{perms/ObjectPath} Return the set of Permissions needed to move a `collection`. Like archiving, moving is recursive, so we require perms for both the Collection and its descendants; we additionally require permissions for its new parent Collection. For example, suppose we have a Collection hierarchy of three Collections, A, B, and C, and a forth Collection, D, and we want to move B from A to D: A > B > C A ===> D D > B > C To move or archive B, you would need write permissions for A, B, C, and D: * A, because we're moving something out of it * B, since it's the Collection we're operating on * C, since it will by definition be affected too * D, because it's the new parent Collection, and moving something into it requires write perms.
(perms-objects-set collection-or-id read-or-write)
Return the required set of permissions to read-or-write
collection-or-id
.
Return the required set of permissions to `read-or-write` `collection-or-id`.
Special placeholder object representing the Root Collection, which isn't really a real Collection.
Special placeholder object representing the Root Collection, which isn't really a real Collection.
(root-collection-with-ui-details)
The special Root Collection placeholder object with some extra details to facilitate displaying it on the FE.
The special Root Collection placeholder object with some extra details to facilitate displaying it on the FE.
(update-graph! new-graph)
(update-graph! ks new-value)
Inputs: ([new-graph :- PermissionsGraph] [ks new-value])
Update the collections permissions graph. This works just like the function of the same name in
metabase.models.permissions
, but for Collections
; refer to that function's extensive documentation to get a
sense for how this works.
Inputs: ([new-graph :- PermissionsGraph] [ks new-value]) Update the collections permissions graph. This works just like the function of the same name in `metabase.models.permissions`, but for `Collections`; refer to that function's extensive documentation to get a sense for how this works.
(user->personal-collection user-or-id)
Inputs: [user-or-id] Returns: CollectionInstance
Return the Personal Collection for user-or-id
, if it already exists; if not, create it and return it.
Inputs: [user-or-id] Returns: CollectionInstance Return the Personal Collection for `user-or-id`, if it already exists; if not, create it and return it.
(user->personal-collection-and-descendant-ids user-or-id)
Inputs: [user-or-id]
Somewhat-optimized function that fetches the ID of a User's Personal Collection as well as the IDs of all descendants of that Collection. Exists because this needs to be known to calculate the Current User's permissions set, which is done for every API call; this function is an attempt to make fetching this information as efficient as reasonably possible.
Inputs: [user-or-id] Somewhat-optimized function that fetches the ID of a User's Personal Collection as well as the IDs of all descendants of that Collection. Exists because this needs to be known to calculate the Current User's permissions set, which is done for every API call; this function is an attempt to make fetching this information as efficient as reasonably possible.
(visible-collection-ids->honeysql-filter-clause collection-ids)
(visible-collection-ids->honeysql-filter-clause collection-id-field
collection-ids)
Inputs: ([collection-ids :- VisibleCollections] [collection-id-field :- s/Keyword collection-ids :- VisibleCollections])
Generate an appropriate HoneySQL :where
clause to filter something by visible Collection IDs, such as the ones
returned by permissions-set->visible-collection-ids
. Correctly handles all possible values returned by that
function, including :all
and nil
Collection IDs (for the Root Collection).
Guaranteed to always generate a valid HoneySQL form, so this can be used directly in a query without further checks.
(db/select Card {:where (collection/visible-collection-ids->honeysql-filter-clause (collection/permissions-set->visible-collection-ids @current-user-permissions-set))})
Inputs: ([collection-ids :- VisibleCollections] [collection-id-field :- s/Keyword collection-ids :- VisibleCollections]) Generate an appropriate HoneySQL `:where` clause to filter something by visible Collection IDs, such as the ones returned by `permissions-set->visible-collection-ids`. Correctly handles all possible values returned by that function, including `:all` and `nil` Collection IDs (for the Root Collection). Guaranteed to always generate a valid HoneySQL form, so this can be used directly in a query without further checks. (db/select Card {:where (collection/visible-collection-ids->honeysql-filter-clause (collection/permissions-set->visible-collection-ids @*current-user-permissions-set*))})
Includes the possible values for visible collections, either :all
or a set of ids, possibly including "root"
to
represent the root collection.
Includes the possible values for visible collections, either `:all` or a set of ids, possibly including `"root"` to represent the root collection.
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close