diff --git a/README.md b/README.md index 64b9deb1..f35d2ad6 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,10 @@ Swarmpit is published on port `888` by default. Refer to following [document](https://github.com/swarmpit/swarmpit/blob/master/doc/configuration.md) +## User Types + +Refer to following [document](https://github.com/swarmpit/swarmpit/blob/master/doc/user_types.md) + ## Development Swarmpit is written purely in Clojure and utilizes React on front-end. CouchDB is used to persist application data & InfluxDB for cluster statistics. diff --git a/doc/user_types.md b/doc/user_types.md new file mode 100644 index 00000000..6fef278c --- /dev/null +++ b/doc/user_types.md @@ -0,0 +1,15 @@ +# User Types + +# User & Admin Roles + +Both User & Admin have full access to make modifications to all stacks, services, secrets etc. - however, only Admin users can create/edit other users. + +# View Only Role + +As you would expect, 'View only' users can not make any modifications except pinning/unpinning dashboard entries and changing their password. +With the exception of secret values (which are kept secret to full users and admins), they can view all information. + +

+ + +

diff --git a/resources/public/CreateUser.png b/resources/public/CreateUser.png new file mode 100644 index 00000000..e96b08d9 Binary files /dev/null and b/resources/public/CreateUser.png differ diff --git a/resources/public/UserList.png b/resources/public/UserList.png new file mode 100644 index 00000000..1a9ceb1a Binary files /dev/null and b/resources/public/UserList.png differ diff --git a/src/clj/swarmpit/authorization.clj b/src/clj/swarmpit/authorization.clj index 7d4ea950..c9c8e455 100644 --- a/src/clj/swarmpit/authorization.clj +++ b/src/clj/swarmpit/authorization.clj @@ -3,6 +3,7 @@ [buddy.auth.accessrules :refer [success error wrap-access-rules]] [swarmpit.handler :refer [resp-error]] [swarmpit.token :refer [admin?]] + [swarmpit.token :refer [user?]] [swarmpit.couchdb.client :as cc])) (defn- authenticated-access @@ -25,6 +26,15 @@ (error {:code 403 :message "Unauthorized admin access"})))) +(defn- user-access + [{:keys [identity]}] + (let [username (get-in identity [:usr :username]) + user (cc/user-by-username username)] + (if (or (admin? user) (user? user)) + true + (error {:code 403 + :message "Unauthorized user access"})))) + (defn- owner-access [{:keys [path-params identity]}] (let [user (get-in identity [:usr :username]) @@ -65,16 +75,26 @@ :handler {:and [authenticated-access admin-access]}} {:pattern #"^/api/registry/(dockerhub|v2|ecr|acr|gitlab)/[a-zA-Z0-9]*/repositories$" :request-method :get - :handler {:and [authenticated-access registry-access]}} + :handler {:and [authenticated-access registry-access user-access]}} {:pattern #"^/api/registry/(dockerhub|v2|ecr|acr|gitlab)/[a-zA-Z0-9]*/tags$" :request-method :get - :handler {:and [authenticated-access registry-access]}} + :handler {:and [authenticated-access registry-access user-access]}} {:pattern #"^/api/registry/(dockerhub|v2|ecr|acr|gitlab)/[a-zA-Z0-9]*/ports$" :request-method :get - :handler {:and [authenticated-access registry-access]}} + :handler {:and [authenticated-access registry-access user-access]}} {:pattern #"^/api/registry/(dockerhub|v2|ecr|acr|gitlab)/[a-zA-Z0-9]*$" :request-method #{:get :delete :post} - :handler {:and [authenticated-access owner-access]}} + :handler {:and [authenticated-access owner-access user-access]}} + {:pattern #"^/api/.*/dashboard$" + :request-method #{:delete :post} + :handler {:and [authenticated-access]}} ;;Allow pin/unpin by authenticated + {:pattern #"^/api/.*" + :request-method #{:delete :post} + :handler {:and [authenticated-access user-access]}} ;;Restrict ALL delete/post to user level and higher + {:pattern #"^/api/secrets/$" + :handler {:and [authenticated-access user-access]}} ;;Restrict getting secrets to user level and higher + {:pattern #"^/api/secrets/.*$" + :handler {:and [authenticated-access user-access]}} ;;Restrict getting secrets to user level and higher {:pattern #"^/api/.*" :handler authenticated-access}]) diff --git a/src/cljc/swarmpit/token.cljc b/src/cljc/swarmpit/token.cljc index f25d3c0d..d7ff0adb 100644 --- a/src/cljc/swarmpit/token.cljc +++ b/src/cljc/swarmpit/token.cljc @@ -18,6 +18,10 @@ [user] (= "admin" (:role user))) +(defn user? + [user] + (or (= "admin" (:role user)) (= "user" (:role user)))) + (defn token-value [token] (second (str/split token #" "))) diff --git a/src/cljs/swarmpit/component/account_settings.cljs b/src/cljs/swarmpit/component/account_settings.cljs index 209b6096..3f4ba6d3 100644 --- a/src/cljs/swarmpit/component/account_settings.cljs +++ b/src/cljs/swarmpit/component/account_settings.cljs @@ -3,7 +3,8 @@ [material.components :as comp] [swarmpit.component.password :as password] [swarmpit.component.api-access :as api-access] - [sablono.core :refer-macros [html]])) + [sablono.core :refer-macros [html]] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -30,4 +31,4 @@ {:maxWidth "sm" :className "Swarmpit-container"} (form-password) - (form-api-access))]]))) \ No newline at end of file + (form-api-access))]]))) \ No newline at end of file diff --git a/src/cljs/swarmpit/component/common.cljs b/src/cljs/swarmpit/component/common.cljs index 9b6568fd..50883ebf 100644 --- a/src/cljs/swarmpit/component/common.cljs +++ b/src/cljs/swarmpit/component/common.cljs @@ -106,10 +106,11 @@ (comp/grid {:container true :spacing 2} - (comp/grid - {:item true - :xs 12} - (toolbar/list-toobar title items filtered-items toolbar-render-metadata)) + (if (not= "" toolbar-render-metadata) + (comp/grid + {:item true + :xs 12} + (toolbar/list-toobar title items filtered-items toolbar-render-metadata))) (comp/grid {:item true :xs 12} diff --git a/src/cljs/swarmpit/component/config/info.cljs b/src/cljs/swarmpit/component/config/info.cljs index 41aad220..0080a7fa 100644 --- a/src/cljs/swarmpit/component/config/info.cljs +++ b/src/cljs/swarmpit/component/config/info.cljs @@ -17,7 +17,8 @@ [swarmpit.base64 :as base64] [sablono.core :refer-macros [html]] [clojure.contrib.inflect :as inflect] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -119,10 +120,11 @@ (comp/grid {:container true :spacing 2} - (comp/grid - {:item true - :xs 12} - (toolbar/toolbar "Config" (:configName config) form-actions)) + (if (storage/user?) + (comp/grid + {:item true + :xs 12} + (toolbar/toolbar "Config" (:configName config) form-actions))) (comp/grid {:item true :xs 12} diff --git a/src/cljs/swarmpit/component/config/list.cljs b/src/cljs/swarmpit/component/config/list.cljs index 82e302c6..0762e107 100644 --- a/src/cljs/swarmpit/component/config/list.cljs +++ b/src/cljs/swarmpit/component/config/list.cljs @@ -12,7 +12,8 @@ [swarmpit.url :refer [dispatch!]] [sablono.core :refer-macros [html]] [rum.core :as rum] - [swarmpit.component.common :as common])) + [swarmpit.component.common :as common] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -84,4 +85,6 @@ (reverse)) render-metadata onclick-handler - toolbar-render-metadata)))) + (if (storage/user?) + toolbar-render-metadata + ""))))) diff --git a/src/cljs/swarmpit/component/network/info.cljs b/src/cljs/swarmpit/component/network/info.cljs index 1eed7251..86d4fbe7 100644 --- a/src/cljs/swarmpit/component/network/info.cljs +++ b/src/cljs/swarmpit/component/network/info.cljs @@ -18,7 +18,8 @@ [swarmpit.routes :as routes] [sablono.core :refer-macros [html]] [rum.core :as rum] - [clojure.string :as str])) + [clojure.string :as str] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -133,10 +134,11 @@ (comp/grid {:container true :spacing 2} - (comp/grid - {:item true - :xs 12} - (toolbar/toolbar "Network" (:networkName network) form-actions)) + (if (storage/user?) + (comp/grid + {:item true + :xs 12} + (toolbar/toolbar "Network" (:networkName network) form-actions))) (comp/grid {:item true :xs 12} diff --git a/src/cljs/swarmpit/component/network/list.cljs b/src/cljs/swarmpit/component/network/list.cljs index 5ed52be6..65ec7a22 100644 --- a/src/cljs/swarmpit/component/network/list.cljs +++ b/src/cljs/swarmpit/component/network/list.cljs @@ -12,7 +12,8 @@ [swarmpit.url :refer [dispatch!]] [sablono.core :refer-macros [html]] [rum.core :as rum] - [swarmpit.component.common :as common])) + [swarmpit.component.common :as common] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -79,4 +80,6 @@ filtered-items render-metadata onclick-handler - toolbar-render-metadata)))) + (if (storage/user?) + toolbar-render-metadata + ""))))) diff --git a/src/cljs/swarmpit/component/registry/list.cljs b/src/cljs/swarmpit/component/registry/list.cljs index 05085c95..8ea38f10 100644 --- a/src/cljs/swarmpit/component/registry/list.cljs +++ b/src/cljs/swarmpit/component/registry/list.cljs @@ -13,7 +13,8 @@ [swarmpit.url :refer [dispatch!]] [sablono.core :refer-macros [html]] [cljs.core :as core] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -181,6 +182,10 @@ distributions filtered-distributions render-metadata - onclick-handler - toolbar-render-metadata)))) + (if (storage/user?) + onclick-handler + "") + (if (storage/user?) + toolbar-render-metadata + ""))))) diff --git a/src/cljs/swarmpit/component/secret/list.cljs b/src/cljs/swarmpit/component/secret/list.cljs index 31e38e01..47b59111 100644 --- a/src/cljs/swarmpit/component/secret/list.cljs +++ b/src/cljs/swarmpit/component/secret/list.cljs @@ -11,7 +11,8 @@ [swarmpit.routes :as routes] [swarmpit.url :refer [dispatch!]] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -74,5 +75,9 @@ (sort-by :createdAt) (reverse)) render-metadata - onclick-handler - toolbar-render-metadata)))) + (if (storage/user?) + onclick-handler + nil) + (if (storage/user?) + toolbar-render-metadata + ""))))) diff --git a/src/cljs/swarmpit/component/service/info.cljs b/src/cljs/swarmpit/component/service/info.cljs index edecef55..1ea411b8 100644 --- a/src/cljs/swarmpit/component/service/info.cljs +++ b/src/cljs/swarmpit/component/service/info.cljs @@ -28,7 +28,8 @@ [swarmpit.ajax :as ajax] [swarmpit.routes :as routes] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -167,6 +168,18 @@ (filter #(not (= "shutdown" (:state %))))) tasks/onclick-handler)))) +(defn form-pin-action + [service service-id pinned?] + (if pinned? + {:onClick #(detach-service-handler service-id) + :icon (comp/svg icon/pin-path) + :group false + :name "Detach"} + {:onClick #(pin-service-handler service-id) + :icon (comp/svg icon/pin-path) + :group false + :name "Pin"})) + (defn form-actions [service service-id pinned?] [(if pinned? @@ -348,7 +361,12 @@ (comp/grid {:item true :xs 12} - (toolbar/toolbar "Service" (:serviceName service) (form-actions service id pinned?))) + (toolbar/toolbar + "Service" + (:serviceName service) + (if (storage/user?) + (form-actions service id pinned?) + [(form-pin-action service id pinned?)]))) (comp/grid {:item true :sm 6 @@ -385,7 +403,12 @@ (comp/grid {:item true :xs 12} - (toolbar/toolbar "Service" (:serviceName service) (form-actions service id pinned?))) + (toolbar/toolbar + "Service" + (:serviceName service) + (if (storage/user?) + (form-actions service id pinned?) + [(form-pin-action service id pinned?)]))) (form-settings-grid service tasks stats) (form-tasks-grid service tasks) (form-networks-grid networks id immutable?) diff --git a/src/cljs/swarmpit/component/service/info/configs.cljs b/src/cljs/swarmpit/component/service/info/configs.cljs index 9ee16c5a..c96f0425 100644 --- a/src/cljs/swarmpit/component/service/info/configs.cljs +++ b/src/cljs/swarmpit/component/service/info/configs.cljs @@ -6,7 +6,8 @@ [swarmpit.routes :as routes] [swarmpit.url :refer [dispatch!]] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -24,14 +25,16 @@ (comp/card-header {:className "Swarmpit-table-card-header" :title (comp/typography {:variant "h6"} "Configs") - :action (comp/icon-button - {:aria-label "Edit" - :disabled immutable? - :href (routes/path-for-frontend - :service-edit - {:id service-id} - {:section 2})} - (comp/svg icon/edit-path))}) + :action (if (storage/user?) + (comp/icon-button + {:aria-label "Edit" + :disabled immutable? + :href (routes/path-for-frontend + :service-edit + {:id service-id} + {:section 2})} + (comp/svg icon/edit-path)) + nil)}) (if (empty? configs) (comp/card-content {} diff --git a/src/cljs/swarmpit/component/service/info/deployment.cljs b/src/cljs/swarmpit/component/service/info/deployment.cljs index f7c3fdb3..c9681bb0 100644 --- a/src/cljs/swarmpit/component/service/info/deployment.cljs +++ b/src/cljs/swarmpit/component/service/info/deployment.cljs @@ -4,7 +4,8 @@ [material.component.form :as form] [swarmpit.routes :as routes] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -28,14 +29,16 @@ (comp/card-header {:className "Swarmpit-form-card-header" :title (comp/typography {:variant "h6"} "Deployment") - :action (comp/icon-button - {:aria-label "Edit" - :disabled immutable? - :href (routes/path-for-frontend - :service-edit - {:id service-id} - {:section 4})} - (comp/svg icon/edit-path))}) + :action (if (storage/user?) + (comp/icon-button + {:aria-label "Edit" + :disabled immutable? + :href (routes/path-for-frontend + :service-edit + {:id service-id} + {:section 4})} + (comp/svg icon/edit-path)) + nil)}) (comp/card-content {} (comp/grid diff --git a/src/cljs/swarmpit/component/service/info/hosts.cljs b/src/cljs/swarmpit/component/service/info/hosts.cljs index c8f00db3..66903e70 100644 --- a/src/cljs/swarmpit/component/service/info/hosts.cljs +++ b/src/cljs/swarmpit/component/service/info/hosts.cljs @@ -5,7 +5,8 @@ [material.component.list.basic :as list] [swarmpit.routes :as routes] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -19,14 +20,16 @@ (comp/card-header {:className "Swarmpit-table-card-header" :title (comp/typography {:variant "h6"} "Extra hosts") - :action (comp/icon-button - {:aria-label "Edit" - :disabled immutable? - :href (routes/path-for-frontend - :service-edit - {:id service-id} - {:section 1})} - (comp/svg icon/edit-path))}) + :action (if (storage/user?) + (comp/icon-button + {:aria-label "Edit" + :disabled immutable? + :href (routes/path-for-frontend + :service-edit + {:id service-id} + {:section 1})} + (comp/svg icon/edit-path)) + nil)}) (if (empty? hosts) (comp/card-content {} diff --git a/src/cljs/swarmpit/component/service/info/labels.cljs b/src/cljs/swarmpit/component/service/info/labels.cljs index 86aca613..374dcf49 100644 --- a/src/cljs/swarmpit/component/service/info/labels.cljs +++ b/src/cljs/swarmpit/component/service/info/labels.cljs @@ -5,7 +5,8 @@ [material.component.list.basic :as list] [swarmpit.routes :as routes] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -19,14 +20,16 @@ (comp/card-header {:className "Swarmpit-table-card-header" :title (comp/typography {:variant "h6"} "Labels") - :action (comp/icon-button - {:aria-label "Edit" - :disabled immutable? - :href (routes/path-for-frontend - :service-edit - {:id service-id} - {:section 4})} - (comp/svg icon/edit-path))}) + :action (if (storage/user?) + (comp/icon-button + {:aria-label "Edit" + :disabled immutable? + :href (routes/path-for-frontend + :service-edit + {:id service-id} + {:section 4})} + (comp/svg icon/edit-path)) + nil)}) (if (empty? labels) (comp/card-content diff --git a/src/cljs/swarmpit/component/service/info/logdriver.cljs b/src/cljs/swarmpit/component/service/info/logdriver.cljs index 493c021a..e2bb16eb 100644 --- a/src/cljs/swarmpit/component/service/info/logdriver.cljs +++ b/src/cljs/swarmpit/component/service/info/logdriver.cljs @@ -5,7 +5,8 @@ [material.component.list.basic :as list] [swarmpit.routes :as routes] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -19,14 +20,16 @@ (comp/card-header {:className "Swarmpit-table-card-header" :title (comp/typography {:variant "h6"} "Log driver") - :action (comp/icon-button - {:aria-label "Edit" - :disabled immutable? - :href (routes/path-for-frontend - :service-edit - {:id service-id} - {:section 5})} - (comp/svg icon/edit-path))}) + :action (if (storage/user?) + (comp/icon-button + {:aria-label "Edit" + :disabled immutable? + :href (routes/path-for-frontend + :service-edit + {:id service-id} + {:section 5})} + (comp/svg icon/edit-path)) + nil)}) (comp/card-content {} (comp/grid diff --git a/src/cljs/swarmpit/component/service/info/mounts.cljs b/src/cljs/swarmpit/component/service/info/mounts.cljs index 7fa2db71..1a0eaa2b 100644 --- a/src/cljs/swarmpit/component/service/info/mounts.cljs +++ b/src/cljs/swarmpit/component/service/info/mounts.cljs @@ -6,7 +6,8 @@ [swarmpit.routes :as routes] [swarmpit.url :refer [dispatch!]] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -67,14 +68,16 @@ (comp/card-header {:className "Swarmpit-table-card-header" :title (comp/typography {:variant "h6"} "Mounts") - :action (comp/icon-button - {:aria-label "Edit" - :disabled immutable? - :href (routes/path-for-frontend - :service-edit - {:id service-id} - {:section 2})} - (comp/svg icon/edit-path))}) + :action (if (storage/user?) + (comp/icon-button + {:aria-label "Edit" + :disabled immutable? + :href (routes/path-for-frontend + :service-edit + {:id service-id} + {:section 2})} + (comp/svg icon/edit-path)) + nil)}) (if (empty? mounts) (comp/card-content diff --git a/src/cljs/swarmpit/component/service/info/networks.cljs b/src/cljs/swarmpit/component/service/info/networks.cljs index 12863082..3fe997de 100644 --- a/src/cljs/swarmpit/component/service/info/networks.cljs +++ b/src/cljs/swarmpit/component/service/info/networks.cljs @@ -6,7 +6,8 @@ [swarmpit.component.network.list :as networks] [swarmpit.routes :as routes] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -16,14 +17,16 @@ (comp/card-header {:className "Swarmpit-table-card-header" :title (comp/typography {:variant "h6"} "Networks") - :action (comp/icon-button - {:aria-label "Edit" - :disabled immutable? - :href (routes/path-for-frontend - :service-edit - {:id service-id} - {:section 1})} - (comp/svg icon/edit-path))}) + :action (if (storage/user?) + (comp/icon-button + {:aria-label "Edit" + :disabled immutable? + :href (routes/path-for-frontend + :service-edit + {:id service-id} + {:section 1})} + (comp/svg icon/edit-path)) + nil)}) (if (empty? networks) (comp/card-content {} diff --git a/src/cljs/swarmpit/component/service/info/ports.cljs b/src/cljs/swarmpit/component/service/info/ports.cljs index 6bfc8482..0f8673dc 100644 --- a/src/cljs/swarmpit/component/service/info/ports.cljs +++ b/src/cljs/swarmpit/component/service/info/ports.cljs @@ -5,7 +5,8 @@ [material.component.list.basic :as list] [swarmpit.routes :as routes] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -27,14 +28,16 @@ (comp/card-header {:className "Swarmpit-table-card-header" :title (comp/typography {:variant "h6"} "Ports") - :action (comp/icon-button - {:aria-label "Edit" - :disabled immutable? - :href (routes/path-for-frontend - :service-edit - {:id service-id} - {:section 1})} - (comp/svg icon/edit-path))}) + :action (if (storage/user?) + (comp/icon-button + {:aria-label "Edit" + :disabled immutable? + :href (routes/path-for-frontend + :service-edit + {:id service-id} + {:section 1})} + (comp/svg icon/edit-path)) + nil)}) (if (empty? ports) (comp/card-content {} diff --git a/src/cljs/swarmpit/component/service/info/resources.cljs b/src/cljs/swarmpit/component/service/info/resources.cljs index 8c82a646..b59a6577 100644 --- a/src/cljs/swarmpit/component/service/info/resources.cljs +++ b/src/cljs/swarmpit/component/service/info/resources.cljs @@ -4,7 +4,8 @@ [material.component.form :as form] [swarmpit.routes :as routes] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (defn format-cpu [value] @@ -24,14 +25,16 @@ (comp/card-header {:className "Swarmpit-form-card-header" :title (comp/typography {:variant "h6"} "Resources") - :action (comp/icon-button - {:aria-label "Edit" - :disabled immutable? - :href (routes/path-for-frontend - :service-edit - {:id service-id} - {:section 3})} - (comp/svg icon/edit-path))}) + :action (if (storage/user?) + (comp/icon-button + {:aria-label "Edit" + :disabled immutable? + :href (routes/path-for-frontend + :service-edit + {:id service-id} + {:section 3})} + (comp/svg icon/edit-path)) + nil)}) (comp/card-content {} (comp/grid diff --git a/src/cljs/swarmpit/component/service/info/secrets.cljs b/src/cljs/swarmpit/component/service/info/secrets.cljs index 3ed33e0d..1ba4407f 100644 --- a/src/cljs/swarmpit/component/service/info/secrets.cljs +++ b/src/cljs/swarmpit/component/service/info/secrets.cljs @@ -6,7 +6,8 @@ [swarmpit.routes :as routes] [swarmpit.url :refer [dispatch!]] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -24,14 +25,16 @@ (comp/card-header {:className "Swarmpit-table-card-header" :title (comp/typography {:variant "h6"} "Secrets") - :action (comp/icon-button - {:aria-label "Edit" - :disabled immutable? - :href (routes/path-for-frontend - :service-edit - {:id service-id} - {:section 2})} - (comp/svg icon/edit-path))}) + :action (if (storage/user?) + (comp/icon-button + {:aria-label "Edit" + :disabled immutable? + :href (routes/path-for-frontend + :service-edit + {:id service-id} + {:section 2})} + (comp/svg icon/edit-path)) + nil)}) (if (empty? secrets) (comp/card-content {} @@ -41,5 +44,7 @@ (list/list render-metadata secrets - onclick-handler))))) + (if (storage/user?) + onclick-handler + nil)))))) diff --git a/src/cljs/swarmpit/component/service/info/variables.cljs b/src/cljs/swarmpit/component/service/info/variables.cljs index b6d757aa..a8527820 100644 --- a/src/cljs/swarmpit/component/service/info/variables.cljs +++ b/src/cljs/swarmpit/component/service/info/variables.cljs @@ -5,7 +5,8 @@ [material.component.list.basic :as list] [swarmpit.routes :as routes] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -19,14 +20,16 @@ (comp/card-header {:className "Swarmpit-table-card-header" :title (comp/typography {:variant "h6"} "Environment variables") - :action (comp/icon-button - {:aria-label "Edit" - :disabled immutable? - :href (routes/path-for-frontend - :service-edit - {:id service-id} - {:section 2})} - (comp/svg icon/edit-path))}) + :action (if (storage/user?) + (comp/icon-button + {:aria-label "Edit" + :disabled immutable? + :href (routes/path-for-frontend + :service-edit + {:id service-id} + {:section 2})} + (comp/svg icon/edit-path)) + nil)}) (if (empty? variables) (comp/card-content {} diff --git a/src/cljs/swarmpit/component/service/list.cljs b/src/cljs/swarmpit/component/service/list.cljs index 23c34c3a..4dda9d5d 100644 --- a/src/cljs/swarmpit/component/service/list.cljs +++ b/src/cljs/swarmpit/component/service/list.cljs @@ -14,7 +14,8 @@ [swarmpit.routes :as routes] [swarmpit.url :refer [dispatch!]] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -180,5 +181,7 @@ filtered-items render-metadata onclick-handler - toolbar-render-metadata) + (if (storage/user?) + toolbar-render-metadata + "")) (form-filters filterOpen? filter))))) diff --git a/src/cljs/swarmpit/component/stack/info.cljs b/src/cljs/swarmpit/component/stack/info.cljs index 17da9541..81e30963 100644 --- a/src/cljs/swarmpit/component/stack/info.cljs +++ b/src/cljs/swarmpit/component/stack/info.cljs @@ -26,7 +26,8 @@ [clojure.contrib.inflect :as inflect] [clojure.contrib.humanize :as humanize] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -337,7 +338,9 @@ (list/list (:list secrets/render-metadata) (sort-by :secretName secrets) - secrets/onclick-handler))))) + (if (storage/user?) + secrets/onclick-handler + nil)))))) (defn- init-form-state [] @@ -417,10 +420,11 @@ (comp/grid {:container true :spacing 2} - (comp/grid - {:item true - :xs 12} - (toolbar/toolbar "Stack" stack-name (form-actions stack-name stackfile))) + (if (storage/user?) + (comp/grid + {:item true + :xs 12} + (toolbar/toolbar "Stack" stack-name (form-actions stack-name stackfile)))) (comp/grid {:item true :sm 6 @@ -447,10 +451,11 @@ (comp/grid {:container true :spacing 2} - (comp/grid - {:item true - :xs 12} - (toolbar/toolbar "Stack" stack-name (form-actions stack-name stackfile))) + (if (storage/user?) + (comp/grid + {:item true + :xs 12} + (toolbar/toolbar "Stack" stack-name (form-actions stack-name stackfile)))) (form-general-grid stack-name stackfile item) (form-services-grid stack-name services) (form-networks-grid stack-name networks) diff --git a/src/cljs/swarmpit/component/stack/list.cljs b/src/cljs/swarmpit/component/stack/list.cljs index b033477d..9ea4b437 100644 --- a/src/cljs/swarmpit/component/stack/list.cljs +++ b/src/cljs/swarmpit/component/stack/list.cljs @@ -12,7 +12,8 @@ [swarmpit.url :refer [dispatch!]] [sablono.core :refer-macros [html]] [rum.core :as rum] - [swarmpit.component.common :as common])) + [swarmpit.component.common :as common] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -106,4 +107,6 @@ (sort-by :stackName)) render-metadata onclick-handler - toolbar-render-metadata)))) + (if (storage/user?) + toolbar-render-metadata + ""))))) diff --git a/src/cljs/swarmpit/component/user/create.cljs b/src/cljs/swarmpit/component/user/create.cljs index e3aff7f3..72fb871b 100644 --- a/src/cljs/swarmpit/component/user/create.cljs +++ b/src/cljs/swarmpit/component/user/create.cljs @@ -58,6 +58,14 @@ :key "role-rg" :value value :onChange #(state/update-value [:role] (-> % .-target .-value) state/form-value-cursor)} + (comp/form-control-label + {:control (comp/radio + {:name "viewer-role" + :color "primary" + :key "viewer-role"}) + :key "viewer-role" + :value "viewer" + :label "View Only"}) (comp/form-control-label {:control (comp/radio {:name "user-role" @@ -114,7 +122,7 @@ (state/set-value {:username "" :password "" :email "" - :role "user"} state/form-value-cursor)) + :role "viewer"} state/form-value-cursor)) (def mixin-init-form (mixin/init-form diff --git a/src/cljs/swarmpit/component/user/edit.cljs b/src/cljs/swarmpit/component/user/edit.cljs index 189b9330..73662a6d 100644 --- a/src/cljs/swarmpit/component/user/edit.cljs +++ b/src/cljs/swarmpit/component/user/edit.cljs @@ -42,6 +42,14 @@ :key "role-rg" :value value :onChange #(state/update-value [:role] (-> % .-target .-value) state/form-value-cursor)} + (comp/form-control-label + {:control (comp/radio + {:name "viewer-role" + :color "primary" + :key "viewer-role"}) + :key "viewer-role" + :value "viewer" + :label "View Only"}) (comp/form-control-label {:control (comp/radio {:name "user-role" diff --git a/src/cljs/swarmpit/component/user/list.cljs b/src/cljs/swarmpit/component/user/list.cljs index 87580539..eb126e60 100644 --- a/src/cljs/swarmpit/component/user/list.cljs +++ b/src/cljs/swarmpit/component/user/list.cljs @@ -20,8 +20,15 @@ :render-fn (fn [item] (:username item))} {:name "Email" :render-fn (fn [item] (:email item))} + {:name "Role" + :render-fn (fn [item] + (if (="admin" (:role item)) + "Admin" + (if (="user" (:role item)) + "User" + "View Only")))} {:name "Is Admin" - :render-fn (fn [item] (if (:role item) "yes" "no"))}]} + :render-fn (fn [item] (if (= "admin" (:role item)) "Yes" "-"))}]} :list {:primary (fn [item] (:username item)) :secondary (fn [item] (:email item))}}) diff --git a/src/cljs/swarmpit/component/volume/info.cljs b/src/cljs/swarmpit/component/volume/info.cljs index 0c58e428..8e0e4cd1 100644 --- a/src/cljs/swarmpit/component/volume/info.cljs +++ b/src/cljs/swarmpit/component/volume/info.cljs @@ -17,7 +17,8 @@ [swarmpit.routes :as routes] [sablono.core :refer-macros [html]] [clojure.contrib.humanize :as humanize] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -117,10 +118,11 @@ (comp/grid {:container true :spacing 2} - (comp/grid - {:item true - :xs 12} - (toolbar/toolbar "Volume" (:volumeName volume) form-actions)) + (if (storage/user?) + (comp/grid + {:item true + :xs 12} + (toolbar/toolbar "Volume" (:volumeName volume) form-actions))) (comp/grid {:item true :xs 12} diff --git a/src/cljs/swarmpit/component/volume/list.cljs b/src/cljs/swarmpit/component/volume/list.cljs index 8eabbd01..5a9eee09 100644 --- a/src/cljs/swarmpit/component/volume/list.cljs +++ b/src/cljs/swarmpit/component/volume/list.cljs @@ -11,7 +11,8 @@ [swarmpit.routes :as routes] [swarmpit.url :refer [dispatch!]] [sablono.core :refer-macros [html]] - [rum.core :as rum])) + [rum.core :as rum] + [swarmpit.storage :as storage])) (enable-console-print!) @@ -73,4 +74,6 @@ filtered-items render-metadata onclick-handler - toolbar-render-metadata)))) + (if (storage/user?) + toolbar-render-metadata + ""))))) diff --git a/src/cljs/swarmpit/storage.cljs b/src/cljs/swarmpit/storage.cljs index 54f92513..9075fd99 100644 --- a/src/cljs/swarmpit/storage.cljs +++ b/src/cljs/swarmpit/storage.cljs @@ -49,3 +49,7 @@ (defn admin? [] (token/admin? (get-in (claims) [:usr]))) + +(defn user? + [] + (token/user? (get-in (claims) [:usr])))