0
Fork 0
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:
Andrey Antukh 2019-09-10 12:00:52 +02:00
parent faf7877d00
commit b1459f85cd
11 changed files with 136 additions and 150 deletions

View file

@ -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"))

View file

@ -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?

View file

@ -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))))))

View file

@ -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

View file

@ -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)))

View file

@ -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

View file

@ -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

View file

@ -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 ""))

View file

@ -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)

View file

@ -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}]

View file

@ -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? %))))