mirror of
https://github.com/penpot/penpot.git
synced 2025-03-13 16:21:57 -05:00
🚧 More work on data validation.
This commit is contained in:
parent
faf7877d00
commit
b1459f85cd
11 changed files with 136 additions and 150 deletions
|
@ -67,7 +67,7 @@
|
|||
(add-watch html-history/path ::main #(on-navigate router %4))
|
||||
|
||||
(when (:auth storage)
|
||||
(st/emit! (udu/fetch-profile)))
|
||||
(st/emit! udu/fetch-profile))
|
||||
|
||||
(mf/mount (mf/element ui/app) (dom/get-element "app"))
|
||||
(mf/mount (lightbox) (dom/get-element "lightbox"))
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
|
||||
;; --- Logged In
|
||||
|
||||
;; TODO: add spec
|
||||
|
||||
(defn logged-in
|
||||
[data]
|
||||
(reify
|
||||
|
@ -40,7 +38,7 @@
|
|||
ptk/WatchEvent
|
||||
(watch [this state s]
|
||||
(swap! storage assoc :auth data)
|
||||
(rx/of (du/fetch-profile)
|
||||
(rx/of du/fetch-profile
|
||||
(rt/navigate :dashboard/projects)))))
|
||||
|
||||
(defn logged-in?
|
||||
|
|
|
@ -139,46 +139,44 @@
|
|||
[state id]
|
||||
(update state :packed-pages dissoc id))
|
||||
|
||||
|
||||
|
||||
;; --- Pages Fetched
|
||||
|
||||
(deftype PagesFetched [id pages]
|
||||
IDeref
|
||||
(-deref [_] (list id pages))
|
||||
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [get-order #(get-in % [:metadata :order])
|
||||
pages (sort-by get-order pages)
|
||||
page-ids (into [] (map :id) pages)]
|
||||
(as-> state $
|
||||
(assoc-in $ [:projects id :pages] page-ids)
|
||||
(reduce unpack-page $ pages)
|
||||
(reduce assoc-packed-page $ pages)))))
|
||||
|
||||
(defn pages-fetched
|
||||
[id pages]
|
||||
{:pre [(uuid? id) (coll? pages)]}
|
||||
(PagesFetched. id pages))
|
||||
(s/assert ::us/uuid id)
|
||||
(s/assert ::us/coll pages)
|
||||
(reify
|
||||
IDeref
|
||||
(-deref [_] (list id pages))
|
||||
|
||||
ptk/EventType
|
||||
(type [_] ::page-fetched)
|
||||
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [get-order #(get-in % [:metadata :order])
|
||||
pages (sort-by get-order pages)
|
||||
page-ids (into [] (map :id) pages)]
|
||||
(as-> state $
|
||||
(assoc-in $ [:projects id :pages] page-ids)
|
||||
(reduce unpack-page $ pages)
|
||||
(reduce assoc-packed-page $ pages))))))
|
||||
|
||||
(defn pages-fetched?
|
||||
[v]
|
||||
(instance? PagesFetched v))
|
||||
(= ::page-fetched (ptk/type v)))
|
||||
|
||||
;; --- Fetch Pages (by project id)
|
||||
|
||||
(deftype FetchPages [id]
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/req :fetch/pages-by-project {:project id})
|
||||
(rx/map :payload)
|
||||
(rx/map #(pages-fetched id %)))))
|
||||
|
||||
(defn fetch-pages
|
||||
[id]
|
||||
{:pre [(uuid? id)]}
|
||||
(FetchPages. id))
|
||||
(s/assert ::us/uuid id)
|
||||
(reify
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/req :fetch/pages-by-project {:project id})
|
||||
(rx/map :payload)
|
||||
(rx/map #(pages-fetched id %))))))
|
||||
|
||||
;; --- Page Created
|
||||
|
||||
|
@ -189,7 +187,7 @@
|
|||
|
||||
(defn page-created
|
||||
[data]
|
||||
(s/assert ::page-created-event data)
|
||||
(s/assert ::page-created-params data)
|
||||
(reify
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
|
@ -203,14 +201,14 @@
|
|||
(watch [_ state stream]
|
||||
(rx/of (rehash-pages (:project data))))))
|
||||
|
||||
;; --- Create Page
|
||||
;; --- Create Page Form
|
||||
|
||||
(s/def ::created-page-params
|
||||
(s/def ::form-created-page-params
|
||||
(s/keys :req-un [::name ::project ::width ::height]))
|
||||
|
||||
(defn create-page
|
||||
(defn form->create-page
|
||||
[{:keys [name project width height layout] :as data}]
|
||||
(s/assert ::created-page-params data)
|
||||
(s/assert ::form-created-page-params data)
|
||||
(reify
|
||||
ptk/WatchEvent
|
||||
(watch [this state s]
|
||||
|
@ -232,6 +230,25 @@
|
|||
(rx/map :payload)
|
||||
(rx/map page-created))))))
|
||||
|
||||
;; --- Update Page Form
|
||||
|
||||
(s/def ::form-update-page-params
|
||||
(s/keys :req-un [::id ::name ::width ::height]))
|
||||
|
||||
(defn form->update-page
|
||||
[{:keys [id name width height] :as data}]
|
||||
(s/assert ::form-update-page-params data)
|
||||
(reify
|
||||
IPageUpdate
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:pages id]
|
||||
(fn [page]
|
||||
(-> (assoc page :name name)
|
||||
(assoc-in [:name] name)
|
||||
(assoc-in [:metadata :width] width)
|
||||
(assoc-in [:metadata :height] height)))))))
|
||||
|
||||
;; --- Page Persisted
|
||||
|
||||
(defn page-persisted
|
||||
|
@ -321,10 +338,9 @@
|
|||
|
||||
;; --- Update Page
|
||||
|
||||
(defn update-page
|
||||
[id data]
|
||||
(defn update-page-attrs
|
||||
[{:keys [id] :as data}]
|
||||
(s/assert ::page-entity data)
|
||||
(s/assert ::id id)
|
||||
(reify
|
||||
IPageUpdate
|
||||
ptk/UpdateEvent
|
||||
|
@ -381,27 +397,6 @@
|
|||
pages (vec (concat before [page-id] after))]
|
||||
(assoc-in state [:projects project-id :pages] pages)))))
|
||||
|
||||
;; --- Persist Page Form
|
||||
;;
|
||||
;; A specialized event for persist data
|
||||
;; from the update page form.
|
||||
|
||||
(s/def ::persist-page-update-form-params
|
||||
(s/keys :req-un [::id ::name ::width ::height]))
|
||||
|
||||
(defn persist-page-update-form
|
||||
[{:keys [id name width height] :as data}]
|
||||
(s/assert ::persist-page-update-form-params data)
|
||||
(reify
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:pages id]
|
||||
(fn [page]
|
||||
(-> (assoc page :name name)
|
||||
(assoc-in [:name] name)
|
||||
(assoc-in [:metadata :width] width)
|
||||
(assoc-in [:metadata :height] height)))))))
|
||||
|
||||
;; --- Delete Page (by id)
|
||||
|
||||
(defn delete-page
|
||||
|
@ -419,31 +414,28 @@
|
|||
|
||||
;; --- Watch Page Changes
|
||||
|
||||
(deftype WatchPageChanges [id]
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [stopper (->> stream
|
||||
(rx/filter #(= % ::stop-page-watcher))
|
||||
(rx/take 1))]
|
||||
(rx/merge
|
||||
(->> stream
|
||||
(rx/filter #(or (satisfies? IPageUpdate %)
|
||||
(= ::page-update %)))
|
||||
(rx/take-until stopper)
|
||||
(rx/debounce 1000)
|
||||
(rx/mapcat #(rx/merge (rx/of (persist-page id))
|
||||
(->> (rx/filter page-persisted? stream)
|
||||
(rx/take 1)
|
||||
(rx/ignore)))))
|
||||
(->> stream
|
||||
(rx/filter #(satisfies? IMetadataUpdate %))
|
||||
(rx/take-until stopper)
|
||||
(rx/debounce 1000)
|
||||
(rx/mapcat #(rx/merge (rx/of (persist-metadata id))
|
||||
(->> (rx/filter metadata-persisted? stream)
|
||||
(rx/take 1)
|
||||
(rx/ignore)))))))))
|
||||
|
||||
(defn watch-page-changes
|
||||
[id]
|
||||
(WatchPageChanges. id))
|
||||
(s/assert ::us/uuid id)
|
||||
(reify
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [stopper (rx/filter #(= % ::stop-page-watcher) stream)]
|
||||
(->> (rx/merge
|
||||
(->> stream
|
||||
(rx/filter #(or (satisfies? IPageUpdate %)
|
||||
(= ::page-update %)))
|
||||
(rx/debounce 1000)
|
||||
(rx/mapcat #(rx/merge (rx/of (persist-page id))
|
||||
(->> (rx/filter page-persisted? stream)
|
||||
(rx/take 1)
|
||||
(rx/ignore)))))
|
||||
(->> stream
|
||||
(rx/filter #(satisfies? IMetadataUpdate %))
|
||||
(rx/debounce 1000)
|
||||
(rx/mapcat #(rx/merge (rx/of (persist-metadata id))
|
||||
(->> (rx/filter metadata-persisted? stream)
|
||||
(rx/take 1)
|
||||
(rx/ignore))))))
|
||||
(rx/take-until stopper))))))
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@
|
|||
(rx/map :payload)
|
||||
(rx/mapcat (fn [{:keys [id] :as project}]
|
||||
(rx/of #(assoc-project % project)
|
||||
(udp/create-page (assoc params :project id)))))))))
|
||||
(udp/form->create-page (assoc params :project id)))))))))
|
||||
|
||||
;; --- Go To Project
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
|
||||
;; Copyright (c) 2016-2019 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.main.data.users
|
||||
(:require
|
||||
|
@ -15,62 +15,64 @@
|
|||
[uxbox.util.spec :as us]
|
||||
[uxbox.util.storage :refer [storage]]))
|
||||
|
||||
;; --- Common Specs
|
||||
|
||||
(s/def ::id uuid?)
|
||||
(s/def ::username string?)
|
||||
(s/def ::fullname string?)
|
||||
(s/def ::email ::us/email)
|
||||
(s/def ::password string?)
|
||||
(s/def ::language string?)
|
||||
(s/def ::photo string?)
|
||||
(s/def ::created-at inst?)
|
||||
(s/def ::password-1 string?)
|
||||
(s/def ::password-2 string?)
|
||||
(s/def ::password-old string?)
|
||||
|
||||
;; --- Profile Fetched
|
||||
|
||||
(s/def ::profile-fetched-params
|
||||
(s/keys :req-un [::id
|
||||
::username
|
||||
::fullname
|
||||
::email
|
||||
::created-at
|
||||
::photo]))
|
||||
|
||||
(defn profile-fetched
|
||||
[data]
|
||||
(s/assert ::profile-fetched-params data)
|
||||
(reify
|
||||
ptk/UpdateEvent
|
||||
(update [this state]
|
||||
(update [_ state]
|
||||
(assoc state :profile data))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [this state stream]
|
||||
(effect [_ state stream]
|
||||
(swap! storage assoc :profile data)
|
||||
;; (prn "profile-fetched" data)
|
||||
(when-let [lang (get-in data [:metadata :language])]
|
||||
(i18n/set-current-locale! lang)))))
|
||||
|
||||
;; --- Fetch Profile
|
||||
|
||||
(deftype FetchProfile []
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/req :fetch/profile)
|
||||
(rx/map :payload)
|
||||
(rx/map profile-fetched))))
|
||||
|
||||
(defn fetch-profile
|
||||
[]
|
||||
(FetchProfile.))
|
||||
|
||||
;; --- Profile Updated
|
||||
|
||||
(deftype ProfileUpdated [data]
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(rx/of (profile-fetched data)
|
||||
(uum/info (tr "settings.profile.profile-saved")))))
|
||||
|
||||
(defn profile-updated
|
||||
[data]
|
||||
(ProfileUpdated. data))
|
||||
(def fetch-profile
|
||||
(reify
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/req :fetch/profile)
|
||||
(rx/map :payload)
|
||||
(rx/map profile-fetched)))))
|
||||
|
||||
;; --- Update Profile
|
||||
|
||||
(s/def ::fullname string?)
|
||||
(s/def ::email ::us/email)
|
||||
(s/def ::password string?)
|
||||
(s/def ::language string?)
|
||||
|
||||
(s/def ::update-profile-params
|
||||
(s/keys :req-un [::fullname
|
||||
::email
|
||||
::username
|
||||
::language]))
|
||||
|
||||
(defn update-profile
|
||||
[data {:keys [on-success on-error]}]
|
||||
(defn form->update-profile
|
||||
[data on-success on-error]
|
||||
(s/assert ::update-profile-params data)
|
||||
(s/assert ::us/fn on-error)
|
||||
(s/assert ::us/fn on-success)
|
||||
|
@ -88,16 +90,11 @@
|
|||
(->> (rp/req :update/profile data)
|
||||
(rx/map :payload)
|
||||
(rx/do on-success)
|
||||
(rx/map profile-updated)
|
||||
;; (rx/map profile-fetched)
|
||||
(rx/map profile-fetched)
|
||||
(rx/catch rp/client-error? handle-error)))))))
|
||||
|
||||
;; --- Update Password (Form)
|
||||
|
||||
(s/def ::password-1 string?)
|
||||
(s/def ::password-2 string?)
|
||||
(s/def ::password-old string?)
|
||||
|
||||
(s/def ::update-password-params
|
||||
(s/keys :req-un [::password-1
|
||||
::password-2
|
||||
|
@ -128,7 +125,7 @@
|
|||
(watch [_ state stream]
|
||||
(->> (rp/req :update/profile-photo {:file file})
|
||||
(rx/do done)
|
||||
(rx/map fetch-profile))))
|
||||
(rx/map (constantly fetch-profile)))))
|
||||
|
||||
(defn update-photo
|
||||
([file] (update-photo file (constantly nil)))
|
||||
|
|
|
@ -7,20 +7,21 @@
|
|||
|
||||
(ns uxbox.main.ui.auth.login
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[cljs.spec.alpha :as s]
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.config :as cfg]
|
||||
[uxbox.main.data.auth :as da]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.messages :refer [messages-widget]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.forms :as fm2]
|
||||
[uxbox.util.forms :as fm]
|
||||
[uxbox.util.i18n :refer [tr]]
|
||||
[uxbox.util.router :as rt]))
|
||||
[uxbox.util.router :as rt]
|
||||
[uxbox.util.spec :as us]))
|
||||
|
||||
(s/def ::username ::fm2/not-empty-string)
|
||||
(s/def ::password ::fm2/not-empty-string)
|
||||
(s/def ::username ::us/not-empty-string)
|
||||
(s/def ::password ::us/not-empty-string)
|
||||
|
||||
(s/def ::login-form
|
||||
(s/keys :req-un [::username ::password]))
|
||||
|
@ -44,8 +45,7 @@
|
|||
|
||||
(mf/defc login-form
|
||||
[]
|
||||
(let [{:keys [data] :as form} (fm2/use-form ::login-form {})]
|
||||
(prn "login-form" form)
|
||||
(let [{:keys [data] :as form} (fm/use-form ::login-form {})]
|
||||
[:form {:on-submit #(on-submit % form)}
|
||||
[:div.login-content
|
||||
(when cfg/isdemo
|
||||
|
@ -55,18 +55,18 @@
|
|||
{:name "username"
|
||||
:tab-index "2"
|
||||
:value (:username data "")
|
||||
:class (fm2/error-class form :username)
|
||||
:on-blur (fm2/on-input-blur form :username)
|
||||
:on-change (fm2/on-input-change form :username)
|
||||
:class (fm/error-class form :username)
|
||||
:on-blur (fm/on-input-blur form :username)
|
||||
:on-change (fm/on-input-change form :username)
|
||||
:placeholder (tr "auth.email-or-username")
|
||||
:type "text"}]
|
||||
[:input.input-text
|
||||
{:name "password"
|
||||
:tab-index "3"
|
||||
:value (:password data "")
|
||||
:class (fm2/error-class form :password)
|
||||
:on-blur (fm2/on-input-blur form :password)
|
||||
:on-change (fm2/on-input-change form :password)
|
||||
:class (fm/error-class form :password)
|
||||
:on-blur (fm/on-input-blur form :password)
|
||||
:on-change (fm/on-input-change form :password)
|
||||
:placeholder (tr "auth.password")
|
||||
:type "password"}]
|
||||
[:input.btn-primary
|
||||
|
|
|
@ -66,10 +66,8 @@
|
|||
(dom/prevent-default event)
|
||||
(let [data (:clean-data form)
|
||||
on-success #(st/emit! (um/info (tr "settings.profile.profile-saved")))
|
||||
on-error #(on-error % form)
|
||||
opts {:on-success on-success
|
||||
:on-error on-error}]
|
||||
(st/emit! (udu/update-profile data opts))))
|
||||
on-error #(on-error % form)]
|
||||
(st/emit! (udu/form->update-profile data on-success on-error))))
|
||||
|
||||
;; --- Profile Form
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
(l/derive st/state)))
|
||||
|
||||
(mf/defc user
|
||||
[_]
|
||||
[props]
|
||||
(let [open (mf/use-state false)
|
||||
profile (mf/deref profile-ref)
|
||||
photo (if (str/empty? (:photo profile ""))
|
||||
|
|
|
@ -43,8 +43,8 @@
|
|||
(on-name-change [event]
|
||||
(let [value (-> (dom/event->value event)
|
||||
(str/trim))]
|
||||
(st/emit! (->> (assoc page :name value)
|
||||
(udp/update-page (:id page))))))
|
||||
(st/emit! (-> (assoc page :name value)
|
||||
(udp/update-page-attrs)))))
|
||||
|
||||
(show-color-picker [event]
|
||||
(let [x (.-clientX event)
|
||||
|
|
|
@ -43,8 +43,8 @@
|
|||
(modal/hide!)
|
||||
(let [data (:clean-data form)]
|
||||
(if (nil? (:id data))
|
||||
(st/emit! (udp/create-page data))
|
||||
(st/emit! (udp/persist-page-update-form data)))))
|
||||
(st/emit! (udp/form->create-page data))
|
||||
(st/emit! (udp/form->update-page data)))))
|
||||
|
||||
(defn- swap-size
|
||||
[event {:keys [data] :as form}]
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
(s/def ::inst inst?)
|
||||
(s/def ::keyword keyword?)
|
||||
(s/def ::fn fn?)
|
||||
(s/def ::coll coll?)
|
||||
|
||||
(s/def ::not-empty-string
|
||||
(s/and string? #(not (str/empty? %))))
|
||||
|
|
Loading…
Add table
Reference in a new issue