diff --git a/src/metabase/api/collection.clj b/src/metabase/api/collection.clj index 8e52656849fafc5acf70d7988a704c96cf60b134..a877ccf5f46dd8ebc099d5f97723824791e39cb5 100644 --- a/src/metabase/api/collection.clj +++ b/src/metabase/api/collection.clj @@ -10,6 +10,8 @@ [compojure.core :refer [GET POST PUT]] [honeysql.core :as hsql] [honeysql.helpers :as hh] + [malli.core :as mc] + [malli.transform :as mtx] [medley.core :as m] [metabase.api.card :as api.card] [metabase.api.common :as api] @@ -881,33 +883,49 @@ (api/check-superuser) (graph/graph namespace)) -(defn- ->int [id] (Integer/parseInt (name id))) +(def CollectionID "an id for a [[Collection]]." + [pos-int? {:title "Collection ID"}]) -(defn- dejsonify-collections [collections] - (into {} (for [[collection-id perms] collections] - [(if (= (keyword collection-id) :root) - :root - (->int collection-id)) - (keyword perms)]))) +(def GroupID "an id for a [[PermissionsGroup]]." + [pos-int? {:title "Group ID"}]) -(defn- dejsonify-groups [groups] - (into {} (for [[group-id collections] groups] - {(->int group-id) (dejsonify-collections collections)}))) +(def CollectionPermissions + "Malli enum for what sort of collection permissions we have. (:write :read or :none)" + [:and keyword? [:enum :write :read :none]]) -(defn- dejsonify-graph - "Fix the types in the graph when it comes in from the API, e.g. converting things like `\"none\"` to `:none` and - parsing object keys as integers." - [graph] - (update graph :groups dejsonify-groups)) +(def GroupPermissionsGraph + "Map describing permissions for a (Group x Collection)" + [:map-of + [:or + ;; We need the [:and keyword ...] piece to make decoding "root" work. There's a merged fix for this, but it hasn't + ;; been released as of malli 0.9.2. When the malli version gets bumped, we should remove this. + [:and keyword? [:= :root]] + CollectionID] + CollectionPermissions]) + +(def PermissionsGraph + "Map describing permissions for 1 or more groups. + Revision # is used for consistency" + [:map + [:revision int?] + [:groups [:map-of GroupID GroupPermissionsGraph]]]) + +(def ^:private graph-decoder + "Building it this way is a lot faster then calling mc/decode <value> <schema> <transformer>" + (mc/decoder PermissionsGraph (mtx/string-transformer))) + +(defn- decode-graph [permission-graph] + (graph-decoder permission-graph)) (api/defendpoint-schema PUT "/graph" - "Do a batch update of Collections Permissions by passing in a modified graph." + "Do a batch update of Collections Permissions by passing in a modified graph. + Will overwrite parts of the graph that are present in the request, and leave the rest unchanged." [:as {{:keys [namespace], :as body} :body}] {body su/Map namespace (s/maybe su/NonBlankString)} (api/check-superuser) (->> (dissoc body :namespace) - dejsonify-graph + decode-graph (graph/update-graph! namespace)) (graph/graph namespace))