Builds client SSR approach, sunsets old cljs.
This commit is contained in:
@@ -16,51 +16,51 @@
|
||||
:headers (into {"Content-Type" "text/html"}
|
||||
headers)
|
||||
:body (str
|
||||
(hiccup/html
|
||||
{}
|
||||
hiccup)
|
||||
"\n"
|
||||
(str/join "\n"
|
||||
(map (fn [o]
|
||||
(hiccup/html
|
||||
{}
|
||||
o))
|
||||
oob)))})
|
||||
(hiccup/html
|
||||
{}
|
||||
hiccup)
|
||||
"\n"
|
||||
(str/join "\n"
|
||||
(map (fn [o]
|
||||
(hiccup/html
|
||||
{}
|
||||
o))
|
||||
oob)))})
|
||||
|
||||
(defn modal-response [hiccup & {:as opts}]
|
||||
(apply html-response
|
||||
(into
|
||||
[hiccup]
|
||||
(mapcat identity
|
||||
(-> opts
|
||||
(assoc-in [:headers "hx-trigger"] "modalopen")
|
||||
(assoc-in [:headers "hx-retarget"] "#modal-content")
|
||||
(assoc-in [:headers "hx-reswap"] "innerHTML"))))))
|
||||
(into
|
||||
[hiccup]
|
||||
(mapcat identity
|
||||
(-> opts
|
||||
(assoc-in [:headers "hx-trigger"] "modalopen")
|
||||
(assoc-in [:headers "hx-retarget"] "#modal-content")
|
||||
(assoc-in [:headers "hx-reswap"] "innerHTML"))))))
|
||||
|
||||
(defn next-step-modal-response [hiccup & {:as opts}]
|
||||
(apply html-response
|
||||
(into
|
||||
[hiccup]
|
||||
(mapcat identity
|
||||
(-> opts
|
||||
(assoc-in [:headers "hx-retarget"] "#modal-content")
|
||||
(assoc-in [:headers "hx-reswap"] "innerHTML"))))))
|
||||
(into
|
||||
[hiccup]
|
||||
(mapcat identity
|
||||
(-> opts
|
||||
(assoc-in [:headers "hx-retarget"] "#modal-content")
|
||||
(assoc-in [:headers "hx-reswap"] "innerHTML"))))))
|
||||
|
||||
|
||||
|
||||
(defn form-data->map [form-data]
|
||||
(reduce-kv
|
||||
(fn [acc k v]
|
||||
(cond (and (string? v)
|
||||
(empty? v))
|
||||
acc
|
||||
(fn [acc k v]
|
||||
(cond (and (string? v)
|
||||
(empty? v))
|
||||
acc
|
||||
|
||||
:else
|
||||
(assoc-in acc (->> (str/split k #"_")
|
||||
(mapv #(apply keyword (str/split % #"/"))))
|
||||
v)))
|
||||
{}
|
||||
form-data))
|
||||
:else
|
||||
(assoc-in acc (->> (str/split k #"_")
|
||||
(mapv #(apply keyword (str/split % #"/"))))
|
||||
v)))
|
||||
{}
|
||||
form-data))
|
||||
|
||||
(defn path->name [k]
|
||||
(cond (keyword? k)
|
||||
@@ -75,29 +75,32 @@
|
||||
[:vector {:decode/json {:enter (fn [x]
|
||||
(if (sequential? x)
|
||||
x
|
||||
[x])
|
||||
)}}
|
||||
[x]))}}
|
||||
x])
|
||||
|
||||
(defn empty->nil [v]
|
||||
(if (and (string? v) (clojure.string/blank? v))
|
||||
nil
|
||||
v))
|
||||
(if (and (string? v) (clojure.string/blank? v))
|
||||
nil
|
||||
v))
|
||||
|
||||
(defn parse-empty-as-nil []
|
||||
(mt2/transformer
|
||||
{:decoders
|
||||
{:string empty->nil
|
||||
:double empty->nil
|
||||
:int empty->nil
|
||||
:long empty->nil
|
||||
'nat-int? empty->nil}}))
|
||||
(defn parse-empty-as-nil []
|
||||
(mt2/transformer
|
||||
{:decoders
|
||||
{:map (fn [m]
|
||||
(if (not (seq (filter identity (vals m))))
|
||||
nil
|
||||
m))
|
||||
:string empty->nil
|
||||
:double empty->nil
|
||||
:int empty->nil
|
||||
:long empty->nil
|
||||
'nat-int? empty->nil}}))
|
||||
|
||||
(def entity-id (mc/schema [nat-int? {:error/message "required"
|
||||
:decode/arbitrary (fn [e]
|
||||
(if (and (map? e) (:db/id e))
|
||||
(:db/id e)
|
||||
e))} ]))
|
||||
:decode/arbitrary (fn [e]
|
||||
(if (and (map? e) (:db/id e))
|
||||
(:db/id e)
|
||||
e))}]))
|
||||
|
||||
(def temp-id (mc/schema [:string {:min 1}]))
|
||||
(def money (mc/schema [:double]))
|
||||
@@ -110,12 +113,12 @@
|
||||
|
||||
(def regex (mc/schema [:fn {:error/message "not a regex"}
|
||||
(fn check-regx [x]
|
||||
(try
|
||||
(and (string? x)
|
||||
(. java.util.regex.Pattern (compile x java.util.regex.Pattern/CASE_INSENSITIVE)))
|
||||
true
|
||||
(catch Exception _
|
||||
false)))]))
|
||||
(try
|
||||
(and (string? x)
|
||||
(. java.util.regex.Pattern (compile x java.util.regex.Pattern/CASE_INSENSITIVE)))
|
||||
true
|
||||
(catch Exception _
|
||||
false)))]))
|
||||
|
||||
(def map->db-id-decoder
|
||||
{:enter (fn [x]
|
||||
@@ -127,12 +130,12 @@
|
||||
|
||||
(defn many-entity [params & keys]
|
||||
(mc/schema
|
||||
[:vector (merge params {:decode/json map->db-id-decoder
|
||||
:decode/arbitrary (fn [x]
|
||||
(if (sequential? x)
|
||||
x
|
||||
[x]))})
|
||||
(into [:map] keys)]))
|
||||
[:vector (merge params {:decode/json map->db-id-decoder
|
||||
:decode/arbitrary (fn [x]
|
||||
(if (sequential? x)
|
||||
x
|
||||
[x]))})
|
||||
(into [:map] keys)]))
|
||||
|
||||
(defn str->keyword [s]
|
||||
(if (string? s)
|
||||
@@ -156,23 +159,38 @@
|
||||
:form-validation-errors [m]}))))
|
||||
|
||||
(def main-transformer
|
||||
(mt2/transformer
|
||||
parse-empty-as-nil
|
||||
(mt2/key-transformer {:encode keyword->str :decode str->keyword})
|
||||
mt2/string-transformer
|
||||
mt2/json-transformer
|
||||
(mt2/transformer {:name :arbitrary})
|
||||
mt2/default-value-transformer))
|
||||
(mt2/transformer
|
||||
parse-empty-as-nil
|
||||
(mt2/key-transformer {:encode keyword->str :decode str->keyword})
|
||||
mt2/string-transformer
|
||||
mt2/json-transformer
|
||||
(mt2/transformer {:name :arbitrary})
|
||||
mt2/default-value-transformer))
|
||||
|
||||
(defn strip [s]
|
||||
(cond (and (string? s) (str/blank? s))
|
||||
nil
|
||||
nil
|
||||
|
||||
(string? s)
|
||||
(str/trim s)
|
||||
(string? s)
|
||||
(str/trim s)
|
||||
|
||||
:else
|
||||
s))
|
||||
(defn assert-schema [schema entity]
|
||||
(when-not (mc/validate schema entity)
|
||||
(throw (ex-info #_(->> (-> (mc/explain schema entity)
|
||||
(me/humanize {:errors (assoc me/default-errors
|
||||
::mc/missing-key {:error/message {:en "required"}})}))
|
||||
(map (fn [[k v]]
|
||||
(str (if (keyword? k)
|
||||
(name k)
|
||||
k) ": " (str/join ", " v))))
|
||||
(str/join ", "))
|
||||
"validation failed"
|
||||
{:type :schema-validation
|
||||
:decoded entity
|
||||
:error {:explain (mc/explain schema entity)}}))))
|
||||
|
||||
:else
|
||||
s))
|
||||
|
||||
(defn schema-enforce-request [{:keys [form-params query-params params] :as request} & {:keys [form-schema query-schema route-schema params-schema]}]
|
||||
(let [request (try
|
||||
@@ -180,35 +198,35 @@
|
||||
(and (:params request) params-schema)
|
||||
(assoc :params
|
||||
(mc/coerce
|
||||
params-schema
|
||||
(:params request)
|
||||
main-transformer))
|
||||
params-schema
|
||||
(:params request)
|
||||
main-transformer))
|
||||
|
||||
(and (:route-params request) route-schema)
|
||||
(assoc :route-params
|
||||
(mc/coerce
|
||||
route-schema
|
||||
(:route-params request)
|
||||
main-transformer))
|
||||
route-schema
|
||||
(:route-params request)
|
||||
main-transformer))
|
||||
|
||||
(and form-schema form-params)
|
||||
(assoc :form-params
|
||||
(mc/coerce
|
||||
form-schema
|
||||
form-params
|
||||
main-transformer))
|
||||
form-schema
|
||||
form-params
|
||||
main-transformer))
|
||||
|
||||
(and query-schema query-params)
|
||||
(assoc :query-params
|
||||
(mc/coerce
|
||||
query-schema
|
||||
query-params
|
||||
main-transformer)))
|
||||
|
||||
query-schema
|
||||
query-params
|
||||
main-transformer)))
|
||||
|
||||
(catch Exception e
|
||||
(alog/warn ::validation-error :error e)
|
||||
(throw (ex-info (->> (-> e
|
||||
(ex-data )
|
||||
(ex-data)
|
||||
:data
|
||||
:explain
|
||||
(me/humanize {:errors (assoc me/default-errors
|
||||
@@ -237,30 +255,30 @@
|
||||
(and (:params request) params-schema)
|
||||
(assoc :params
|
||||
(mc/decode
|
||||
params-schema
|
||||
(:params request)
|
||||
main-transformer))
|
||||
params-schema
|
||||
(:params request)
|
||||
main-transformer))
|
||||
|
||||
(and (:route-params request) route-schema)
|
||||
(assoc :route-params
|
||||
(mc/decode
|
||||
route-schema
|
||||
(:route-params request)
|
||||
main-transformer))
|
||||
route-schema
|
||||
(:route-params request)
|
||||
main-transformer))
|
||||
|
||||
(and form-schema form-params)
|
||||
(assoc :form-params
|
||||
(mc/decode
|
||||
form-schema
|
||||
form-params
|
||||
main-transformer))
|
||||
form-schema
|
||||
form-params
|
||||
main-transformer))
|
||||
|
||||
(and query-schema query-params)
|
||||
(assoc :query-params
|
||||
(mc/decode
|
||||
query-schema
|
||||
query-params
|
||||
main-transformer)))]
|
||||
query-schema
|
||||
query-params
|
||||
main-transformer)))]
|
||||
request))
|
||||
|
||||
(defn wrap-schema-decode [handler & {:keys [form-schema query-schema route-schema params-schema]}]
|
||||
@@ -275,8 +293,7 @@
|
||||
(into [:enum {:decode/string #(if (keyword? %)
|
||||
%
|
||||
(when (not-empty %)
|
||||
(keyword n %))
|
||||
)}]
|
||||
(keyword n %)))}]
|
||||
(for [{:db/keys [ident]} (all-schema)
|
||||
:when (= n (namespace ident))]
|
||||
ident)))
|
||||
@@ -301,41 +318,39 @@
|
||||
(defn wrap-form-4xx-2 [handler form-handler]
|
||||
(fn [request]
|
||||
(try+
|
||||
(handler request)
|
||||
(catch [:type :schema-validation] e
|
||||
|
||||
(let [humanized (-> e :error :explain (me/humanize {:errors (assoc me/default-errors
|
||||
::mc/missing-key {:error/message {:en "required"}})}))
|
||||
errors (map
|
||||
(fn [e]
|
||||
{:path (:in e)
|
||||
:message (get-in humanized (:in e))})
|
||||
(:errors (:explain (:error e))))]
|
||||
(alog/warn ::form-4xx :errors errors)
|
||||
(form-handler (assoc request
|
||||
:form-params (:decoded e)
|
||||
:field-validation-errors errors
|
||||
:form-errors humanized)))
|
||||
#_(html-response [:span.error-content.text-red-500 (:message &throw-context)]
|
||||
:status 400))
|
||||
(catch [:type :field-validation] e
|
||||
(form-handler (assoc request
|
||||
:form-params (:form e)
|
||||
:form-errors (:form-errors e))))
|
||||
(catch [:type :form-validation] e
|
||||
(form-handler (assoc request
|
||||
:form-params (:form e)
|
||||
:form-validation-errors (:form-validation-errors e)
|
||||
:form-errors {:errors (:form-validation-errors e)}))))))
|
||||
(handler request)
|
||||
(catch [:type :schema-validation] e
|
||||
(let [humanized (-> e :error :explain (me/humanize {:errors (assoc me/default-errors
|
||||
::mc/missing-key {:error/message {:en "required"}})}))
|
||||
errors (map
|
||||
(fn [e]
|
||||
{:path (:in e)
|
||||
:message (get-in humanized (:in e))})
|
||||
(:errors (:explain (:error e))))]
|
||||
(alog/warn ::form-4xx :errors errors)
|
||||
(form-handler (assoc request
|
||||
:form-params (:decoded e)
|
||||
:field-validation-errors errors
|
||||
:form-errors humanized)))
|
||||
#_(html-response [:span.error-content.text-red-500 (:message &throw-context)]
|
||||
:status 400))
|
||||
(catch [:type :field-validation] e
|
||||
(form-handler (assoc request
|
||||
:form-params (:form e)
|
||||
:form-errors (:form-errors e))))
|
||||
(catch [:type :form-validation] e
|
||||
(form-handler (assoc request
|
||||
:form-params (:form e)
|
||||
:form-validation-errors (:form-validation-errors e)
|
||||
:form-errors {:errors (:form-validation-errors e)}))))))
|
||||
|
||||
|
||||
(defn apply-middleware-to-all-handlers [key->handler f]
|
||||
(->> key->handler
|
||||
(reduce
|
||||
(fn [key-handler [k v]]
|
||||
(assoc key-handler k (f v)))
|
||||
key->handler)
|
||||
))
|
||||
(fn [key-handler [k v]]
|
||||
(assoc key-handler k (f v)))
|
||||
key->handler)))
|
||||
|
||||
(defn path->name2 [k & rest]
|
||||
(let [k->n (fn [k]
|
||||
@@ -354,10 +369,10 @@
|
||||
(defn wrap-entity [handler path read]
|
||||
(fn wrap-entity-request [request]
|
||||
(let [entity (some->>
|
||||
(get-in request path)
|
||||
(#(if (string? %) (Long/parseLong %) %))
|
||||
(dc/pull (dc/db conn) read ))]
|
||||
(get-in request path)
|
||||
(#(if (string? %) (Long/parseLong %) %))
|
||||
(dc/pull (dc/db conn) read))]
|
||||
(handler (if entity
|
||||
(assoc request
|
||||
:entity entity)
|
||||
request)))))
|
||||
request)))))
|
||||
Reference in New Issue
Block a user