mirror of
https://github.com/penpot/penpot.git
synced 2026-04-25 11:18:36 +00:00
🐛 Fix switching a team nitrate organization lose the background
This commit is contained in:
parent
01d68ec09b
commit
debfe5490f
@ -10,9 +10,11 @@
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.json :as json]
|
||||
[app.common.logging :as l]
|
||||
[app.common.organization :as co]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.schema.generators :as sg]
|
||||
[app.common.time :as ct]
|
||||
[app.common.types.team :as ctt]
|
||||
[app.config :as cf]
|
||||
[app.http.client :as http]
|
||||
[app.rpc :as-alias rpc]
|
||||
@ -108,16 +110,6 @@
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(def ^:private schema:organization
|
||||
[:map
|
||||
[:id ::sm/uuid]
|
||||
[:name ::sm/text]
|
||||
[:slug ::sm/text]
|
||||
[:is-your-penpot :boolean]
|
||||
[:owner-id ::sm/uuid]
|
||||
[:avatar-bg-url [::sm/text]]
|
||||
[:logo-id {:optional true} [:maybe ::sm/uuid]]])
|
||||
|
||||
(def ^:private schema:org-summary
|
||||
[:map
|
||||
[:id ::sm/uuid]
|
||||
@ -129,12 +121,6 @@
|
||||
[:id ::sm/uuid]
|
||||
[:is-your-penpot :boolean]]]]])
|
||||
|
||||
(def ^:private schema:team
|
||||
[:map
|
||||
[:id ::sm/uuid]
|
||||
[:organization-id ::sm/uuid]
|
||||
[:is-your-penpot :boolean]])
|
||||
|
||||
(def ^:private schema:profile-org
|
||||
[:map
|
||||
[:is-member :boolean]
|
||||
@ -221,7 +207,7 @@
|
||||
(str baseuri
|
||||
"/api/teams/"
|
||||
team-id)
|
||||
schema:organization params)))
|
||||
ctt/schema:team-with-organization params)))
|
||||
|
||||
(defn- get-org-membership-api
|
||||
[cfg {:keys [profile-id organization-id] :as params}]
|
||||
@ -261,13 +247,18 @@
|
||||
[cfg {:keys [organization-id team-id is-default] :as params}]
|
||||
(let [baseuri (cf/get :nitrate-backend-uri)
|
||||
params (assoc params :request-params {:team-id team-id
|
||||
:is-your-penpot (true? is-default)})]
|
||||
(request-to-nitrate cfg :post
|
||||
(str baseuri
|
||||
"/api/organizations/"
|
||||
organization-id
|
||||
"/add-team")
|
||||
schema:team params)))
|
||||
:is-your-penpot (true? is-default)})
|
||||
team (request-to-nitrate cfg :post
|
||||
(str baseuri
|
||||
"/api/organizations/"
|
||||
organization-id
|
||||
"/add-team")
|
||||
ctt/schema:team-with-organization params)
|
||||
custom-photo (when-let [logo-id (get-in team [:organization :logo-id])]
|
||||
(str (cf/get :public-uri) "/assets/by-id/" logo-id))]
|
||||
(cond-> team
|
||||
custom-photo
|
||||
(assoc-in [:organization :custom-photo] custom-photo))))
|
||||
|
||||
(defn- add-profile-to-org-api
|
||||
[cfg {:keys [profile-id organization-id team-id email] :as params}]
|
||||
@ -385,18 +376,14 @@
|
||||
Returns the original team unchanged if the request fails or org data is nil."
|
||||
[cfg team params]
|
||||
(try
|
||||
(let [params (assoc (or params {}) :team-id (:id team))
|
||||
org (call cfg :get-team-org params)]
|
||||
(let [params (assoc (or params {}) :team-id (:id team))
|
||||
team-with-org (call cfg :get-team-org params)
|
||||
org (:organization team-with-org)]
|
||||
(if (some? org)
|
||||
(assoc team
|
||||
:organization-id (:id org)
|
||||
:organization-name (:name org)
|
||||
:organization-slug (:slug org)
|
||||
:organization-owner-id (:owner-id org)
|
||||
:organization-avatar-bg-url (:avatar-bg-url org)
|
||||
:organization-custom-photo (when-let [logo-id (:logo-id org)]
|
||||
(str (cf/get :public-uri) "/assets/by-id/" logo-id))
|
||||
:is-default (or (:is-default team) (true? (:is-your-penpot org))))
|
||||
(-> (co/apply-organization team (assoc org :custom-photo
|
||||
(when-let [logo-id (:logo-id org)]
|
||||
(str (cf/get :public-uri) "/assets/by-id/" logo-id))))
|
||||
(assoc :is-default (or (:is-default team) (true? (:is-your-penpot team-with-org)))))
|
||||
team))
|
||||
(catch Throwable cause
|
||||
(l/error :hint "failed to get team organization info"
|
||||
|
||||
@ -249,22 +249,21 @@
|
||||
(nitrate/call cfg :remove-team-from-org {:team-id team-id :organization-id organization-id})
|
||||
|
||||
;; Notify connected users
|
||||
(notifications/notify-team-change cfg team-id nil nil organization-name "dashboard.team-no-longer-belong-org")
|
||||
(notifications/notify-team-change cfg {:id team-id :organization {:name organization-name}} "dashboard.team-no-longer-belong-org")
|
||||
nil)
|
||||
|
||||
|
||||
(def ^:private schema:add-team-to-org
|
||||
[:map
|
||||
[:team-id ::sm/uuid]
|
||||
[:organization-id ::sm/uuid]
|
||||
[:organization-name ::sm/text]])
|
||||
[:organization-id ::sm/uuid]])
|
||||
|
||||
(sv/defmethod ::add-team-to-org
|
||||
{::rpc/auth true
|
||||
::doc/added "2.17"
|
||||
::sm/params schema:add-team-to-org
|
||||
::db/transaction true}
|
||||
[cfg {:keys [::rpc/profile-id team-id organization-id organization-name]}]
|
||||
[cfg {:keys [::rpc/profile-id team-id organization-id]}]
|
||||
|
||||
(assert-is-owner cfg profile-id team-id)
|
||||
(assert-not-default-team cfg team-id)
|
||||
@ -277,8 +276,8 @@
|
||||
(teams/initialize-user-in-nitrate-org cfg member-id organization-id)))
|
||||
|
||||
;; Api call to nitrate
|
||||
(nitrate/call cfg :set-team-org {:team-id team-id :organization-id organization-id :is-default false})
|
||||
(let [team (nitrate/call cfg :set-team-org {:team-id team-id :organization-id organization-id :is-default false})]
|
||||
|
||||
;; Notify connected users
|
||||
(notifications/notify-team-change cfg team-id nil organization-id organization-name "dashboard.team-belong-org")
|
||||
;; Notify connected users
|
||||
(notifications/notify-team-change cfg team "dashboard.team-belong-org"))
|
||||
nil)
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.types.profile :refer [schema:profile, schema:basic-profile]]
|
||||
[app.common.types.team :refer [schema:team]]
|
||||
[app.common.types.team :refer [schema:team schema:team-with-organization]]
|
||||
[app.config :as cf]
|
||||
[app.db :as db]
|
||||
[app.media :as media]
|
||||
@ -117,22 +117,13 @@
|
||||
|
||||
;; ---- API: notify-team-change
|
||||
|
||||
(def ^:private schema:notify-team-change
|
||||
[:map
|
||||
[:id ::sm/uuid]
|
||||
[:organization-id ::sm/uuid]
|
||||
[:organization-name ::sm/text]])
|
||||
|
||||
|
||||
|
||||
|
||||
(sv/defmethod ::notify-team-change
|
||||
"Notify to Penpot a team change from nitrate"
|
||||
{::doc/added "2.14"
|
||||
::sm/params schema:notify-team-change
|
||||
::sm/params schema:team-with-organization
|
||||
::rpc/auth false}
|
||||
[cfg {:keys [id organization-id organization-name]}]
|
||||
(notifications/notify-team-change cfg id nil organization-id organization-name nil)
|
||||
[cfg team]
|
||||
(notifications/notify-team-change cfg (select-keys team [:id :is-your-penpot :organization]) nil)
|
||||
nil)
|
||||
|
||||
;; ---- API: notify-user-added-to-organization
|
||||
@ -143,8 +134,6 @@
|
||||
[:organization-id ::sm/uuid]
|
||||
[:role ::sm/text]])
|
||||
|
||||
|
||||
|
||||
(sv/defmethod ::notify-user-added-to-organization
|
||||
"Notify to Penpot that an user has joined an org from nitrate"
|
||||
{::doc/added "2.14"
|
||||
@ -271,7 +260,7 @@ RETURNING id, name;")
|
||||
|
||||
;; Notify users
|
||||
(doseq [team updated-teams]
|
||||
(notifications/notify-team-change cfg (:id team) (:name team) nil organization-name "dashboard.org-deleted"))))))))
|
||||
(notifications/notify-team-change cfg {:id (:id team) :name (:name team) :organization {:name organization-name}} "dashboard.org-deleted"))))))))
|
||||
|
||||
;; ---- API: get-profile-by-email
|
||||
|
||||
|
||||
@ -10,17 +10,14 @@
|
||||
[app.msgbus :as mbus]))
|
||||
|
||||
(defn notify-team-change
|
||||
[cfg team-id team-name organization-id organization-name notification]
|
||||
[cfg team notification]
|
||||
(let [msgbus (::mbus/msgbus cfg)]
|
||||
(mbus/pub! msgbus
|
||||
;;TODO There is a bug on dashboard with teams notifications.
|
||||
;;For now we send it to uuid/zero instead of team-id
|
||||
:topic uuid/zero
|
||||
:message {:type :team-org-change
|
||||
:team-id team-id
|
||||
:team-name team-name
|
||||
:organization-id organization-id
|
||||
:organization-name organization-name
|
||||
:team team
|
||||
:notification notification})))
|
||||
|
||||
|
||||
|
||||
@ -74,24 +74,32 @@
|
||||
(t/deftest notify-team-change-publishes-event
|
||||
(let [team-id (uuid/random)
|
||||
organization-id (uuid/random)
|
||||
organization {:id organization-id
|
||||
:name "Acme Inc"
|
||||
:slug "acme-inc"
|
||||
:owner-id (uuid/random)
|
||||
:avatar-bg-url "http://example.com/avatar.svg"}
|
||||
calls (atom [])
|
||||
out (with-redefs [mbus/pub! (fn [_cfg & {:keys [topic message]}]
|
||||
(swap! calls conj {:topic topic
|
||||
:message message}))]
|
||||
(management-command-with-nitrate! {::th/type :notify-team-change
|
||||
:id team-id
|
||||
:organization-id organization-id
|
||||
:organization-name "Acme Inc"}))]
|
||||
:is-your-penpot false
|
||||
:organization organization}))]
|
||||
(t/is (th/success? out))
|
||||
(t/is (= 1 (count @calls)))
|
||||
(t/is (= uuid/zero (-> @calls first :topic)))
|
||||
(t/is (= {:type :team-org-change
|
||||
:team-id team-id
|
||||
:team-name nil
|
||||
:organization-id organization-id
|
||||
:organization-name "Acme Inc"
|
||||
:notification nil}
|
||||
(-> @calls first :message)))))
|
||||
(let [msg (-> @calls first :message)]
|
||||
(t/is (= :team-org-change (:type msg)))
|
||||
(t/is (= nil (:notification msg)))
|
||||
(t/is (= team-id (-> msg :team :id)))
|
||||
(t/is (= false (-> msg :team :is-your-penpot)))
|
||||
(t/is (= (:id organization) (-> msg :team :organization :id)))
|
||||
(t/is (= (:name organization) (-> msg :team :organization :name)))
|
||||
(t/is (= (:slug organization) (-> msg :team :organization :slug)))
|
||||
(t/is (= (:owner-id organization) (-> msg :team :organization :owner-id)))
|
||||
(t/is (= (:avatar-bg-url organization) (str (-> msg :team :organization :avatar-bg-url)))))))
|
||||
|
||||
(t/deftest notify-user-added-to-organization-creates-default-org-team
|
||||
(let [profile (th/create-profile* 1 {:is-active true})
|
||||
@ -181,7 +189,7 @@
|
||||
(doseq [call @calls]
|
||||
(t/is (= uuid/zero (:topic call)))
|
||||
(t/is (= :team-org-change (-> call :message :type)))
|
||||
(t/is (= organization-name (-> call :message :organization-name)))
|
||||
(t/is (= organization-name (-> call :message :team :organization :name)))
|
||||
(t/is (= "dashboard.org-deleted" (-> call :message :notification))))))
|
||||
|
||||
(t/deftest get-profile-by-email-success-and-not-found
|
||||
|
||||
32
common/src/app/common/organization.cljc
Normal file
32
common/src/app/common/organization.cljc
Normal file
@ -0,0 +1,32 @@
|
||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.common.organization)
|
||||
|
||||
(def organization->team-keys
|
||||
"Mapping from organization field keys to their corresponding :organization-* team keys."
|
||||
[[:id :organization-id]
|
||||
[:name :organization-name]
|
||||
[:custom-photo :organization-custom-photo]
|
||||
[:slug :organization-slug]
|
||||
[:avatar-bg-url :organization-avatar-bg-url]
|
||||
[:owner-id :organization-owner-id]])
|
||||
|
||||
(defn apply-organization
|
||||
"Updates a team map with organization fields sourced from org.
|
||||
Associates each org field to the corresponding :organization-* team key when
|
||||
the value is non-nil; dissociates the key otherwise. This correctly handles
|
||||
both attaching an org (all values present) and detaching one (org is nil or
|
||||
all fields absent)."
|
||||
[team organization]
|
||||
(let [id (:id organization)]
|
||||
(reduce (fn [acc [org-k team-k]]
|
||||
(let [v (get organization org-k)]
|
||||
(if (and id (some? v))
|
||||
(assoc acc team-k v)
|
||||
(dissoc acc team-k))))
|
||||
team
|
||||
organization->team-keys)))
|
||||
@ -26,3 +26,16 @@
|
||||
[:id ::sm/uuid]
|
||||
[:name :string]])
|
||||
|
||||
(def schema:team-with-organization
|
||||
[:map
|
||||
[:id ::sm/uuid]
|
||||
[:is-your-penpot :boolean]
|
||||
[:organization
|
||||
[:map
|
||||
[:id ::sm/uuid]
|
||||
[:name ::sm/text]
|
||||
[:slug ::sm/text]
|
||||
[:owner-id ::sm/uuid]
|
||||
[:avatar-bg-url ::sm/uri]
|
||||
[:logo-id {:optional true} [:maybe ::sm/uuid]]]]])
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
[app.common.features :as cfeat]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.logging :as log]
|
||||
[app.common.organization :as co]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.time :as ct]
|
||||
[app.common.types.project :refer [valid-project?]]
|
||||
@ -686,29 +687,29 @@
|
||||
(modal/hide)))))
|
||||
|
||||
(defn handle-change-team-org
|
||||
[{:keys [team-id team-name organization-id organization-name notification]}]
|
||||
[{:keys [team notification]}]
|
||||
(ptk/reify ::handle-change-team-org
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [current-team-id (:current-team-id state)]
|
||||
(let [current-team-id (:current-team-id state)
|
||||
organization (:organization team)]
|
||||
(when (and (contains? cf/flags :nitrate)
|
||||
notification
|
||||
(= team-id current-team-id))
|
||||
(rx/of (ntf/show {:content (tr notification organization-name)
|
||||
(= (:id team) current-team-id))
|
||||
(rx/of (ntf/show {:content (tr notification (:name organization))
|
||||
:type :toast
|
||||
:level :info
|
||||
:timeout nil})))))
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(if (contains? cf/flags :nitrate)
|
||||
(d/update-in-when state [:teams team-id]
|
||||
(fn [team]
|
||||
(cond-> team
|
||||
(some? organization-id) (assoc :organization-id organization-id)
|
||||
(nil? organization-id) (dissoc :organization-id)
|
||||
(some? organization-name) (assoc :organization-name organization-name)
|
||||
(nil? organization-name) (dissoc :organization-name)
|
||||
team-name (assoc :name team-name))))
|
||||
(let [team-id (:id team)
|
||||
team-name (:name team)
|
||||
organization (:organization team)]
|
||||
(d/update-in-when state [:teams team-id]
|
||||
(fn [team]
|
||||
(cond-> (co/apply-organization team organization)
|
||||
team-name (assoc :name team-name)))))
|
||||
state))))
|
||||
|
||||
(defn- handle-user-org-change
|
||||
|
||||
@ -126,11 +126,11 @@
|
||||
|
||||
|
||||
(defn add-team-to-org
|
||||
[{:keys [team-id organization-id organization-name] :as params}]
|
||||
[{:keys [team-id organization-id] :as params}]
|
||||
(ptk/reify ::add-team-to-org
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/cmd! ::add-team-to-org {:team-id team-id :organization-id organization-id :organization-name organization-name})
|
||||
(->> (rp/cmd! ::add-team-to-org {:team-id team-id :organization-id organization-id})
|
||||
(rx/mapcat
|
||||
(fn [_]
|
||||
(rx/of (modal/hide))))))))
|
||||
|
||||
@ -1437,8 +1437,7 @@
|
||||
(let [organization (d/seek #(= organization-id (:id %)) organizations)]
|
||||
(when organization
|
||||
(st/emit! (dnt/add-team-to-org {:team-id (:id team)
|
||||
:organization-id organization-id
|
||||
:organization-name (:name organization)}))))))
|
||||
:organization-id organization-id}))))))
|
||||
|
||||
on-add-team-to-org
|
||||
(mf/use-fn
|
||||
|
||||
@ -874,7 +874,6 @@
|
||||
// SELECT ORGANIZATION MODAL
|
||||
|
||||
.modal-select-org-container {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: $sz-512;
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
outline-offset: calc(-1 * $b-1);
|
||||
background-color: var(--options-bg-color);
|
||||
color: var(--options-fg-color);
|
||||
cursor: default;
|
||||
|
||||
&:hover,
|
||||
&[aria-selected="true"] {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user