mirror of
https://github.com/penpot/penpot.git
synced 2025-05-25 12:06:11 +02:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
3026bd8aaf
14 changed files with 220 additions and 259 deletions
|
@ -21,6 +21,12 @@
|
||||||
|
|
||||||
### :bug: Bugs fixed
|
### :bug: Bugs fixed
|
||||||
|
|
||||||
|
- Don't allow registry with email and password, if password login is disabled (invitation workflow) [Github #4975](https://github.com/penpot/penpot/issues/4975)
|
||||||
|
|
||||||
|
## 2.1.2
|
||||||
|
|
||||||
|
### :bug: Bugs fixed
|
||||||
|
|
||||||
- User switch language to "zh_hant" will get 400 [Github #4884](https://github.com/penpot/penpot/issues/4884)
|
- User switch language to "zh_hant" will get 400 [Github #4884](https://github.com/penpot/penpot/issues/4884)
|
||||||
- Smtp config ignoring port if ssl is set [Github #4872](https://github.com/penpot/penpot/issues/4872)
|
- Smtp config ignoring port if ssl is set [Github #4872](https://github.com/penpot/penpot/issues/4872)
|
||||||
- Ability to let users to authenticate with a private oidc provider only [Github #4963](https://github.com/penpot/penpot/issues/4963)
|
- Ability to let users to authenticate with a private oidc provider only [Github #4963](https://github.com/penpot/penpot/issues/4963)
|
||||||
|
|
|
@ -180,10 +180,11 @@
|
||||||
(defn- validate-register-attempt!
|
(defn- validate-register-attempt!
|
||||||
[cfg params]
|
[cfg params]
|
||||||
|
|
||||||
(when-not (contains? cf/flags :registration)
|
(when (or
|
||||||
(when-not (contains? params :invitation-token)
|
(not (contains? cf/flags :registration))
|
||||||
|
(not (contains? cf/flags :login-with-password)))
|
||||||
(ex/raise :type :restriction
|
(ex/raise :type :restriction
|
||||||
:code :registration-disabled)))
|
:code :registration-disabled))
|
||||||
|
|
||||||
(when (contains? params :invitation-token)
|
(when (contains? params :invitation-token)
|
||||||
(let [invitation (tokens/verify (::setup/props cfg)
|
(let [invitation (tokens/verify (::setup/props cfg)
|
||||||
|
@ -282,6 +283,7 @@
|
||||||
is-demo (:is-demo params false)
|
is-demo (:is-demo params false)
|
||||||
is-muted (:is-muted params false)
|
is-muted (:is-muted params false)
|
||||||
is-active (:is-active params false)
|
is-active (:is-active params false)
|
||||||
|
theme (:theme params nil)
|
||||||
email (str/lower email)
|
email (str/lower email)
|
||||||
|
|
||||||
params {:id id
|
params {:id id
|
||||||
|
@ -292,6 +294,7 @@
|
||||||
:password password
|
:password password
|
||||||
:deleted-at (:deleted-at params)
|
:deleted-at (:deleted-at params)
|
||||||
:props props
|
:props props
|
||||||
|
:theme theme
|
||||||
:is-active is-active
|
:is-active is-active
|
||||||
:is-muted is-muted
|
:is-muted is-muted
|
||||||
:is-demo is-demo}]
|
:is-demo is-demo}]
|
||||||
|
@ -347,11 +350,13 @@
|
||||||
:extra-data ptoken})))
|
:extra-data ptoken})))
|
||||||
|
|
||||||
(defn register-profile
|
(defn register-profile
|
||||||
[{:keys [::db/conn] :as cfg} {:keys [token fullname] :as params}]
|
[{:keys [::db/conn] :as cfg} {:keys [token fullname theme] :as params}]
|
||||||
(let [claims (tokens/verify (::setup/props cfg) {:token token :iss :prepared-register})
|
(let [theme (when (= theme "light") theme)
|
||||||
|
claims (tokens/verify (::setup/props cfg) {:token token :iss :prepared-register})
|
||||||
params (-> claims
|
params (-> claims
|
||||||
(into params)
|
(into params)
|
||||||
(assoc :fullname fullname))
|
(assoc :fullname fullname)
|
||||||
|
(assoc :theme theme))
|
||||||
|
|
||||||
profile (if-let [profile-id (:profile-id claims)]
|
profile (if-let [profile-id (:profile-id claims)]
|
||||||
(profile/get-profile conn profile-id)
|
(profile/get-profile conn profile-id)
|
||||||
|
@ -456,7 +461,8 @@
|
||||||
(def schema:register-profile
|
(def schema:register-profile
|
||||||
[:map {:title "register-profile"}
|
[:map {:title "register-profile"}
|
||||||
[:token schema:token]
|
[:token schema:token]
|
||||||
[:fullname [::sm/word-string {:max 100}]]])
|
[:fullname [::sm/word-string {:max 100}]]
|
||||||
|
[:theme {:optional true} [:string {:max 10}]]])
|
||||||
|
|
||||||
(sv/defmethod ::register-profile
|
(sv/defmethod ::register-profile
|
||||||
{::rpc/auth false
|
{::rpc/auth false
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.db.sql :as-alias sql]
|
[app.db.sql :as-alias sql]
|
||||||
[app.http.session :as session]
|
[app.http.session :as session]
|
||||||
|
@ -160,7 +161,8 @@
|
||||||
{:team-id team-id :email-to member-email})
|
{:team-id team-id :email-to member-email})
|
||||||
profile (db/get* conn :profile
|
profile (db/get* conn :profile
|
||||||
{:id profile-id}
|
{:id profile-id}
|
||||||
{:columns [:id :email]})]
|
{:columns [:id :email]})
|
||||||
|
registration-disabled? (not (contains? cf/flags :registration))]
|
||||||
(when (nil? invitation)
|
(when (nil? invitation)
|
||||||
(ex/raise :type :validation
|
(ex/raise :type :validation
|
||||||
:code :invalid-token
|
:code :invalid-token
|
||||||
|
@ -189,12 +191,12 @@
|
||||||
:hint "logged-in user does not matches the invitation"))
|
:hint "logged-in user does not matches the invitation"))
|
||||||
|
|
||||||
;; If we have not logged-in user, and invitation comes with member-id we
|
;; If we have not logged-in user, and invitation comes with member-id we
|
||||||
;; redirect user to login, if no memeber-id is present in the invitation
|
;; redirect user to login, if no memeber-id is present and in the invitation
|
||||||
;; token, we redirect user the the register page.
|
;; token and registration is enabled, we redirect user the the register page.
|
||||||
|
|
||||||
{:invitation-token token
|
{:invitation-token token
|
||||||
:iss :team-invitation
|
:iss :team-invitation
|
||||||
:redirect-to (if member-id :auth-login :auth-register)
|
:redirect-to (if (or member-id registration-disabled?) :auth-login :auth-register)
|
||||||
:state :pending})))
|
:state :pending})))
|
||||||
|
|
||||||
;; --- Default
|
;; --- Default
|
||||||
|
|
|
@ -505,9 +505,7 @@
|
||||||
(t/is (nil? (:error out)))
|
(t/is (nil? (:error out)))
|
||||||
(t/is (= 0 (:call-count @mock))))))))
|
(t/is (= 0 (:call-count @mock))))))))
|
||||||
|
|
||||||
|
(t/deftest prepare-and-register-with-invitation-and-enabled-registration-1
|
||||||
(t/deftest prepare-and-register-with-invitation-and-disabled-registration-1
|
|
||||||
(with-redefs [app.config/flags [:disable-registration]]
|
|
||||||
(let [sprops (:app.setup/props th/*system*)
|
(let [sprops (:app.setup/props th/*system*)
|
||||||
itoken (tokens/generate sprops
|
itoken (tokens/generate sprops
|
||||||
{:iss :team-invitation
|
{:iss :team-invitation
|
||||||
|
@ -534,7 +532,47 @@
|
||||||
;; (th/print-result! out)
|
;; (th/print-result! out)
|
||||||
(t/is (nil? error))
|
(t/is (nil? error))
|
||||||
(t/is (map? result))
|
(t/is (map? result))
|
||||||
(t/is (string? (:invitation-token result)))))))
|
(t/is (string? (:invitation-token result))))))
|
||||||
|
|
||||||
|
(t/deftest prepare-and-register-with-invitation-and-enabled-registration-2
|
||||||
|
(let [sprops (:app.setup/props th/*system*)
|
||||||
|
itoken (tokens/generate sprops
|
||||||
|
{:iss :team-invitation
|
||||||
|
:exp (dt/in-future "48h")
|
||||||
|
:role :editor
|
||||||
|
:team-id uuid/zero
|
||||||
|
:member-email "user2@example.com"})
|
||||||
|
|
||||||
|
data {::th/type :prepare-register-profile
|
||||||
|
:invitation-token itoken
|
||||||
|
:email "user@example.com"
|
||||||
|
:password "foobar"}
|
||||||
|
out (th/command! data)]
|
||||||
|
|
||||||
|
(t/is (not (th/success? out)))
|
||||||
|
(let [edata (-> out :error ex-data)]
|
||||||
|
(t/is (= :restriction (:type edata)))
|
||||||
|
(t/is (= :email-does-not-match-invitation (:code edata))))))
|
||||||
|
|
||||||
|
(t/deftest prepare-and-register-with-invitation-and-disabled-registration-1
|
||||||
|
(with-redefs [app.config/flags [:disable-registration]]
|
||||||
|
(let [sprops (:app.setup/props th/*system*)
|
||||||
|
itoken (tokens/generate sprops
|
||||||
|
{:iss :team-invitation
|
||||||
|
:exp (dt/in-future "48h")
|
||||||
|
:role :editor
|
||||||
|
:team-id uuid/zero
|
||||||
|
:member-email "user@example.com"})
|
||||||
|
data {::th/type :prepare-register-profile
|
||||||
|
:invitation-token itoken
|
||||||
|
:email "user@example.com"
|
||||||
|
:password "foobar"}
|
||||||
|
out (th/command! data)]
|
||||||
|
|
||||||
|
(t/is (not (th/success? out)))
|
||||||
|
(let [edata (-> out :error ex-data)]
|
||||||
|
(t/is (= :restriction (:type edata)))
|
||||||
|
(t/is (= :registration-disabled (:code edata)))))))
|
||||||
|
|
||||||
(t/deftest prepare-and-register-with-invitation-and-disabled-registration-2
|
(t/deftest prepare-and-register-with-invitation-and-disabled-registration-2
|
||||||
(with-redefs [app.config/flags [:disable-registration]]
|
(with-redefs [app.config/flags [:disable-registration]]
|
||||||
|
@ -555,7 +593,28 @@
|
||||||
(t/is (not (th/success? out)))
|
(t/is (not (th/success? out)))
|
||||||
(let [edata (-> out :error ex-data)]
|
(let [edata (-> out :error ex-data)]
|
||||||
(t/is (= :restriction (:type edata)))
|
(t/is (= :restriction (:type edata)))
|
||||||
(t/is (= :email-does-not-match-invitation (:code edata)))))))
|
(t/is (= :registration-disabled (:code edata)))))))
|
||||||
|
|
||||||
|
(t/deftest prepare-and-register-with-invitation-and-disabled-login-with-password
|
||||||
|
(with-redefs [app.config/flags [:disable-login-with-password]]
|
||||||
|
(let [sprops (:app.setup/props th/*system*)
|
||||||
|
itoken (tokens/generate sprops
|
||||||
|
{:iss :team-invitation
|
||||||
|
:exp (dt/in-future "48h")
|
||||||
|
:role :editor
|
||||||
|
:team-id uuid/zero
|
||||||
|
:member-email "user2@example.com"})
|
||||||
|
|
||||||
|
data {::th/type :prepare-register-profile
|
||||||
|
:invitation-token itoken
|
||||||
|
:email "user@example.com"
|
||||||
|
:password "foobar"}
|
||||||
|
out (th/command! data)]
|
||||||
|
|
||||||
|
(t/is (not (th/success? out)))
|
||||||
|
(let [edata (-> out :error ex-data)]
|
||||||
|
(t/is (= :restriction (:type edata)))
|
||||||
|
(t/is (= :registration-disabled (:code edata)))))))
|
||||||
|
|
||||||
(t/deftest prepare-register-with-registration-disabled
|
(t/deftest prepare-register-with-registration-disabled
|
||||||
(with-redefs [app.config/flags #{}]
|
(with-redefs [app.config/flags #{}]
|
||||||
|
|
|
@ -125,3 +125,7 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- "10389:10389"
|
- "10389:10389"
|
||||||
- "10636:10636"
|
- "10636:10636"
|
||||||
|
ulimits:
|
||||||
|
nofile:
|
||||||
|
soft: "1024"
|
||||||
|
hard: "1024"
|
|
@ -38,7 +38,10 @@ http {
|
||||||
|
|
||||||
gzip_types text/plain text/css text/javascript application/javascript application/json application/transit+json;
|
gzip_types text/plain text/css text/javascript application/javascript application/json application/transit+json;
|
||||||
|
|
||||||
resolver $PENPOT_INTERNAL_RESOLVER;
|
proxy_buffer_size 16k;
|
||||||
|
proxy_busy_buffers_size 24k; # essentially, proxy_buffer_size + 2 small buffers of 4k
|
||||||
|
proxy_buffers 32 4k;
|
||||||
|
resolver $PENPOT_INTERNAL_RESOLVER ipv6=off;
|
||||||
|
|
||||||
map $http_upgrade $connection_upgrade {
|
map $http_upgrade $connection_upgrade {
|
||||||
default upgrade;
|
default upgrade;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
[app.main.data.websocket :as ws]
|
[app.main.data.websocket :as ws]
|
||||||
[app.main.features :as features]
|
[app.main.features :as features]
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[app.util.router :as rt]
|
[app.util.router :as rt]
|
||||||
[app.util.storage :refer [storage]]
|
[app.util.storage :refer [storage]]
|
||||||
|
@ -135,7 +136,8 @@
|
||||||
(swap! storage assoc :profile profile)
|
(swap! storage assoc :profile profile)
|
||||||
(i18n/set-locale! (:lang profile))
|
(i18n/set-locale! (:lang profile))
|
||||||
(when (not= previous-email email)
|
(when (not= previous-email email)
|
||||||
(set-current-team! nil)))))))
|
(set-current-team! nil))
|
||||||
|
(dom/set-html-theme-color (or (:theme profile) "default")))))))
|
||||||
|
|
||||||
(defn fetch-profile
|
(defn fetch-profile
|
||||||
[]
|
[]
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
[app.main.data.workspace.collapse :as dwco]
|
[app.main.data.workspace.collapse :as dwco]
|
||||||
[app.main.data.workspace.drawing :as dwd]
|
[app.main.data.workspace.drawing :as dwd]
|
||||||
[app.main.data.workspace.edition :as dwe]
|
[app.main.data.workspace.edition :as dwe]
|
||||||
[app.main.data.workspace.fix-bool-contents :as fbc]
|
|
||||||
[app.main.data.workspace.fix-broken-shapes :as fbs]
|
[app.main.data.workspace.fix-broken-shapes :as fbs]
|
||||||
[app.main.data.workspace.fix-deleted-fonts :as fdf]
|
[app.main.data.workspace.fix-deleted-fonts :as fdf]
|
||||||
[app.main.data.workspace.groups :as dwg]
|
[app.main.data.workspace.groups :as dwg]
|
||||||
|
@ -129,7 +128,6 @@
|
||||||
(when (and (not (boolean (-> state :profile :props :v2-info-shown)))
|
(when (and (not (boolean (-> state :profile :props :v2-info-shown)))
|
||||||
(features/active-feature? state "components/v2"))
|
(features/active-feature? state "components/v2"))
|
||||||
(modal/show :v2-info {}))
|
(modal/show :v2-info {}))
|
||||||
(fbc/fix-bool-contents)
|
|
||||||
(fdf/fix-deleted-fonts)
|
(fdf/fix-deleted-fonts)
|
||||||
(fbs/fix-broken-shapes)))))
|
(fbs/fix-broken-shapes)))))
|
||||||
|
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
;; 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.main.data.workspace.fix-bool-contents
|
|
||||||
(:require
|
|
||||||
[app.common.data :as d]
|
|
||||||
[app.common.geom.shapes :as gsh]
|
|
||||||
[app.main.data.changes :as dch]
|
|
||||||
[app.main.data.workspace.shapes :as dwsh]
|
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
|
||||||
[beicon.v2.core :as rx]
|
|
||||||
[potok.v2.core :as ptk]))
|
|
||||||
|
|
||||||
;; This event will update the file so the boolean data has a pre-generated path data
|
|
||||||
;; to increase performance.
|
|
||||||
;; For new shapes this will be generated in the :reg-objects but we need to do this for
|
|
||||||
;; old files.
|
|
||||||
|
|
||||||
;; FIXME: Remove me after June 2022
|
|
||||||
|
|
||||||
(defn fix-bool-contents
|
|
||||||
"This event will calculate the bool content and update the page. This is kind of a 'addhoc' migration
|
|
||||||
to fill the optional value 'bool-content'"
|
|
||||||
[]
|
|
||||||
|
|
||||||
(letfn [(should-migrate-shape? [shape]
|
|
||||||
(and (= :bool (:type shape)) (not (contains? shape :bool-content))))
|
|
||||||
|
|
||||||
(should-migrate-component? [component]
|
|
||||||
(->> (:objects component)
|
|
||||||
(vals)
|
|
||||||
(d/seek should-migrate-shape?)))
|
|
||||||
|
|
||||||
(update-shape [shape objects]
|
|
||||||
(cond-> shape
|
|
||||||
(should-migrate-shape? shape)
|
|
||||||
(assoc :bool-content (gsh/calc-bool-content shape objects))))
|
|
||||||
|
|
||||||
(migrate-component [component]
|
|
||||||
(-> component
|
|
||||||
(update
|
|
||||||
:objects
|
|
||||||
(fn [objects]
|
|
||||||
(d/mapm #(update-shape %2 objects) objects)))))
|
|
||||||
|
|
||||||
(update-library
|
|
||||||
[library]
|
|
||||||
(-> library
|
|
||||||
(d/update-in-when
|
|
||||||
[:data :components]
|
|
||||||
(fn [components]
|
|
||||||
(d/mapm #(migrate-component %2) components)))))]
|
|
||||||
|
|
||||||
(ptk/reify ::fix-bool-contents
|
|
||||||
ptk/UpdateEvent
|
|
||||||
(update [_ state]
|
|
||||||
;; Update (only-local) the imported libraries
|
|
||||||
(-> state
|
|
||||||
(d/update-when
|
|
||||||
:workspace-libraries
|
|
||||||
(fn [libraries] (d/mapm #(update-library %2) libraries)))))
|
|
||||||
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [it state _]
|
|
||||||
(let [objects (wsh/lookup-page-objects state)
|
|
||||||
|
|
||||||
ids (into #{}
|
|
||||||
(comp (filter should-migrate-shape?) (map :id))
|
|
||||||
(vals objects))
|
|
||||||
|
|
||||||
components (->> (wsh/lookup-local-components state)
|
|
||||||
(vals)
|
|
||||||
(filter should-migrate-component?))
|
|
||||||
|
|
||||||
component-changes
|
|
||||||
(into []
|
|
||||||
(map (fn [component]
|
|
||||||
{:type :mod-component
|
|
||||||
:id (:id component)
|
|
||||||
:objects (-> component migrate-component :objects)}))
|
|
||||||
components)]
|
|
||||||
|
|
||||||
(rx/of (dwsh/update-shapes ids #(update-shape % objects) {:reg-objects? false
|
|
||||||
:save-undo? false
|
|
||||||
:ignore-tree true}))
|
|
||||||
|
|
||||||
(if (empty? component-changes)
|
|
||||||
(rx/empty)
|
|
||||||
(rx/of (dch/commit-changes {:origin it
|
|
||||||
:redo-changes component-changes
|
|
||||||
:undo-changes []
|
|
||||||
:save-undo? false}))))))))
|
|
|
@ -6,11 +6,9 @@
|
||||||
|
|
||||||
(ns app.main.data.workspace.fix-deleted-fonts
|
(ns app.main.data.workspace.fix-deleted-fonts
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
|
||||||
[app.common.files.helpers :as cfh]
|
[app.common.files.helpers :as cfh]
|
||||||
[app.common.text :as txt]
|
[app.common.text :as txt]
|
||||||
[app.main.data.changes :as dwc]
|
[app.main.data.changes :as dwc]
|
||||||
[app.main.data.workspace.shapes :as dwsh]
|
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.main.fonts :as fonts]
|
[app.main.fonts :as fonts]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
|
@ -22,14 +20,7 @@
|
||||||
;; - Moving files from one team to another in the same instance
|
;; - Moving files from one team to another in the same instance
|
||||||
;; - Custom fonts are explicitly deleted in the team area
|
;; - Custom fonts are explicitly deleted in the team area
|
||||||
|
|
||||||
(defn has-invalid-font-family
|
(defn- calculate-alternative-font-id
|
||||||
[node]
|
|
||||||
(let [fonts (deref fonts/fontsdb)]
|
|
||||||
(and
|
|
||||||
(some? (:font-family node))
|
|
||||||
(nil? (get fonts (:font-id node))))))
|
|
||||||
|
|
||||||
(defn calculate-alternative-font-id
|
|
||||||
[value]
|
[value]
|
||||||
(let [fonts (deref fonts/fontsdb)]
|
(let [fonts (deref fonts/fontsdb)]
|
||||||
(->> (vals fonts)
|
(->> (vals fonts)
|
||||||
|
@ -37,39 +28,44 @@
|
||||||
(first)
|
(first)
|
||||||
:id)))
|
:id)))
|
||||||
|
|
||||||
(defn should-fix-deleted-font-shape?
|
(defn- has-invalid-font-family?
|
||||||
|
[node]
|
||||||
|
(let [fonts (deref fonts/fontsdb)
|
||||||
|
font-family (:font-family node)
|
||||||
|
alternative-font-id (calculate-alternative-font-id font-family)]
|
||||||
|
(and (some? font-family)
|
||||||
|
(nil? (get fonts (:font-id node)))
|
||||||
|
(some? alternative-font-id))))
|
||||||
|
|
||||||
|
(defn- should-fix-deleted-font-shape?
|
||||||
[shape]
|
[shape]
|
||||||
(let [text-nodes (txt/node-seq txt/is-text-node? (:content shape))]
|
(let [text-nodes (txt/node-seq txt/is-text-node? (:content shape))]
|
||||||
(and (cfh/text-shape? shape) (some has-invalid-font-family text-nodes))))
|
(and (cfh/text-shape? shape)
|
||||||
|
(some has-invalid-font-family? text-nodes))))
|
||||||
|
|
||||||
(defn should-fix-deleted-font-component?
|
(defn- should-fix-deleted-font-component?
|
||||||
[component]
|
[component]
|
||||||
(->> (:objects component)
|
(let [xf (comp (map val)
|
||||||
(vals)
|
(filter should-fix-deleted-font-shape?))]
|
||||||
(d/seek should-fix-deleted-font-shape?)))
|
(first (sequence xf (:objects component)))))
|
||||||
|
|
||||||
(defn should-fix-deleted-font-typography?
|
(defn- fix-deleted-font
|
||||||
[typography]
|
|
||||||
(let [fonts (deref fonts/fontsdb)]
|
|
||||||
(nil? (get fonts (:font-id typography)))))
|
|
||||||
|
|
||||||
(defn fix-deleted-font
|
|
||||||
[node]
|
[node]
|
||||||
(let [alternative-font-id (calculate-alternative-font-id (:font-family node))]
|
(let [alternative-font-id (calculate-alternative-font-id (:font-family node))]
|
||||||
(cond-> node
|
(cond-> node
|
||||||
(some? alternative-font-id) (assoc :font-id alternative-font-id))))
|
(some? alternative-font-id) (assoc :font-id alternative-font-id))))
|
||||||
|
|
||||||
(defn fix-deleted-font-shape
|
(defn- fix-deleted-font-shape
|
||||||
[shape]
|
[shape]
|
||||||
(let [transform (partial txt/transform-nodes has-invalid-font-family fix-deleted-font)]
|
(let [transform (partial txt/transform-nodes has-invalid-font-family? fix-deleted-font)]
|
||||||
(update shape :content transform)))
|
(update shape :content transform)))
|
||||||
|
|
||||||
(defn fix-deleted-font-component
|
(defn- fix-deleted-font-component
|
||||||
[component]
|
[component]
|
||||||
(update component
|
(update component
|
||||||
:objects
|
:objects
|
||||||
(fn [objects]
|
(fn [objects]
|
||||||
(d/mapm #(fix-deleted-font-shape %2) objects))))
|
(update-vals objects fix-deleted-font-shape))))
|
||||||
|
|
||||||
(defn fix-deleted-font-typography
|
(defn fix-deleted-font-typography
|
||||||
[typography]
|
[typography]
|
||||||
|
@ -77,54 +73,60 @@
|
||||||
(cond-> typography
|
(cond-> typography
|
||||||
(some? alternative-font-id) (assoc :font-id alternative-font-id))))
|
(some? alternative-font-id) (assoc :font-id alternative-font-id))))
|
||||||
|
|
||||||
|
(defn- generate-deleted-font-shape-changes
|
||||||
|
[{:keys [objects id]}]
|
||||||
|
(sequence
|
||||||
|
(comp (map val)
|
||||||
|
(filter should-fix-deleted-font-shape?)
|
||||||
|
(map (fn [shape]
|
||||||
|
{:type :mod-obj
|
||||||
|
:id (:id shape)
|
||||||
|
:page-id id
|
||||||
|
:operations [{:type :set
|
||||||
|
:attr :content
|
||||||
|
:val (:content (fix-deleted-font-shape shape))}
|
||||||
|
{:type :set
|
||||||
|
:attr :position-data
|
||||||
|
:val nil}]})))
|
||||||
|
objects))
|
||||||
|
|
||||||
|
(defn- generate-deleted-font-components-changes
|
||||||
|
[state]
|
||||||
|
(sequence
|
||||||
|
(comp (map val)
|
||||||
|
(filter should-fix-deleted-font-component?)
|
||||||
|
(map (fn [component]
|
||||||
|
{:type :mod-component
|
||||||
|
:id (:id component)
|
||||||
|
:objects (-> (fix-deleted-font-component component) :objects)})))
|
||||||
|
(wsh/lookup-local-components state)))
|
||||||
|
|
||||||
|
(defn- generate-deleted-font-typography-changes
|
||||||
|
[state]
|
||||||
|
(sequence
|
||||||
|
(comp (map val)
|
||||||
|
(filter has-invalid-font-family?)
|
||||||
|
(map (fn [typography]
|
||||||
|
{:type :mod-typography
|
||||||
|
:typography (fix-deleted-font-typography typography)})))
|
||||||
|
(get-in state [:workspace-data :typographies])))
|
||||||
|
|
||||||
(defn fix-deleted-fonts
|
(defn fix-deleted-fonts
|
||||||
[]
|
[]
|
||||||
(ptk/reify ::fix-deleted-fonts
|
(ptk/reify ::fix-deleted-fonts
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [it state _]
|
(watch [it state _]
|
||||||
(let [objects (wsh/lookup-page-objects state)
|
(let [data (get state :workspace-data)
|
||||||
|
shape-changes (mapcat generate-deleted-font-shape-changes (vals (:pages-index data)))
|
||||||
ids (into #{}
|
components-changes (generate-deleted-font-components-changes state)
|
||||||
(comp (filter should-fix-deleted-font-shape?) (map :id))
|
typography-changes (generate-deleted-font-typography-changes state)
|
||||||
(vals objects))
|
changes (concat shape-changes
|
||||||
|
components-changes
|
||||||
components (->> (wsh/lookup-local-components state)
|
typography-changes)]
|
||||||
(vals)
|
(if (seq changes)
|
||||||
(filter should-fix-deleted-font-component?))
|
(rx/of (dwc/commit-changes
|
||||||
|
{:origin it
|
||||||
component-changes
|
:redo-changes (vec changes)
|
||||||
(into []
|
|
||||||
(map (fn [component]
|
|
||||||
{:type :mod-component
|
|
||||||
:id (:id component)
|
|
||||||
:objects (-> (fix-deleted-font-component component) :objects)}))
|
|
||||||
components)
|
|
||||||
|
|
||||||
typographies (->> (get-in state [:workspace-data :typographies])
|
|
||||||
(vals)
|
|
||||||
(filter should-fix-deleted-font-typography?))
|
|
||||||
|
|
||||||
typography-changes
|
|
||||||
(into []
|
|
||||||
(map (fn [typography]
|
|
||||||
{:type :mod-typography
|
|
||||||
:typography (fix-deleted-font-typography typography)}))
|
|
||||||
typographies)]
|
|
||||||
|
|
||||||
(rx/concat
|
|
||||||
(rx/of (dwsh/update-shapes ids #(fix-deleted-font-shape %) {:reg-objects? false
|
|
||||||
:save-undo? false
|
|
||||||
:ignore-tree true}))
|
|
||||||
(if (empty? component-changes)
|
|
||||||
(rx/empty)
|
|
||||||
(rx/of (dwc/commit-changes {:origin it
|
|
||||||
:redo-changes component-changes
|
|
||||||
:undo-changes []
|
:undo-changes []
|
||||||
:save-undo? false})))
|
:save-undo? false}))
|
||||||
|
(rx/empty))))))
|
||||||
(if (empty? typography-changes)
|
|
||||||
(rx/empty)
|
|
||||||
(rx/of (dwc/commit-changes {:origin it
|
|
||||||
:redo-changes typography-changes
|
|
||||||
:undo-changes []
|
|
||||||
:save-undo? false}))))))))
|
|
||||||
|
|
|
@ -30,26 +30,27 @@
|
||||||
(not= section :auth-register-success))
|
(not= section :auth-register-success))
|
||||||
params (:query-params route)
|
params (:query-params route)
|
||||||
error (:error params)
|
error (:error params)
|
||||||
hide-image-auth? (cf/external-feature-flag "signup-01" "test")]
|
default-light? (cf/external-feature-flag "onboarding-02" "test")]
|
||||||
|
|
||||||
(mf/with-effect []
|
(mf/with-effect []
|
||||||
(dom/set-html-title (tr "title.default")))
|
(dom/set-html-title (tr "title.default")))
|
||||||
|
|
||||||
|
(mf/with-effect [default-light?]
|
||||||
|
(when default-light?
|
||||||
|
(dom/set-html-theme-color "light")))
|
||||||
|
|
||||||
(mf/with-effect [error]
|
(mf/with-effect [error]
|
||||||
(when error
|
(when error
|
||||||
(st/emit! (du/show-redirect-error error))))
|
(st/emit! (du/show-redirect-error error))))
|
||||||
|
|
||||||
[:main {:class (stl/css-case :auth-section (not hide-image-auth?)
|
[:main {:class (stl/css :auth-section)}
|
||||||
:auth-section-hide-image hide-image-auth?)}
|
|
||||||
(when show-login-icon
|
(when show-login-icon
|
||||||
[:h1 {:class (stl/css :logo-container)}
|
[:h1 {:class (stl/css :logo-container)}
|
||||||
[:a {:href "#/" :title "Penpot" :class (stl/css :logo-btn)} i/logo]])
|
[:a {:href "#/" :title "Penpot" :class (stl/css :logo-btn)} i/logo]])
|
||||||
(when (not hide-image-auth?)
|
|
||||||
[:div {:class (stl/css :login-illustration)}
|
[:div {:class (stl/css :login-illustration)}
|
||||||
i/login-illustration])
|
i/login-illustration]
|
||||||
|
|
||||||
[:section {:class (stl/css-case :auth-content (not hide-image-auth?)
|
[:section {:class (stl/css :auth-content)}
|
||||||
:auth-content-hide-image hide-image-auth?)}
|
|
||||||
|
|
||||||
(case section
|
(case section
|
||||||
:auth-register
|
:auth-register
|
||||||
|
|
|
@ -24,24 +24,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A-B text signup-01
|
|
||||||
.auth-section-hide-image {
|
|
||||||
position: relative;
|
|
||||||
align-items: center;
|
|
||||||
background: var(--panel-background-color);
|
|
||||||
display: grid;
|
|
||||||
gap: $s-32;
|
|
||||||
height: 100%;
|
|
||||||
padding: $s-32;
|
|
||||||
width: 100%;
|
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
@media (max-width: 992px) {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo-container {
|
.logo-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: $s-20;
|
top: $s-20;
|
||||||
|
@ -83,19 +65,6 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A-B text signup-01
|
|
||||||
.auth-content-hide-image {
|
|
||||||
display: grid;
|
|
||||||
grid-template-rows: 1fr auto;
|
|
||||||
gap: $s-24;
|
|
||||||
height: fit-content;
|
|
||||||
margin: auto;
|
|
||||||
max-width: $s-412;
|
|
||||||
padding-block-end: $s-8;
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo-btn {
|
.logo-btn {
|
||||||
svg {
|
svg {
|
||||||
width: $s-120;
|
width: $s-120;
|
||||||
|
|
|
@ -110,7 +110,8 @@
|
||||||
[:& login/login-buttons {:params params}])
|
[:& login/login-buttons {:params params}])
|
||||||
(when (or login/show-alt-login-buttons? (false? hide-separator))
|
(when (or login/show-alt-login-buttons? (false? hide-separator))
|
||||||
[:hr {:class (stl/css :separator)}])
|
[:hr {:class (stl/css :separator)}])
|
||||||
[:& register-form {:params params :on-success-callback on-success-callback}]])
|
(when (contains? cf/flags :login-with-password)
|
||||||
|
[:& register-form {:params params :on-success-callback on-success-callback}])])
|
||||||
|
|
||||||
(mf/defc register-page
|
(mf/defc register-page
|
||||||
{::mf/props :obj}
|
{::mf/props :obj}
|
||||||
|
@ -176,6 +177,7 @@
|
||||||
[{:keys [params on-success-callback]}]
|
[{:keys [params on-success-callback]}]
|
||||||
(let [form (fm/use-form :schema schema:register-validate-form :initial params)
|
(let [form (fm/use-form :schema schema:register-validate-form :initial params)
|
||||||
submitted? (mf/use-state false)
|
submitted? (mf/use-state false)
|
||||||
|
theme (when (cf/external-feature-flag "onboarding-02" "test") "light")
|
||||||
|
|
||||||
on-success
|
on-success
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
@ -207,7 +209,8 @@
|
||||||
(mf/deps on-success on-error)
|
(mf/deps on-success on-error)
|
||||||
(fn [form _]
|
(fn [form _]
|
||||||
(reset! submitted? true)
|
(reset! submitted? true)
|
||||||
(let [params (:clean-data @form)]
|
(let [params (cond-> (:clean-data @form)
|
||||||
|
(some? theme) (assoc :theme theme))]
|
||||||
(->> (rp/cmd! :register-profile params)
|
(->> (rp/cmd! :register-profile params)
|
||||||
(rx/finalize #(reset! submitted? false))
|
(rx/finalize #(reset! submitted? false))
|
||||||
(rx/subs! on-success on-error)))))]
|
(rx/subs! on-success on-error)))))]
|
||||||
|
|
|
@ -64,7 +64,8 @@
|
||||||
[{:keys [grow-type id migrate] :as shape} node]
|
[{:keys [grow-type id migrate] :as shape} node]
|
||||||
;; Check if we need to update the size because it's auto-width or auto-height
|
;; Check if we need to update the size because it's auto-width or auto-height
|
||||||
;; Update the position-data of every text fragment
|
;; Update the position-data of every text fragment
|
||||||
(p/let [position-data (tsp/calc-position-data id)]
|
(->> (tsp/calc-position-data id)
|
||||||
|
(p/fmap (fn [position-data]
|
||||||
;; At least one paragraph needs to be inside the bounding box
|
;; At least one paragraph needs to be inside the bounding box
|
||||||
(when (gsht/overlaps-position-data? shape position-data)
|
(when (gsht/overlaps-position-data? shape position-data)
|
||||||
(st/emit! (dwt/update-position-data id position-data)))
|
(st/emit! (dwt/update-position-data id position-data)))
|
||||||
|
@ -81,7 +82,7 @@
|
||||||
(not migrate))
|
(not migrate))
|
||||||
(st/emit! (dwt/resize-text id width height)))))
|
(st/emit! (dwt/resize-text id width height)))))
|
||||||
|
|
||||||
(st/emit! (dwt/clean-text-modifier id))))
|
(st/emit! (dwt/clean-text-modifier id))))))
|
||||||
|
|
||||||
(defn- update-text-modifier
|
(defn- update-text-modifier
|
||||||
[{:keys [grow-type id] :as shape} node]
|
[{:keys [grow-type id] :as shape} node]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue