mirror of
https://github.com/penpot/penpot.git
synced 2025-12-23 22:48:40 -05:00
♻️ Refactor time related namespaces
Mainly removes the custom app.util.time namespace from frontend and backend and normalize all to use the app.common.time namespace
This commit is contained in:
@@ -45,10 +45,16 @@
|
|||||||
:potok/reify-type
|
:potok/reify-type
|
||||||
{:level :error}
|
{:level :error}
|
||||||
|
|
||||||
|
:missing-protocol-method
|
||||||
|
{:level :off}
|
||||||
|
|
||||||
:unresolved-namespace
|
:unresolved-namespace
|
||||||
{:level :warning
|
{:level :warning
|
||||||
:exclude [data_readers]}
|
:exclude [data_readers]}
|
||||||
|
|
||||||
|
:unused-value
|
||||||
|
{:level :off}
|
||||||
|
|
||||||
:single-key-in
|
:single-key-in
|
||||||
{:level :warning}
|
{:level :warning}
|
||||||
|
|
||||||
@@ -64,6 +70,9 @@
|
|||||||
:redundant-nested-call
|
:redundant-nested-call
|
||||||
{:level :off}
|
{:level :off}
|
||||||
|
|
||||||
|
:redundant-str-call
|
||||||
|
{:level :off}
|
||||||
|
|
||||||
:earmuffed-var-not-dynamic
|
:earmuffed-var-not-dynamic
|
||||||
{:level :off}
|
{:level :off}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
[app.srepl.helpers :as srepl.helpers]
|
[app.srepl.helpers :as srepl.helpers]
|
||||||
[app.srepl.main :as srepl]
|
[app.srepl.main :as srepl]
|
||||||
[app.util.blob :as blob]
|
[app.util.blob :as blob]
|
||||||
[app.util.time :as dt]
|
[app.common.time :as ct]
|
||||||
[clj-async-profiler.core :as prof]
|
[clj-async-profiler.core :as prof]
|
||||||
[clojure.contrib.humanize :as hum]
|
[clojure.contrib.humanize :as hum]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uri :as u]
|
[app.common.uri :as u]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -28,7 +29,6 @@
|
|||||||
[app.tokens :as tokens]
|
[app.tokens :as tokens]
|
||||||
[app.util.inet :as inet]
|
[app.util.inet :as inet]
|
||||||
[app.util.json :as json]
|
[app.util.json :as json]
|
||||||
[app.util.time :as dt]
|
|
||||||
[buddy.sign.jwk :as jwk]
|
[buddy.sign.jwk :as jwk]
|
||||||
[buddy.sign.jwt :as jwt]
|
[buddy.sign.jwt :as jwt]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
@@ -514,7 +514,7 @@
|
|||||||
[cfg info request]
|
[cfg info request]
|
||||||
(let [info (assoc info
|
(let [info (assoc info
|
||||||
:iss :prepared-register
|
:iss :prepared-register
|
||||||
:exp (dt/in-future {:hours 48}))
|
:exp (ct/in-future {:hours 48}))
|
||||||
|
|
||||||
params {:token (tokens/generate (::setup/props cfg) info)
|
params {:token (tokens/generate (::setup/props cfg) info)
|
||||||
:provider (:provider (:path-params request))
|
:provider (:provider (:path-params request))
|
||||||
@@ -571,7 +571,7 @@
|
|||||||
token (or (:invitation-token info)
|
token (or (:invitation-token info)
|
||||||
(tokens/generate (::setup/props cfg)
|
(tokens/generate (::setup/props cfg)
|
||||||
{:iss :auth
|
{:iss :auth
|
||||||
:exp (dt/in-future "15m")
|
:exp (ct/in-future "15m")
|
||||||
:profile-id (:id profile)}))
|
:profile-id (:id profile)}))
|
||||||
props (audit/profile->props profile)
|
props (audit/profile->props profile)
|
||||||
context (d/without-nils {:external-session-id (:external-session-id info)})]
|
context (d/without-nils {:external-session-id (:external-session-id info)})]
|
||||||
@@ -619,7 +619,7 @@
|
|||||||
:invitation-token (:invitation-token params)
|
:invitation-token (:invitation-token params)
|
||||||
:external-session-id esid
|
:external-session-id esid
|
||||||
:props props
|
:props props
|
||||||
:exp (dt/in-future "4h")}
|
:exp (ct/in-future "4h")}
|
||||||
state (tokens/generate (::setup/props cfg)
|
state (tokens/generate (::setup/props cfg)
|
||||||
(d/without-nils params))
|
(d/without-nils params))
|
||||||
uri (build-auth-uri cfg state)]
|
uri (build-auth-uri cfg state)]
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
[app.common.files.validate :as fval]
|
[app.common.files.validate :as fval]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.file :as ctf]
|
[app.common.types.file :as ctf]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
@@ -28,7 +29,6 @@
|
|||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.util.blob :as blob]
|
[app.util.blob :as blob]
|
||||||
[app.util.pointer-map :as pmap]
|
[app.util.pointer-map :as pmap]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as-alias wrk]
|
[app.worker :as-alias wrk]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
@@ -540,14 +540,13 @@
|
|||||||
|
|
||||||
Returns nil"
|
Returns nil"
|
||||||
[{:keys [::timestamp] :as cfg} file & {:as opts}]
|
[{:keys [::timestamp] :as cfg} file & {:as opts}]
|
||||||
|
(assert (ct/inst? timestamp) "expected valid timestamp")
|
||||||
|
|
||||||
(assert (dt/instant? timestamp) "expected valid timestamp")
|
|
||||||
(let [file (-> file
|
(let [file (-> file
|
||||||
(assoc :created-at timestamp)
|
(assoc :created-at timestamp)
|
||||||
(assoc :modified-at timestamp)
|
(assoc :modified-at timestamp)
|
||||||
(cond-> (not (::overwrite cfg))
|
(cond-> (not (::overwrite cfg))
|
||||||
(assoc :ignore-sync-until (dt/plus timestamp (dt/duration {:seconds 5}))))
|
(assoc :ignore-sync-until (ct/plus timestamp (ct/duration {:seconds 5}))))
|
||||||
(update :revn inc)
|
|
||||||
(update :features
|
(update :features
|
||||||
(fn [features]
|
(fn [features]
|
||||||
(-> (::features cfg #{})
|
(-> (::features cfg #{})
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
[app.common.fressian :as fres]
|
[app.common.fressian :as fres]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.file :as ctf]
|
[app.common.types.file :as ctf]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
@@ -30,7 +31,6 @@
|
|||||||
[app.storage.tmp :as tmp]
|
[app.storage.tmp :as tmp]
|
||||||
[app.tasks.file-gc]
|
[app.tasks.file-gc]
|
||||||
[app.util.events :as events]
|
[app.util.events :as events]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as-alias wrk]
|
[app.worker :as-alias wrk]
|
||||||
[clojure.java.io :as jio]
|
[clojure.java.io :as jio]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
@@ -434,7 +434,7 @@
|
|||||||
(defn read-import!
|
(defn read-import!
|
||||||
"Do the importation of the specified resource in penpot custom binary
|
"Do the importation of the specified resource in penpot custom binary
|
||||||
format."
|
format."
|
||||||
[{:keys [::bfc/input ::bfc/timestamp] :or {timestamp (dt/now)} :as options}]
|
[{:keys [::bfc/input ::bfc/timestamp] :or {timestamp (ct/now)} :as options}]
|
||||||
|
|
||||||
(dm/assert!
|
(dm/assert!
|
||||||
"expected input stream"
|
"expected input stream"
|
||||||
@@ -442,7 +442,7 @@
|
|||||||
|
|
||||||
(dm/assert!
|
(dm/assert!
|
||||||
"expected valid instant"
|
"expected valid instant"
|
||||||
(dt/instant? timestamp))
|
(ct/inst? timestamp))
|
||||||
|
|
||||||
(let [version (read-header! input)]
|
(let [version (read-header! input)]
|
||||||
(read-import (assoc options ::version version ::bfc/timestamp timestamp))))
|
(read-import (assoc options ::version version ::bfc/timestamp timestamp))))
|
||||||
@@ -682,7 +682,7 @@
|
|||||||
(io/coercible? output))
|
(io/coercible? output))
|
||||||
|
|
||||||
(let [id (uuid/next)
|
(let [id (uuid/next)
|
||||||
tp (dt/tpoint)
|
tp (ct/tpoint)
|
||||||
ab (volatile! false)
|
ab (volatile! false)
|
||||||
cs (volatile! nil)]
|
cs (volatile! nil)]
|
||||||
(try
|
(try
|
||||||
@@ -720,7 +720,7 @@
|
|||||||
(satisfies? jio/IOFactory input))
|
(satisfies? jio/IOFactory input))
|
||||||
|
|
||||||
(let [id (uuid/next)
|
(let [id (uuid/next)
|
||||||
tp (dt/tpoint)
|
tp (ct/tpoint)
|
||||||
cs (volatile! nil)]
|
cs (volatile! nil)]
|
||||||
|
|
||||||
(l/info :hint "import: started" :id (str id))
|
(l/info :hint "import: started" :id (str id))
|
||||||
@@ -742,6 +742,6 @@
|
|||||||
(finally
|
(finally
|
||||||
(l/info :hint "import: terminated"
|
(l/info :hint "import: terminated"
|
||||||
:id (str id)
|
:id (str id)
|
||||||
:elapsed (dt/format-duration (tp))
|
:elapsed (ct/format-duration (tp))
|
||||||
:error? (some? @cs))))))
|
:error? (some? @cs))))))
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.features :as cfeat]
|
[app.common.features :as cfeat]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
@@ -23,7 +24,6 @@
|
|||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.storage.tmp :as tmp]
|
[app.storage.tmp :as tmp]
|
||||||
[app.util.events :as events]
|
[app.util.events :as events]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as-alias wrk]
|
[app.worker :as-alias wrk]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
@@ -344,7 +344,7 @@
|
|||||||
(defn export-team!
|
(defn export-team!
|
||||||
[cfg team-id]
|
[cfg team-id]
|
||||||
(let [id (uuid/next)
|
(let [id (uuid/next)
|
||||||
tp (dt/tpoint)
|
tp (ct/tpoint)
|
||||||
cfg (create-database cfg)]
|
cfg (create-database cfg)]
|
||||||
|
|
||||||
(l/inf :hint "start"
|
(l/inf :hint "start"
|
||||||
@@ -378,15 +378,15 @@
|
|||||||
(l/inf :hint "end"
|
(l/inf :hint "end"
|
||||||
:operation "export"
|
:operation "export"
|
||||||
:id (str id)
|
:id (str id)
|
||||||
:elapsed (dt/format-duration elapsed)))))))
|
:elapsed (ct/format-duration elapsed)))))))
|
||||||
|
|
||||||
(defn import-team!
|
(defn import-team!
|
||||||
[cfg path]
|
[cfg path]
|
||||||
(let [id (uuid/next)
|
(let [id (uuid/next)
|
||||||
tp (dt/tpoint)
|
tp (ct/tpoint)
|
||||||
|
|
||||||
cfg (-> (create-database cfg path)
|
cfg (-> (create-database cfg path)
|
||||||
(assoc ::bfc/timestamp (dt/now)))]
|
(assoc ::bfc/timestamp (ct/now)))]
|
||||||
|
|
||||||
(l/inf :hint "start"
|
(l/inf :hint "start"
|
||||||
:operation "import"
|
:operation "import"
|
||||||
@@ -434,4 +434,4 @@
|
|||||||
(l/inf :hint "end"
|
(l/inf :hint "end"
|
||||||
:operation "import"
|
:operation "import"
|
||||||
:id (str id)
|
:id (str id)
|
||||||
:elapsed (dt/format-duration elapsed)))))))
|
:elapsed (ct/format-duration elapsed)))))))
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
[app.common.media :as cmedia]
|
[app.common.media :as cmedia]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.thumbnails :as cth]
|
[app.common.thumbnails :as cth]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.color :as ctcl]
|
[app.common.types.color :as ctcl]
|
||||||
[app.common.types.component :as ctc]
|
[app.common.types.component :as ctc]
|
||||||
[app.common.types.file :as ctf]
|
[app.common.types.file :as ctf]
|
||||||
@@ -35,7 +36,6 @@
|
|||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.storage.impl :as sto.impl]
|
[app.storage.impl :as sto.impl]
|
||||||
[app.util.events :as events]
|
[app.util.events :as events]
|
||||||
[app.util.time :as dt]
|
|
||||||
[clojure.java.io :as jio]
|
[clojure.java.io :as jio]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[datoteka.fs :as fs]
|
[datoteka.fs :as fs]
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
|
|
||||||
(defn- default-now
|
(defn- default-now
|
||||||
[o]
|
[o]
|
||||||
(or o (dt/now)))
|
(or o (ct/now)))
|
||||||
|
|
||||||
;; --- ENCODERS
|
;; --- ENCODERS
|
||||||
|
|
||||||
@@ -937,10 +937,10 @@
|
|||||||
[file-id])))
|
[file-id])))
|
||||||
|
|
||||||
(defn- import-files
|
(defn- import-files
|
||||||
[{:keys [::bfc/timestamp ::bfc/input] :or {timestamp (dt/now)} :as cfg}]
|
[{:keys [::bfc/timestamp ::bfc/input] :or {timestamp (ct/now)} :as cfg}]
|
||||||
|
|
||||||
(assert (instance? ZipFile input) "expected zip file")
|
(assert (instance? ZipFile input) "expected zip file")
|
||||||
(assert (dt/instant? timestamp) "expected valid instant")
|
(assert (ct/inst? timestamp) "expected valid instant")
|
||||||
|
|
||||||
(let [manifest (-> (read-manifest input)
|
(let [manifest (-> (read-manifest input)
|
||||||
(validate-manifest))
|
(validate-manifest))
|
||||||
@@ -1000,7 +1000,7 @@
|
|||||||
"expected instance of jio/IOFactory for `input`")
|
"expected instance of jio/IOFactory for `input`")
|
||||||
|
|
||||||
(let [id (uuid/next)
|
(let [id (uuid/next)
|
||||||
tp (dt/tpoint)
|
tp (ct/tpoint)
|
||||||
ab (volatile! false)
|
ab (volatile! false)
|
||||||
cs (volatile! nil)]
|
cs (volatile! nil)]
|
||||||
(try
|
(try
|
||||||
@@ -1046,7 +1046,7 @@
|
|||||||
"expected instance of jio/IOFactory for `input`")
|
"expected instance of jio/IOFactory for `input`")
|
||||||
|
|
||||||
(let [id (uuid/next)
|
(let [id (uuid/next)
|
||||||
tp (dt/tpoint)
|
tp (ct/tpoint)
|
||||||
cs (volatile! nil)]
|
cs (volatile! nil)]
|
||||||
|
|
||||||
(l/info :hint "import: started" :id (str id))
|
(l/info :hint "import: started" :id (str id))
|
||||||
@@ -1061,7 +1061,7 @@
|
|||||||
(finally
|
(finally
|
||||||
(l/info :hint "import: terminated"
|
(l/info :hint "import: terminated"
|
||||||
:id (str id)
|
:id (str id)
|
||||||
:elapsed (dt/format-duration (tp))
|
:elapsed (ct/format-duration (tp))
|
||||||
:error? (some? @cs))))))
|
:error? (some? @cs))))))
|
||||||
|
|
||||||
(defn get-manifest
|
(defn get-manifest
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.flags :as flags]
|
[app.common.flags :as flags]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uri :as u]
|
[app.common.uri :as u]
|
||||||
[app.common.version :as v]
|
[app.common.version :as v]
|
||||||
[app.util.overrides]
|
[app.util.overrides]
|
||||||
[app.util.time :as dt]
|
|
||||||
[clojure.core :as c]
|
[clojure.core :as c]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
@@ -59,10 +59,10 @@
|
|||||||
:smtp-default-reply-to "Penpot <no-reply@example.com>"
|
:smtp-default-reply-to "Penpot <no-reply@example.com>"
|
||||||
:smtp-default-from "Penpot <no-reply@example.com>"
|
:smtp-default-from "Penpot <no-reply@example.com>"
|
||||||
|
|
||||||
:profile-complaint-max-age (dt/duration {:days 7})
|
:profile-complaint-max-age (ct/duration {:days 7})
|
||||||
:profile-complaint-threshold 2
|
:profile-complaint-threshold 2
|
||||||
|
|
||||||
:profile-bounce-max-age (dt/duration {:days 7})
|
:profile-bounce-max-age (ct/duration {:days 7})
|
||||||
:profile-bounce-threshold 10
|
:profile-bounce-threshold 10
|
||||||
|
|
||||||
:telemetry-uri "https://telemetry.penpot.app/"
|
:telemetry-uri "https://telemetry.penpot.app/"
|
||||||
@@ -102,10 +102,10 @@
|
|||||||
[:telemetry-with-taiga {:optional true} ::sm/boolean] ;; DELETE
|
[:telemetry-with-taiga {:optional true} ::sm/boolean] ;; DELETE
|
||||||
|
|
||||||
[:auto-file-snapshot-every {:optional true} ::sm/int]
|
[:auto-file-snapshot-every {:optional true} ::sm/int]
|
||||||
[:auto-file-snapshot-timeout {:optional true} ::dt/duration]
|
[:auto-file-snapshot-timeout {:optional true} ::ct/duration]
|
||||||
|
|
||||||
[:media-max-file-size {:optional true} ::sm/int]
|
[:media-max-file-size {:optional true} ::sm/int]
|
||||||
[:deletion-delay {:optional true} ::dt/duration] ;; REVIEW
|
[:deletion-delay {:optional true} ::ct/duration] ;; REVIEW
|
||||||
[:telemetry-enabled {:optional true} ::sm/boolean]
|
[:telemetry-enabled {:optional true} ::sm/boolean]
|
||||||
[:default-blob-version {:optional true} ::sm/int]
|
[:default-blob-version {:optional true} ::sm/int]
|
||||||
[:allow-demo-users {:optional true} ::sm/boolean]
|
[:allow-demo-users {:optional true} ::sm/boolean]
|
||||||
@@ -148,10 +148,10 @@
|
|||||||
|
|
||||||
[:auth-data-cookie-domain {:optional true} :string]
|
[:auth-data-cookie-domain {:optional true} :string]
|
||||||
[:auth-token-cookie-name {:optional true} :string]
|
[:auth-token-cookie-name {:optional true} :string]
|
||||||
[:auth-token-cookie-max-age {:optional true} ::dt/duration]
|
[:auth-token-cookie-max-age {:optional true} ::ct/duration]
|
||||||
|
|
||||||
[:registration-domain-whitelist {:optional true} [::sm/set :string]]
|
[:registration-domain-whitelist {:optional true} [::sm/set :string]]
|
||||||
[:email-verify-threshold {:optional true} ::dt/duration]
|
[:email-verify-threshold {:optional true} ::ct/duration]
|
||||||
|
|
||||||
[:github-client-id {:optional true} :string]
|
[:github-client-id {:optional true} :string]
|
||||||
[:github-client-secret {:optional true} :string]
|
[:github-client-secret {:optional true} :string]
|
||||||
@@ -186,9 +186,9 @@
|
|||||||
[:ldap-starttls {:optional true} ::sm/boolean]
|
[:ldap-starttls {:optional true} ::sm/boolean]
|
||||||
[:ldap-user-query {:optional true} :string]
|
[:ldap-user-query {:optional true} :string]
|
||||||
|
|
||||||
[:profile-bounce-max-age {:optional true} ::dt/duration]
|
[:profile-bounce-max-age {:optional true} ::ct/duration]
|
||||||
[:profile-bounce-threshold {:optional true} ::sm/int]
|
[:profile-bounce-threshold {:optional true} ::sm/int]
|
||||||
[:profile-complaint-max-age {:optional true} ::dt/duration]
|
[:profile-complaint-max-age {:optional true} ::ct/duration]
|
||||||
[:profile-complaint-threshold {:optional true} ::sm/int]
|
[:profile-complaint-threshold {:optional true} ::sm/int]
|
||||||
|
|
||||||
[:redis-uri {:optional true} ::sm/uri]
|
[:redis-uri {:optional true} ::sm/uri]
|
||||||
@@ -298,7 +298,7 @@
|
|||||||
(defn get-deletion-delay
|
(defn get-deletion-delay
|
||||||
[]
|
[]
|
||||||
(or (c/get config :deletion-delay)
|
(or (c/get config :deletion-delay)
|
||||||
(dt/duration {:days 7})))
|
(ct/duration {:days 7})))
|
||||||
|
|
||||||
(defn get
|
(defn get
|
||||||
"A configuration getter. Helps code be more testable."
|
"A configuration getter. Helps code be more testable."
|
||||||
|
|||||||
@@ -13,11 +13,11 @@
|
|||||||
[app.common.json :as json]
|
[app.common.json :as json]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.db.sql :as sql]
|
[app.db.sql :as sql]
|
||||||
[app.metrics :as mtx]
|
[app.metrics :as mtx]
|
||||||
[app.util.time :as dt]
|
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[integrant.core :as ig]
|
[integrant.core :as ig]
|
||||||
@@ -379,9 +379,9 @@
|
|||||||
|
|
||||||
(defn is-row-deleted?
|
(defn is-row-deleted?
|
||||||
[{:keys [deleted-at]}]
|
[{:keys [deleted-at]}]
|
||||||
(and (dt/instant? deleted-at)
|
(and (ct/inst? deleted-at)
|
||||||
(< (inst-ms deleted-at)
|
(< (inst-ms deleted-at)
|
||||||
(inst-ms (dt/now)))))
|
(inst-ms (ct/now)))))
|
||||||
|
|
||||||
(defn get*
|
(defn get*
|
||||||
"Retrieve a single row from database that matches a simple filters. Do
|
"Retrieve a single row from database that matches a simple filters. Do
|
||||||
@@ -605,7 +605,7 @@
|
|||||||
(string? o)
|
(string? o)
|
||||||
(pginterval o)
|
(pginterval o)
|
||||||
|
|
||||||
(dt/duration? o)
|
(ct/duration? o)
|
||||||
(interval (inst-ms o))
|
(interval (inst-ms o))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
(ns app.features.logical-deletion
|
(ns app.features.logical-deletion
|
||||||
"A code related to handle logical deletion mechanism"
|
"A code related to handle logical deletion mechanism"
|
||||||
(:require
|
(:require
|
||||||
[app.config :as cf]
|
[app.common.time :as ct]
|
||||||
[app.util.time :as dt]))
|
[app.config :as cf]))
|
||||||
|
|
||||||
(def ^:private canceled-status
|
(def ^:private canceled-status
|
||||||
#{"canceled" "unpaid"})
|
#{"canceled" "unpaid"})
|
||||||
@@ -20,10 +20,10 @@
|
|||||||
(if-let [{:keys [type status]} (get team :subscription)]
|
(if-let [{:keys [type status]} (get team :subscription)]
|
||||||
(cond
|
(cond
|
||||||
(and (= "unlimited" type) (not (contains? canceled-status status)))
|
(and (= "unlimited" type) (not (contains? canceled-status status)))
|
||||||
(dt/duration {:days 30})
|
(ct/duration {:days 30})
|
||||||
|
|
||||||
(and (= "enterprise" type) (not (contains? canceled-status status)))
|
(and (= "enterprise" type) (not (contains? canceled-status status)))
|
||||||
(dt/duration {:days 90})
|
(ct/duration {:days 90})
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(cf/get-deletion-delay))
|
(cf/get-deletion-delay))
|
||||||
|
|||||||
@@ -9,18 +9,18 @@
|
|||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uri :as u]
|
[app.common.uri :as u]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.util.time :as dt]
|
|
||||||
[integrant.core :as ig]
|
[integrant.core :as ig]
|
||||||
[yetti.response :as-alias yres]))
|
[yetti.response :as-alias yres]))
|
||||||
|
|
||||||
(def ^:private cache-max-age
|
(def ^:private cache-max-age
|
||||||
(dt/duration {:hours 24}))
|
(ct/duration {:hours 24}))
|
||||||
|
|
||||||
(def ^:private signature-max-age
|
(def ^:private signature-max-age
|
||||||
(dt/duration {:hours 24 :minutes 15}))
|
(ct/duration {:hours 24 :minutes 15}))
|
||||||
|
|
||||||
(defn get-id
|
(defn get-id
|
||||||
[{:keys [path-params]}]
|
[{:keys [path-params]}]
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
[app.common.features :as cfeat]
|
[app.common.features :as cfeat]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.pprint :as pp]
|
[app.common.pprint :as pp]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
@@ -31,7 +32,6 @@
|
|||||||
[app.storage.tmp :as tmp]
|
[app.storage.tmp :as tmp]
|
||||||
[app.util.blob :as blob]
|
[app.util.blob :as blob]
|
||||||
[app.util.template :as tmpl]
|
[app.util.template :as tmpl]
|
||||||
[app.util.time :as dt]
|
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[datoteka.io :as io]
|
[datoteka.io :as io]
|
||||||
[emoji.core :as emj]
|
[emoji.core :as emj]
|
||||||
@@ -137,7 +137,7 @@
|
|||||||
file (some-> params :file :path io/read* t/decode)]
|
file (some-> params :file :path io/read* t/decode)]
|
||||||
|
|
||||||
(if (and file project-id)
|
(if (and file project-id)
|
||||||
(let [fname (str "Imported: " (:name file) "(" (dt/now) ")")
|
(let [fname (str "Imported: " (:name file) "(" (ct/now) ")")
|
||||||
reuse-id? (contains? params :reuseid)
|
reuse-id? (contains? params :reuseid)
|
||||||
file-id (or (and reuse-id? (ex/ignoring (-> params :file :filename parse-uuid)))
|
file-id (or (and reuse-id? (ex/ignoring (-> params :file :filename parse-uuid)))
|
||||||
(uuid/next))]
|
(uuid/next))]
|
||||||
@@ -222,7 +222,7 @@
|
|||||||
(-> (io/resource "app/templates/error-report.v3.tmpl")
|
(-> (io/resource "app/templates/error-report.v3.tmpl")
|
||||||
(tmpl/render (-> content
|
(tmpl/render (-> content
|
||||||
(assoc :id id)
|
(assoc :id id)
|
||||||
(assoc :created-at (dt/format-instant created-at :rfc1123))))))]
|
(assoc :created-at (ct/format-inst created-at :rfc1123))))))]
|
||||||
|
|
||||||
(if-let [report (get-report request)]
|
(if-let [report (get-report request)]
|
||||||
(let [result (case (:version report)
|
(let [result (case (:version report)
|
||||||
@@ -246,7 +246,7 @@
|
|||||||
(defn error-list-handler
|
(defn error-list-handler
|
||||||
[{:keys [::db/pool]} _request]
|
[{:keys [::db/pool]} _request]
|
||||||
(let [items (->> (db/exec! pool [sql:error-reports])
|
(let [items (->> (db/exec! pool [sql:error-reports])
|
||||||
(map #(update % :created-at dt/format-instant :rfc1123)))]
|
(map #(update % :created-at ct/format-inst :rfc1123)))]
|
||||||
{::yres/status 200
|
{::yres/status 200
|
||||||
::yres/body (-> (io/resource "app/templates/error-list.tmpl")
|
::yres/body (-> (io/resource "app/templates/error-list.tmpl")
|
||||||
(tmpl/render {:items items}))
|
(tmpl/render {:items items}))
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uri :as u]
|
[app.common.uri :as u]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -18,7 +19,6 @@
|
|||||||
[app.main :as-alias main]
|
[app.main :as-alias main]
|
||||||
[app.setup :as-alias setup]
|
[app.setup :as-alias setup]
|
||||||
[app.tokens :as tokens]
|
[app.tokens :as tokens]
|
||||||
[app.util.time :as dt]
|
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[integrant.core :as ig]
|
[integrant.core :as ig]
|
||||||
[yetti.request :as yreq]))
|
[yetti.request :as yreq]))
|
||||||
@@ -35,10 +35,10 @@
|
|||||||
(def default-auth-data-cookie-name "auth-data")
|
(def default-auth-data-cookie-name "auth-data")
|
||||||
|
|
||||||
;; Default value for cookie max-age
|
;; Default value for cookie max-age
|
||||||
(def default-cookie-max-age (dt/duration {:days 7}))
|
(def default-cookie-max-age (ct/duration {:days 7}))
|
||||||
|
|
||||||
;; Default age for automatic session renewal
|
;; Default age for automatic session renewal
|
||||||
(def default-renewal-max-age (dt/duration {:hours 6}))
|
(def default-renewal-max-age (ct/duration {:hours 6}))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; PROTOCOLS
|
;; PROTOCOLS
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
[:map {:title "session-params"}
|
[:map {:title "session-params"}
|
||||||
[:user-agent ::sm/text]
|
[:user-agent ::sm/text]
|
||||||
[:profile-id ::sm/uuid]
|
[:profile-id ::sm/uuid]
|
||||||
[:created-at ::sm/inst]])
|
[:created-at ::ct/inst]])
|
||||||
|
|
||||||
(def ^:private valid-params?
|
(def ^:private valid-params?
|
||||||
(sm/validator schema:params))
|
(sm/validator schema:params))
|
||||||
@@ -95,7 +95,7 @@
|
|||||||
params))
|
params))
|
||||||
|
|
||||||
(update! [_ params]
|
(update! [_ params]
|
||||||
(let [updated-at (dt/now)]
|
(let [updated-at (ct/now)]
|
||||||
(db/update! pool :http-session
|
(db/update! pool :http-session
|
||||||
{:updated-at updated-at}
|
{:updated-at updated-at}
|
||||||
{:id (:id params)})
|
{:id (:id params)})
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
params))
|
params))
|
||||||
|
|
||||||
(update! [_ params]
|
(update! [_ params]
|
||||||
(let [updated-at (dt/now)]
|
(let [updated-at (ct/now)]
|
||||||
(swap! cache update (:id params) assoc :updated-at updated-at)
|
(swap! cache update (:id params) assoc :updated-at updated-at)
|
||||||
(assoc params :updated-at updated-at)))
|
(assoc params :updated-at updated-at)))
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@
|
|||||||
(let [uagent (yreq/get-header request "user-agent")
|
(let [uagent (yreq/get-header request "user-agent")
|
||||||
params {:profile-id profile-id
|
params {:profile-id profile-id
|
||||||
:user-agent uagent
|
:user-agent uagent
|
||||||
:created-at (dt/now)}
|
:created-at (ct/now)}
|
||||||
token (gen-token props params)
|
token (gen-token props params)
|
||||||
session (write! manager token params)]
|
session (write! manager token params)]
|
||||||
(l/trace :hint "create" :profile-id (str profile-id))
|
(l/trace :hint "create" :profile-id (str profile-id))
|
||||||
@@ -203,8 +203,8 @@
|
|||||||
|
|
||||||
(defn- renew-session?
|
(defn- renew-session?
|
||||||
[{:keys [updated-at] :as session}]
|
[{:keys [updated-at] :as session}]
|
||||||
(and (dt/instant? updated-at)
|
(and (ct/inst? updated-at)
|
||||||
(let [elapsed (dt/diff updated-at (dt/now))]
|
(let [elapsed (ct/diff updated-at (ct/now))]
|
||||||
(neg? (compare default-renewal-max-age elapsed)))))
|
(neg? (compare default-renewal-max-age elapsed)))))
|
||||||
|
|
||||||
(defn- wrap-soft-auth
|
(defn- wrap-soft-auth
|
||||||
@@ -256,14 +256,14 @@
|
|||||||
(defn- assign-auth-token-cookie
|
(defn- assign-auth-token-cookie
|
||||||
[response {token :id updated-at :updated-at}]
|
[response {token :id updated-at :updated-at}]
|
||||||
(let [max-age (cf/get :auth-token-cookie-max-age default-cookie-max-age)
|
(let [max-age (cf/get :auth-token-cookie-max-age default-cookie-max-age)
|
||||||
created-at (or updated-at (dt/now))
|
created-at (or updated-at (ct/now))
|
||||||
renewal (dt/plus created-at default-renewal-max-age)
|
renewal (ct/plus created-at default-renewal-max-age)
|
||||||
expires (dt/plus created-at max-age)
|
expires (ct/plus created-at max-age)
|
||||||
secure? (contains? cf/flags :secure-session-cookies)
|
secure? (contains? cf/flags :secure-session-cookies)
|
||||||
strict? (contains? cf/flags :strict-session-cookies)
|
strict? (contains? cf/flags :strict-session-cookies)
|
||||||
cors? (contains? cf/flags :cors)
|
cors? (contains? cf/flags :cors)
|
||||||
name (cf/get :auth-token-cookie-name default-auth-token-cookie-name)
|
name (cf/get :auth-token-cookie-name default-auth-token-cookie-name)
|
||||||
comment (str "Renewal at: " (dt/format-instant renewal :rfc1123))
|
comment (str "Renewal at: " (ct/format-inst renewal :rfc1123))
|
||||||
cookie {:path "/"
|
cookie {:path "/"
|
||||||
:http-only true
|
:http-only true
|
||||||
:expires expires
|
:expires expires
|
||||||
@@ -279,11 +279,11 @@
|
|||||||
domain (cf/get :auth-data-cookie-domain)
|
domain (cf/get :auth-data-cookie-domain)
|
||||||
cname default-auth-data-cookie-name
|
cname default-auth-data-cookie-name
|
||||||
|
|
||||||
created-at (or updated-at (dt/now))
|
created-at (or updated-at (ct/now))
|
||||||
renewal (dt/plus created-at default-renewal-max-age)
|
renewal (ct/plus created-at default-renewal-max-age)
|
||||||
expires (dt/plus created-at max-age)
|
expires (ct/plus created-at max-age)
|
||||||
|
|
||||||
comment (str "Renewal at: " (dt/format-instant renewal :rfc1123))
|
comment (str "Renewal at: " (ct/format-inst renewal :rfc1123))
|
||||||
secure? (contains? cf/flags :secure-session-cookies)
|
secure? (contains? cf/flags :secure-session-cookies)
|
||||||
strict? (contains? cf/flags :strict-session-cookies)
|
strict? (contains? cf/flags :strict-session-cookies)
|
||||||
cors? (contains? cf/flags :cors)
|
cors? (contains? cf/flags :cors)
|
||||||
@@ -323,7 +323,7 @@
|
|||||||
(defmethod ig/assert-key ::tasks/gc
|
(defmethod ig/assert-key ::tasks/gc
|
||||||
[_ params]
|
[_ params]
|
||||||
(assert (db/pool? (::db/pool params)) "expected valid database pool")
|
(assert (db/pool? (::db/pool params)) "expected valid database pool")
|
||||||
(assert (dt/duration? (::tasks/max-age params))))
|
(assert (ct/duration? (::tasks/max-age params))))
|
||||||
|
|
||||||
(defmethod ig/expand-key ::tasks/gc
|
(defmethod ig/expand-key ::tasks/gc
|
||||||
[k v]
|
[k v]
|
||||||
|
|||||||
@@ -11,12 +11,12 @@
|
|||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.pprint :as pp]
|
[app.common.pprint :as pp]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.http.session :as session]
|
[app.http.session :as session]
|
||||||
[app.metrics :as mtx]
|
[app.metrics :as mtx]
|
||||||
[app.msgbus :as mbus]
|
[app.msgbus :as mbus]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.util.websocket :as ws]
|
[app.util.websocket :as ws]
|
||||||
[integrant.core :as ig]
|
[integrant.core :as ig]
|
||||||
[promesa.exec.csp :as sp]
|
[promesa.exec.csp :as sp]
|
||||||
@@ -239,7 +239,7 @@
|
|||||||
|
|
||||||
(defn- on-connect
|
(defn- on-connect
|
||||||
[{:keys [::mtx/metrics]} {:keys [::ws/id] :as wsp}]
|
[{:keys [::mtx/metrics]} {:keys [::ws/id] :as wsp}]
|
||||||
(let [created-at (dt/now)]
|
(let [created-at (ct/now)]
|
||||||
(l/trace :fn "on-connect" :conn-id id)
|
(l/trace :fn "on-connect" :conn-id id)
|
||||||
(swap! state assoc id wsp)
|
(swap! state assoc id wsp)
|
||||||
(mtx/run! metrics
|
(mtx/run! metrics
|
||||||
@@ -253,7 +253,7 @@
|
|||||||
(mtx/run! metrics :id :websocket-active-connections :dec 1)
|
(mtx/run! metrics :id :websocket-active-connections :dec 1)
|
||||||
(mtx/run! metrics
|
(mtx/run! metrics
|
||||||
:id :websocket-session-timing
|
:id :websocket-session-timing
|
||||||
:val (/ (inst-ms (dt/diff created-at (dt/now))) 1000.0))))))
|
:val (/ (inst-ms (ct/diff created-at (ct/now))) 1000.0))))))
|
||||||
|
|
||||||
(defn- on-rcv-message
|
(defn- on-rcv-message
|
||||||
[{:keys [::mtx/metrics ::profile-id ::session-id]} message]
|
[{:keys [::mtx/metrics ::profile-id ::session-id]} message]
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -23,7 +24,6 @@
|
|||||||
[app.setup :as-alias setup]
|
[app.setup :as-alias setup]
|
||||||
[app.util.inet :as inet]
|
[app.util.inet :as inet]
|
||||||
[app.util.services :as-alias sv]
|
[app.util.services :as-alias sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
@@ -108,9 +108,9 @@
|
|||||||
[::ip-addr {:optional true} ::sm/text]
|
[::ip-addr {:optional true} ::sm/text]
|
||||||
[::props {:optional true} [:map-of :keyword :any]]
|
[::props {:optional true} [:map-of :keyword :any]]
|
||||||
[::context {:optional true} [:map-of :keyword :any]]
|
[::context {:optional true} [:map-of :keyword :any]]
|
||||||
[::tracked-at {:optional true} ::sm/inst]
|
[::tracked-at {:optional true} ::ct/inst]
|
||||||
[::webhooks/event? {:optional true} ::sm/boolean]
|
[::webhooks/event? {:optional true} ::sm/boolean]
|
||||||
[::webhooks/batch-timeout {:optional true} ::dt/duration]
|
[::webhooks/batch-timeout {:optional true} ::ct/duration]
|
||||||
[::webhooks/batch-key {:optional true}
|
[::webhooks/batch-key {:optional true}
|
||||||
[:or ::sm/fn ::sm/text :keyword]]])
|
[:or ::sm/fn ::sm/text :keyword]]])
|
||||||
|
|
||||||
@@ -199,7 +199,7 @@
|
|||||||
(defn- handle-event!
|
(defn- handle-event!
|
||||||
[cfg event]
|
[cfg event]
|
||||||
(let [params (event->params event)
|
(let [params (event->params event)
|
||||||
tnow (dt/now)]
|
tnow (ct/now)]
|
||||||
|
|
||||||
(when (contains? cf/flags :audit-log)
|
(when (contains? cf/flags :audit-log)
|
||||||
;; NOTE: this operation may cause primary key conflicts on inserts
|
;; NOTE: this operation may cause primary key conflicts on inserts
|
||||||
@@ -273,7 +273,7 @@
|
|||||||
(let [event (-> (d/without-nils event)
|
(let [event (-> (d/without-nils event)
|
||||||
(check-event))]
|
(check-event))]
|
||||||
(db/run! cfg (fn [cfg]
|
(db/run! cfg (fn [cfg]
|
||||||
(let [tnow (dt/now)
|
(let [tnow (ct/now)
|
||||||
params (-> (event->params event)
|
params (-> (event->params event)
|
||||||
(assoc :created-at tnow)
|
(assoc :created-at tnow)
|
||||||
(update :tracked-at #(or % tnow)))]
|
(update :tracked-at #(or % tnow)))]
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
@@ -16,7 +17,6 @@
|
|||||||
[app.http.client :as http]
|
[app.http.client :as http]
|
||||||
[app.setup :as-alias setup]
|
[app.setup :as-alias setup]
|
||||||
[app.tokens :as tokens]
|
[app.tokens :as tokens]
|
||||||
[app.util.time :as dt]
|
|
||||||
[integrant.core :as ig]
|
[integrant.core :as ig]
|
||||||
[lambdaisland.uri :as u]
|
[lambdaisland.uri :as u]
|
||||||
[promesa.exec :as px]))
|
[promesa.exec :as px]))
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
[{:keys [::uri] :as cfg} events]
|
[{:keys [::uri] :as cfg} events]
|
||||||
(let [token (tokens/generate (::setup/props cfg)
|
(let [token (tokens/generate (::setup/props cfg)
|
||||||
{:iss "authentication"
|
{:iss "authentication"
|
||||||
:iat (dt/now)
|
:iat (ct/now)
|
||||||
:uid uuid/zero})
|
:uid uuid/zero})
|
||||||
body (t/encode {:events events})
|
body (t/encode {:events events})
|
||||||
headers {"content-type" "application/transit+json"
|
headers {"content-type" "application/transit+json"
|
||||||
|
|||||||
@@ -10,13 +10,13 @@
|
|||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.common.uri :as uri]
|
[app.common.uri :as uri]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.http.client :as http]
|
[app.http.client :as http]
|
||||||
[app.loggers.audit :as audit]
|
[app.loggers.audit :as audit]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[clojure.data.json :as json]
|
[clojure.data.json :as json]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
@@ -124,7 +124,7 @@
|
|||||||
{:id (:id whook)})))
|
{:id (:id whook)})))
|
||||||
|
|
||||||
(db/update! pool :webhook
|
(db/update! pool :webhook
|
||||||
{:updated-at (dt/now)
|
{:updated-at (ct/now)
|
||||||
:error-code nil
|
:error-code nil
|
||||||
:error-count 0}
|
:error-count 0}
|
||||||
{:id (:id whook)})))
|
{:id (:id whook)})))
|
||||||
@@ -132,7 +132,7 @@
|
|||||||
(report-delivery! [whook req rsp err]
|
(report-delivery! [whook req rsp err]
|
||||||
(db/insert! pool :webhook-delivery
|
(db/insert! pool :webhook-delivery
|
||||||
{:webhook-id (:id whook)
|
{:webhook-id (:id whook)
|
||||||
:created-at (dt/now)
|
:created-at (ct/now)
|
||||||
:error-code err
|
:error-code err
|
||||||
:req-data (db/tjson req)
|
:req-data (db/tjson req)
|
||||||
:rsp-data (db/tjson rsp)}))]
|
:rsp-data (db/tjson rsp)}))]
|
||||||
@@ -155,7 +155,7 @@
|
|||||||
(let [req {:uri (:uri whook)
|
(let [req {:uri (:uri whook)
|
||||||
:headers {"content-type" (:mtype whook)
|
:headers {"content-type" (:mtype whook)
|
||||||
"user-agent" (str/ffmt "penpot/%" (:main cf/version))}
|
"user-agent" (str/ffmt "penpot/%" (:main cf/version))}
|
||||||
:timeout (dt/duration "4s")
|
:timeout (ct/duration "4s")
|
||||||
:method :post
|
:method :post
|
||||||
:body body}]
|
:body body}]
|
||||||
(try
|
(try
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
[app.auth.oidc.providers :as-alias oidc.providers]
|
[app.auth.oidc.providers :as-alias oidc.providers]
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as-alias db]
|
[app.db :as-alias db]
|
||||||
[app.email :as-alias email]
|
[app.email :as-alias email]
|
||||||
@@ -38,7 +39,7 @@
|
|||||||
[app.storage.gc-touched :as-alias sto.gc-touched]
|
[app.storage.gc-touched :as-alias sto.gc-touched]
|
||||||
[app.storage.s3 :as-alias sto.s3]
|
[app.storage.s3 :as-alias sto.s3]
|
||||||
[app.svgo :as-alias svgo]
|
[app.svgo :as-alias svgo]
|
||||||
[app.util.time :as dt]
|
[app.util.cron]
|
||||||
[app.worker :as-alias wrk]
|
[app.worker :as-alias wrk]
|
||||||
[clojure.test :as test]
|
[clojure.test :as test]
|
||||||
[clojure.tools.namespace.repl :as repl]
|
[clojure.tools.namespace.repl :as repl]
|
||||||
@@ -298,8 +299,8 @@
|
|||||||
|
|
||||||
:app.http.assets/routes
|
:app.http.assets/routes
|
||||||
{::http.assets/path (cf/get :assets-path)
|
{::http.assets/path (cf/get :assets-path)
|
||||||
::http.assets/cache-max-age (dt/duration {:hours 24})
|
::http.assets/cache-max-age (ct/duration {:hours 24})
|
||||||
::http.assets/cache-max-agesignature-max-age (dt/duration {:hours 24 :minutes 5})
|
::http.assets/cache-max-agesignature-max-age (ct/duration {:hours 24 :minutes 5})
|
||||||
::sto/storage (ig/ref ::sto/storage)}
|
::sto/storage (ig/ref ::sto/storage)}
|
||||||
|
|
||||||
::rpc/climit
|
::rpc/climit
|
||||||
@@ -480,33 +481,33 @@
|
|||||||
{::wrk/registry (ig/ref ::wrk/registry)
|
{::wrk/registry (ig/ref ::wrk/registry)
|
||||||
::db/pool (ig/ref ::db/pool)
|
::db/pool (ig/ref ::db/pool)
|
||||||
::wrk/entries
|
::wrk/entries
|
||||||
[{:cron #app/cron "0 0 0 * * ?" ;; daily
|
[{:cron #penpot/cron "0 0 0 * * ?" ;; daily
|
||||||
:task :session-gc}
|
:task :session-gc}
|
||||||
|
|
||||||
{:cron #app/cron "0 0 0 * * ?" ;; daily
|
{:cron #penpot/cron "0 0 0 * * ?" ;; daily
|
||||||
:task :objects-gc}
|
:task :objects-gc}
|
||||||
|
|
||||||
{:cron #app/cron "0 0 0 * * ?" ;; daily
|
{:cron #penpot/cron "0 0 0 * * ?" ;; daily
|
||||||
:task :storage-gc-deleted}
|
:task :storage-gc-deleted}
|
||||||
|
|
||||||
{:cron #app/cron "0 0 0 * * ?" ;; daily
|
{:cron #penpot/cron "0 0 0 * * ?" ;; daily
|
||||||
:task :storage-gc-touched}
|
:task :storage-gc-touched}
|
||||||
|
|
||||||
{:cron #app/cron "0 0 0 * * ?" ;; daily
|
{:cron #penpot/cron "0 0 0 * * ?" ;; daily
|
||||||
:task :tasks-gc}
|
:task :tasks-gc}
|
||||||
|
|
||||||
{:cron #app/cron "0 0 2 * * ?" ;; daily
|
{:cron #penpot/cron "0 0 2 * * ?" ;; daily
|
||||||
:task :file-gc-scheduler}
|
:task :file-gc-scheduler}
|
||||||
|
|
||||||
{:cron #app/cron "0 30 */3,23 * * ?"
|
{:cron #penpot/cron "0 30 */3,23 * * ?"
|
||||||
:task :telemetry}
|
:task :telemetry}
|
||||||
|
|
||||||
(when (contains? cf/flags :audit-log-archive)
|
(when (contains? cf/flags :audit-log-archive)
|
||||||
{:cron #app/cron "0 */5 * * * ?" ;; every 5m
|
{:cron #penpot/cron "0 */5 * * * ?" ;; every 5m
|
||||||
:task :audit-log-archive})
|
:task :audit-log-archive})
|
||||||
|
|
||||||
(when (contains? cf/flags :audit-log-gc)
|
(when (contains? cf/flags :audit-log-gc)
|
||||||
{:cron #app/cron "30 */5 * * * ?" ;; every 5m
|
{:cron #penpot/cron "30 */5 * * * ?" ;; every 5m
|
||||||
:task :audit-log-gc})]}
|
:task :audit-log-gc})]}
|
||||||
|
|
||||||
::wrk/dispatcher
|
::wrk/dispatcher
|
||||||
|
|||||||
@@ -14,11 +14,11 @@
|
|||||||
[app.common.media :as cm]
|
[app.common.media :as cm]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.schema.openapi :as-alias oapi]
|
[app.common.schema.openapi :as-alias oapi]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as-alias db]
|
[app.db :as-alias db]
|
||||||
[app.storage :as-alias sto]
|
[app.storage :as-alias sto]
|
||||||
[app.storage.tmp :as tmp]
|
[app.storage.tmp :as tmp]
|
||||||
[app.util.time :as dt]
|
|
||||||
[buddy.core.bytes :as bb]
|
[buddy.core.bytes :as bb]
|
||||||
[buddy.core.codecs :as bc]
|
[buddy.core.codecs :as bc]
|
||||||
[clojure.java.shell :as sh]
|
[clojure.java.shell :as sh]
|
||||||
@@ -243,7 +243,7 @@
|
|||||||
(ex/raise :type :validation
|
(ex/raise :type :validation
|
||||||
:code :invalid-svg-file
|
:code :invalid-svg-file
|
||||||
:hint "uploaded svg does not provides dimensions"))
|
:hint "uploaded svg does not provides dimensions"))
|
||||||
(merge input info {:ts (dt/now)}))
|
(merge input info {:ts (ct/now)}))
|
||||||
|
|
||||||
(let [instance (Info. (str path))
|
(let [instance (Info. (str path))
|
||||||
mtype' (.getProperty instance "Mime type")]
|
mtype' (.getProperty instance "Mime type")]
|
||||||
@@ -263,7 +263,7 @@
|
|||||||
(assoc input
|
(assoc input
|
||||||
:width width
|
:width width
|
||||||
:height height
|
:height height
|
||||||
:ts (dt/now)))))))
|
:ts (ct/now)))))))
|
||||||
|
|
||||||
(defmethod process-error org.im4java.core.InfoException
|
(defmethod process-error org.im4java.core.InfoException
|
||||||
[error]
|
[error]
|
||||||
|
|||||||
@@ -10,10 +10,10 @@
|
|||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.config :as cfg]
|
[app.config :as cfg]
|
||||||
[app.redis :as rds]
|
[app.redis :as rds]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[integrant.core :as ig]
|
[integrant.core :as ig]
|
||||||
[promesa.core :as p]
|
[promesa.core :as p]
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
[k v]
|
[k v]
|
||||||
{k (-> (d/without-nils v)
|
{k (-> (d/without-nils v)
|
||||||
(assoc ::buffer-size 128)
|
(assoc ::buffer-size 128)
|
||||||
(assoc ::timeout (dt/duration {:seconds 30})))})
|
(assoc ::timeout (ct/duration {:seconds 30})))})
|
||||||
|
|
||||||
(def ^:private schema:params
|
(def ^:private schema:params
|
||||||
[:map ::rds/redis ::wrk/executor])
|
[:map ::rds/redis ::wrk/executor])
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.metrics :as mtx]
|
[app.metrics :as mtx]
|
||||||
[app.redis.script :as-alias rscript]
|
[app.redis.script :as-alias rscript]
|
||||||
[app.util.cache :as cache]
|
[app.util.cache :as cache]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as-alias wrk]
|
[app.worker :as-alias wrk]
|
||||||
[clojure.core :as c]
|
[clojure.core :as c]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
(let [cpus (px/get-available-processors)
|
(let [cpus (px/get-available-processors)
|
||||||
threads (max 1 (int (* cpus 0.2)))]
|
threads (max 1 (int (* cpus 0.2)))]
|
||||||
{k (-> (d/without-nils v)
|
{k (-> (d/without-nils v)
|
||||||
(assoc ::timeout (dt/duration "10s"))
|
(assoc ::timeout (ct/duration "10s"))
|
||||||
(assoc ::io-threads (max 3 threads))
|
(assoc ::io-threads (max 3 threads))
|
||||||
(assoc ::worker-threads (max 3 threads)))}))
|
(assoc ::worker-threads (max 3 threads)))}))
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
[::uri ::sm/uri]
|
[::uri ::sm/uri]
|
||||||
[::worker-threads ::sm/int]
|
[::worker-threads ::sm/int]
|
||||||
[::io-threads ::sm/int]
|
[::io-threads ::sm/int]
|
||||||
[::timeout ::dt/duration]])
|
[::timeout ::ct/duration]])
|
||||||
|
|
||||||
(defmethod ig/assert-key ::redis
|
(defmethod ig/assert-key ::redis
|
||||||
[_ params]
|
[_ params]
|
||||||
@@ -331,7 +331,7 @@
|
|||||||
(p/rejected cause))))
|
(p/rejected cause))))
|
||||||
|
|
||||||
(eval-script [sha]
|
(eval-script [sha]
|
||||||
(let [tpoint (dt/tpoint)]
|
(let [tpoint (ct/tpoint)]
|
||||||
(->> (.evalsha ^RedisScriptingAsyncCommands cmd
|
(->> (.evalsha ^RedisScriptingAsyncCommands cmd
|
||||||
^String sha
|
^String sha
|
||||||
^ScriptOutputType ScriptOutputType/MULTI
|
^ScriptOutputType ScriptOutputType/MULTI
|
||||||
@@ -346,7 +346,7 @@
|
|||||||
:name (name sname)
|
:name (name sname)
|
||||||
:sha sha
|
:sha sha
|
||||||
:params (str/join "," (::rscript/vals script))
|
:params (str/join "," (::rscript/vals script))
|
||||||
:elapsed (dt/format-duration elapsed))
|
:elapsed (ct/format-duration elapsed))
|
||||||
result)))
|
result)))
|
||||||
(p/merr on-error))))
|
(p/merr on-error))))
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.http :as-alias http]
|
[app.http :as-alias http]
|
||||||
@@ -31,7 +32,6 @@
|
|||||||
[app.storage :as-alias sto]
|
[app.storage :as-alias sto]
|
||||||
[app.util.inet :as inet]
|
[app.util.inet :as inet]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[integrant.core :as ig]
|
[integrant.core :as ig]
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
data (-> params
|
data (-> params
|
||||||
(assoc ::handler-name handler-name)
|
(assoc ::handler-name handler-name)
|
||||||
(assoc ::ip-addr ip-addr)
|
(assoc ::ip-addr ip-addr)
|
||||||
(assoc ::request-at (dt/now))
|
(assoc ::request-at (ct/now))
|
||||||
(assoc ::external-session-id session-id)
|
(assoc ::external-session-id session-id)
|
||||||
(assoc ::external-event-origin event-origin)
|
(assoc ::external-event-origin event-origin)
|
||||||
(assoc ::session/id (::session/id request))
|
(assoc ::session/id (::session/id request))
|
||||||
@@ -130,7 +130,7 @@
|
|||||||
[{:keys [::mtx/metrics ::metrics-id]} f mdata]
|
[{:keys [::mtx/metrics ::metrics-id]} f mdata]
|
||||||
(let [labels (into-array String [(::sv/name mdata)])]
|
(let [labels (into-array String [(::sv/name mdata)])]
|
||||||
(fn [cfg params]
|
(fn [cfg params]
|
||||||
(let [tp (dt/tpoint)]
|
(let [tp (ct/tpoint)]
|
||||||
(try
|
(try
|
||||||
(f cfg params)
|
(f cfg params)
|
||||||
(finally
|
(finally
|
||||||
|
|||||||
@@ -11,11 +11,11 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.metrics :as mtx]
|
[app.metrics :as mtx]
|
||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.util.cache :as cache]
|
[app.util.cache :as cache]
|
||||||
[app.util.services :as-alias sv]
|
[app.util.services :as-alias sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as-alias wrk]
|
[app.worker :as-alias wrk]
|
||||||
[clojure.edn :as edn]
|
[clojure.edn :as edn]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
@@ -154,7 +154,7 @@
|
|||||||
:id limit-id
|
:id limit-id
|
||||||
:label limit-label
|
:label limit-label
|
||||||
:queue queue
|
:queue queue
|
||||||
:elapsed (some-> elapsed dt/format-duration)
|
:elapsed (some-> elapsed ct/format-duration)
|
||||||
:params @limit-params)))
|
:params @limit-params)))
|
||||||
|
|
||||||
(def ^:private idseq (AtomicLong. 0))
|
(def ^:private idseq (AtomicLong. 0))
|
||||||
@@ -171,7 +171,7 @@
|
|||||||
mlabels (into-array String [(id->str limit-id)])
|
mlabels (into-array String [(id->str limit-id)])
|
||||||
limit-id (id->str limit-id limit-key)
|
limit-id (id->str limit-id limit-key)
|
||||||
limiter (cache/get cache limit-id (partial create-limiter config))
|
limiter (cache/get cache limit-id (partial create-limiter config))
|
||||||
tpoint (dt/tpoint)
|
tpoint (ct/tpoint)
|
||||||
req-id (.incrementAndGet ^AtomicLong idseq)]
|
req-id (.incrementAndGet ^AtomicLong idseq)]
|
||||||
(try
|
(try
|
||||||
(let [stats (pbh/get-stats limiter)]
|
(let [stats (pbh/get-stats limiter)]
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
(ns app.rpc.commands.access-token
|
(ns app.rpc.commands.access-token
|
||||||
(:require
|
(:require
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.main :as-alias main]
|
[app.main :as-alias main]
|
||||||
@@ -15,8 +16,7 @@
|
|||||||
[app.rpc.quotes :as quotes]
|
[app.rpc.quotes :as quotes]
|
||||||
[app.setup :as-alias setup]
|
[app.setup :as-alias setup]
|
||||||
[app.tokens :as tokens]
|
[app.tokens :as tokens]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]))
|
||||||
[app.util.time :as dt]))
|
|
||||||
|
|
||||||
(defn- decode-row
|
(defn- decode-row
|
||||||
[row]
|
[row]
|
||||||
@@ -24,13 +24,13 @@
|
|||||||
|
|
||||||
(defn create-access-token
|
(defn create-access-token
|
||||||
[{:keys [::db/conn ::setup/props]} profile-id name expiration]
|
[{:keys [::db/conn ::setup/props]} profile-id name expiration]
|
||||||
(let [created-at (dt/now)
|
(let [created-at (ct/now)
|
||||||
token-id (uuid/next)
|
token-id (uuid/next)
|
||||||
token (tokens/generate props {:iss "access-token"
|
token (tokens/generate props {:iss "access-token"
|
||||||
:tid token-id
|
:tid token-id
|
||||||
:iat created-at})
|
:iat created-at})
|
||||||
|
|
||||||
expires-at (some-> expiration dt/in-future)
|
expires-at (some-> expiration ct/in-future)
|
||||||
token (db/insert! conn :access-token
|
token (db/insert! conn :access-token
|
||||||
{:id token-id
|
{:id token-id
|
||||||
:name name
|
:name name
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
(def ^:private schema:create-access-token
|
(def ^:private schema:create-access-token
|
||||||
[:map {:title "create-access-token"}
|
[:map {:title "create-access-token"}
|
||||||
[:name [:string {:max 250 :min 1}]]
|
[:name [:string {:max 250 :min 1}]]
|
||||||
[:expiration {:optional true} ::dt/duration]])
|
[:expiration {:optional true} ::ct/duration]])
|
||||||
|
|
||||||
(sv/defmethod ::create-access-token
|
(sv/defmethod ::create-access-token
|
||||||
{::doc/added "1.18"
|
{::doc/added "1.18"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -20,8 +21,7 @@
|
|||||||
[app.rpc.doc :as-alias doc]
|
[app.rpc.doc :as-alias doc]
|
||||||
[app.rpc.helpers :as rph]
|
[app.rpc.helpers :as rph]
|
||||||
[app.util.inet :as inet]
|
[app.util.inet :as inet]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]))
|
||||||
[app.util.time :as dt]))
|
|
||||||
|
|
||||||
(def ^:private event-columns
|
(def ^:private event-columns
|
||||||
[:id
|
[:id
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
|
|
||||||
(defn- adjust-timestamp
|
(defn- adjust-timestamp
|
||||||
[{:keys [timestamp created-at] :as event}]
|
[{:keys [timestamp created-at] :as event}]
|
||||||
(let [margin (inst-ms (dt/diff timestamp created-at))]
|
(let [margin (inst-ms (ct/diff timestamp created-at))]
|
||||||
(if (or (neg? margin)
|
(if (or (neg? margin)
|
||||||
(> margin 3600000))
|
(> margin 3600000))
|
||||||
;; If event is in future or lags more than 1 hour, we reasign
|
;; If event is in future or lags more than 1 hour, we reasign
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
[{:keys [::db/pool]} {:keys [::rpc/profile-id events] :as params}]
|
[{:keys [::db/pool]} {:keys [::rpc/profile-id events] :as params}]
|
||||||
(let [request (-> params meta ::http/request)
|
(let [request (-> params meta ::http/request)
|
||||||
ip-addr (inet/parse-request request)
|
ip-addr (inet/parse-request request)
|
||||||
tnow (dt/now)
|
tnow (ct/now)
|
||||||
xform (comp
|
xform (comp
|
||||||
(map (fn [event]
|
(map (fn [event]
|
||||||
(-> event
|
(-> event
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
[app.common.features :as cfeat]
|
[app.common.features :as cfeat]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -30,7 +31,6 @@
|
|||||||
[app.setup.welcome-file :refer [create-welcome-file]]
|
[app.setup.welcome-file :refer [create-welcome-file]]
|
||||||
[app.tokens :as tokens]
|
[app.tokens :as tokens]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
(defn- elapsed-verify-threshold?
|
(defn- elapsed-verify-threshold?
|
||||||
[profile]
|
[profile]
|
||||||
(let [elapsed (dt/diff (:modified-at profile) (dt/now))
|
(let [elapsed (ct/diff (:modified-at profile) (ct/now))
|
||||||
verify-threshold (cf/get :email-verify-threshold)]
|
verify-threshold (cf/get :email-verify-threshold)]
|
||||||
(pos? (compare elapsed verify-threshold))))
|
(pos? (compare elapsed verify-threshold))))
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
(ex/raise :type :validation
|
(ex/raise :type :validation
|
||||||
:code :wrong-credentials))
|
:code :wrong-credentials))
|
||||||
(when-let [deleted-at (:deleted-at profile)]
|
(when-let [deleted-at (:deleted-at profile)]
|
||||||
(when (dt/is-after? (dt/now) deleted-at)
|
(when (ct/is-after? (ct/now) deleted-at)
|
||||||
(ex/raise :type :validation
|
(ex/raise :type :validation
|
||||||
:code :wrong-credentials)))
|
:code :wrong-credentials)))
|
||||||
|
|
||||||
@@ -244,7 +244,7 @@
|
|||||||
:backend "penpot"
|
:backend "penpot"
|
||||||
:iss :prepared-register
|
:iss :prepared-register
|
||||||
:profile-id (:id profile)
|
:profile-id (:id profile)
|
||||||
:exp (dt/in-future {:days 7})
|
:exp (ct/in-future {:days 7})
|
||||||
:props {:newsletter-updates (or accept-newsletter-updates false)}}
|
:props {:newsletter-updates (or accept-newsletter-updates false)}}
|
||||||
|
|
||||||
params (d/without-nils params)
|
params (d/without-nils params)
|
||||||
@@ -344,7 +344,7 @@
|
|||||||
[{:keys [::db/conn] :as cfg} profile]
|
[{:keys [::db/conn] :as cfg} profile]
|
||||||
(let [vtoken (tokens/generate (::setup/props cfg)
|
(let [vtoken (tokens/generate (::setup/props cfg)
|
||||||
{:iss :verify-email
|
{:iss :verify-email
|
||||||
:exp (dt/in-future "72h")
|
:exp (ct/in-future "72h")
|
||||||
:profile-id (:id profile)
|
:profile-id (:id profile)
|
||||||
:email (:email profile)})
|
:email (:email profile)})
|
||||||
;; NOTE: this token is mainly used for possible complains
|
;; NOTE: this token is mainly used for possible complains
|
||||||
@@ -352,7 +352,7 @@
|
|||||||
ptoken (tokens/generate (::setup/props cfg)
|
ptoken (tokens/generate (::setup/props cfg)
|
||||||
{:iss :profile-identity
|
{:iss :profile-identity
|
||||||
:profile-id (:id profile)
|
:profile-id (:id profile)
|
||||||
:exp (dt/in-future {:days 30})})]
|
:exp (ct/in-future {:days 30})})]
|
||||||
(eml/send! {::eml/conn conn
|
(eml/send! {::eml/conn conn
|
||||||
::eml/factory eml/register
|
::eml/factory eml/register
|
||||||
:public-uri (cf/get :public-uri)
|
:public-uri (cf/get :public-uri)
|
||||||
@@ -466,7 +466,7 @@
|
|||||||
|
|
||||||
(when (= action "resend-email-verification")
|
(when (= action "resend-email-verification")
|
||||||
(db/update! conn :profile
|
(db/update! conn :profile
|
||||||
{:modified-at (dt/now)}
|
{:modified-at (ct/now)}
|
||||||
{:id (:id profile)})
|
{:id (:id profile)})
|
||||||
(send-email-verification! cfg profile))
|
(send-email-verification! cfg profile))
|
||||||
|
|
||||||
@@ -495,7 +495,7 @@
|
|||||||
(letfn [(create-recovery-token [{:keys [id] :as profile}]
|
(letfn [(create-recovery-token [{:keys [id] :as profile}]
|
||||||
(let [token (tokens/generate (::setup/props cfg)
|
(let [token (tokens/generate (::setup/props cfg)
|
||||||
{:iss :password-recovery
|
{:iss :password-recovery
|
||||||
:exp (dt/in-future "15m")
|
:exp (ct/in-future "15m")
|
||||||
:profile-id id})]
|
:profile-id id})]
|
||||||
(assoc profile :token token)))
|
(assoc profile :token token)))
|
||||||
|
|
||||||
@@ -503,7 +503,7 @@
|
|||||||
(let [ptoken (tokens/generate (::setup/props cfg)
|
(let [ptoken (tokens/generate (::setup/props cfg)
|
||||||
{:iss :profile-identity
|
{:iss :profile-identity
|
||||||
:profile-id (:id profile)
|
:profile-id (:id profile)
|
||||||
:exp (dt/in-future {:days 30})})]
|
:exp (ct/in-future {:days 30})})]
|
||||||
(eml/send! {::eml/conn conn
|
(eml/send! {::eml/conn conn
|
||||||
::eml/factory eml/password-recovery
|
::eml/factory eml/password-recovery
|
||||||
:public-uri (cf/get :public-uri)
|
:public-uri (cf/get :public-uri)
|
||||||
@@ -544,7 +544,7 @@
|
|||||||
:else
|
:else
|
||||||
(do
|
(do
|
||||||
(db/update! conn :profile
|
(db/update! conn :profile
|
||||||
{:modified-at (dt/now)}
|
{:modified-at (ct/now)}
|
||||||
{:id (:id profile)})
|
{:id (:id profile)})
|
||||||
(->> profile
|
(->> profile
|
||||||
(create-recovery-token)
|
(create-recovery-token)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
[app.common.features :as cfeat]
|
[app.common.features :as cfeat]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.http.sse :as sse]
|
[app.http.sse :as sse]
|
||||||
@@ -26,7 +27,6 @@
|
|||||||
[app.rpc.doc :as-alias doc]
|
[app.rpc.doc :as-alias doc]
|
||||||
[app.tasks.file-gc]
|
[app.tasks.file-gc]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as-alias wrk]
|
[app.worker :as-alias wrk]
|
||||||
[promesa.exec :as px]
|
[promesa.exec :as px]
|
||||||
[yetti.response :as yres]))
|
[yetti.response :as yres]))
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
3 (px/invoke! executor (partial bf.v3/import-files! cfg)))]
|
3 (px/invoke! executor (partial bf.v3/import-files! cfg)))]
|
||||||
|
|
||||||
(db/update! pool :project
|
(db/update! pool :project
|
||||||
{:modified-at (dt/now)}
|
{:modified-at (ct/now)}
|
||||||
{:id project-id}
|
{:id project-id}
|
||||||
{::db/return-keys false})
|
{::db/return-keys false})
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uri :as uri]
|
[app.common.uri :as uri]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
@@ -29,7 +30,6 @@
|
|||||||
[app.rpc.retry :as rtry]
|
[app.rpc.retry :as rtry]
|
||||||
[app.util.pointer-map :as pmap]
|
[app.util.pointer-map :as pmap]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
@@ -222,7 +222,7 @@
|
|||||||
|
|
||||||
(defn upsert-comment-thread-status!
|
(defn upsert-comment-thread-status!
|
||||||
([conn profile-id thread-id]
|
([conn profile-id thread-id]
|
||||||
(upsert-comment-thread-status! conn profile-id thread-id (dt/in-future "1s")))
|
(upsert-comment-thread-status! conn profile-id thread-id (ct/in-future "1s")))
|
||||||
([conn profile-id thread-id mod-at]
|
([conn profile-id thread-id mod-at]
|
||||||
(db/exec-one! conn [sql:upsert-comment-thread-status thread-id profile-id mod-at mod-at])))
|
(db/exec-one! conn [sql:upsert-comment-thread-status thread-id profile-id mod-at mod-at])))
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"A demo specific mutations."
|
"A demo specific mutations."
|
||||||
(:require
|
(:require
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.loggers.audit :as audit]
|
[app.loggers.audit :as audit]
|
||||||
@@ -16,7 +17,6 @@
|
|||||||
[app.rpc.commands.profile :as profile]
|
[app.rpc.commands.profile :as profile]
|
||||||
[app.rpc.doc :as-alias doc]
|
[app.rpc.doc :as-alias doc]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[buddy.core.codecs :as bc]
|
[buddy.core.codecs :as bc]
|
||||||
[buddy.core.nonce :as bn]))
|
[buddy.core.nonce :as bn]))
|
||||||
|
|
||||||
@@ -45,15 +45,13 @@
|
|||||||
params {:email email
|
params {:email email
|
||||||
:fullname fullname
|
:fullname fullname
|
||||||
:is-active true
|
:is-active true
|
||||||
:deleted-at (dt/in-future (cf/get-deletion-delay))
|
:deleted-at (ct/in-future (cf/get-deletion-delay))
|
||||||
:password (profile/derive-password cfg password)
|
:password (profile/derive-password cfg password)
|
||||||
:props {}}]
|
:props {}}
|
||||||
|
profile (db/tx-run! cfg (fn [{:keys [::db/conn]}]
|
||||||
|
(->> (auth/create-profile! conn params)
|
||||||
(let [profile (db/tx-run! cfg (fn [{:keys [::db/conn]}]
|
(auth/create-profile-rels! conn))))]
|
||||||
(->> (auth/create-profile! conn params)
|
(with-meta {:email email
|
||||||
(auth/create-profile-rels! conn))))]
|
:password password}
|
||||||
(with-meta {:email email
|
{::audit/profile-id (:id profile)})))
|
||||||
:password password}
|
|
||||||
{::audit/profile-id (:id profile)}))))
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.schema.desc-js-like :as-alias smdj]
|
[app.common.schema.desc-js-like :as-alias smdj]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.components-list :as ctkl]
|
[app.common.types.components-list :as ctkl]
|
||||||
[app.common.types.file :as ctf]
|
[app.common.types.file :as ctf]
|
||||||
[app.common.uri :as uri]
|
[app.common.uri :as uri]
|
||||||
@@ -37,7 +38,6 @@
|
|||||||
[app.util.blob :as blob]
|
[app.util.blob :as blob]
|
||||||
[app.util.pointer-map :as pmap]
|
[app.util.pointer-map :as pmap]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[promesa.exec :as px]))
|
[promesa.exec :as px]))
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
;; --- HELPERS
|
;; --- HELPERS
|
||||||
|
|
||||||
(def long-cache-duration
|
(def long-cache-duration
|
||||||
(dt/duration {:days 7}))
|
(ct/duration {:days 7}))
|
||||||
|
|
||||||
(defn decode-row
|
(defn decode-row
|
||||||
[{:keys [data changes features] :as row}]
|
[{:keys [data changes features] :as row}]
|
||||||
@@ -187,10 +187,10 @@
|
|||||||
[:name [:string {:max 250}]]
|
[:name [:string {:max 250}]]
|
||||||
[:revn [::sm/int {:min 0}]]
|
[:revn [::sm/int {:min 0}]]
|
||||||
[:vern [::sm/int {:min 0}]]
|
[:vern [::sm/int {:min 0}]]
|
||||||
[:modified-at ::dt/instant]
|
[:modified-at ::ct/inst]
|
||||||
[:is-shared ::sm/boolean]
|
[:is-shared ::sm/boolean]
|
||||||
[:project-id ::sm/uuid]
|
[:project-id ::sm/uuid]
|
||||||
[:created-at ::dt/instant]
|
[:created-at ::ct/inst]
|
||||||
[:data {:optional true} ::sm/any]])
|
[:data {:optional true} ::sm/any]])
|
||||||
|
|
||||||
(def schema:permissions-mixin
|
(def schema:permissions-mixin
|
||||||
@@ -304,7 +304,7 @@
|
|||||||
(defn get-file-etag
|
(defn get-file-etag
|
||||||
[{:keys [::rpc/profile-id]} {:keys [modified-at revn vern permissions]}]
|
[{:keys [::rpc/profile-id]} {:keys [modified-at revn vern permissions]}]
|
||||||
(str profile-id "/" revn "/" vern "/" (hash fmg/available-migrations) "/"
|
(str profile-id "/" revn "/" vern "/" (hash fmg/available-migrations) "/"
|
||||||
(dt/format-instant modified-at :iso)
|
(ct/format-inst modified-at :iso)
|
||||||
"/"
|
"/"
|
||||||
(uri/map->query-string permissions)))
|
(uri/map->query-string permissions)))
|
||||||
|
|
||||||
@@ -356,7 +356,7 @@
|
|||||||
[:map {:title "FileFragment"}
|
[:map {:title "FileFragment"}
|
||||||
[:id ::sm/uuid]
|
[:id ::sm/uuid]
|
||||||
[:file-id ::sm/uuid]
|
[:file-id ::sm/uuid]
|
||||||
[:created-at ::dt/instant]
|
[:created-at ::ct/inst]
|
||||||
[:content any?]])
|
[:content any?]])
|
||||||
|
|
||||||
(def schema:get-file-fragment
|
(def schema:get-file-fragment
|
||||||
@@ -770,7 +770,7 @@
|
|||||||
[conn {:keys [id name]}]
|
[conn {:keys [id name]}]
|
||||||
(db/update! conn :file
|
(db/update! conn :file
|
||||||
{:name name
|
{:name name
|
||||||
:modified-at (dt/now)}
|
:modified-at (ct/now)}
|
||||||
{:id id}
|
{:id id}
|
||||||
{::db/return-keys true}))
|
{::db/return-keys true}))
|
||||||
|
|
||||||
@@ -783,8 +783,8 @@
|
|||||||
[:id ::sm/uuid]
|
[:id ::sm/uuid]
|
||||||
[:project-id ::sm/uuid]
|
[:project-id ::sm/uuid]
|
||||||
[:name [:string {:max 250}]]
|
[:name [:string {:max 250}]]
|
||||||
[:created-at ::dt/instant]
|
[:created-at ::ct/inst]
|
||||||
[:modified-at ::dt/instant]]
|
[:modified-at ::ct/inst]]
|
||||||
|
|
||||||
::sm/params
|
::sm/params
|
||||||
[:map {:title "RenameFileParams"}
|
[:map {:title "RenameFileParams"}
|
||||||
@@ -795,8 +795,8 @@
|
|||||||
[:map {:title "SimplifiedFile"}
|
[:map {:title "SimplifiedFile"}
|
||||||
[:id ::sm/uuid]
|
[:id ::sm/uuid]
|
||||||
[:name [:string {:max 250}]]
|
[:name [:string {:max 250}]]
|
||||||
[:created-at ::dt/instant]
|
[:created-at ::ct/inst]
|
||||||
[:modified-at ::dt/instant]]
|
[:modified-at ::ct/inst]]
|
||||||
|
|
||||||
::db/transaction true}
|
::db/transaction true}
|
||||||
[{:keys [::db/conn] :as cfg} {:keys [::rpc/profile-id id] :as params}]
|
[{:keys [::db/conn] :as cfg} {:keys [::rpc/profile-id id] :as params}]
|
||||||
@@ -839,7 +839,7 @@
|
|||||||
(db/update! cfg :file
|
(db/update! cfg :file
|
||||||
{:revn (inc (:revn file))
|
{:revn (inc (:revn file))
|
||||||
:data (blob/encode (:data file))
|
:data (blob/encode (:data file))
|
||||||
:modified-at (dt/now)
|
:modified-at (ct/now)
|
||||||
:has-media-trimmed false}
|
:has-media-trimmed false}
|
||||||
{:id file-id})
|
{:id file-id})
|
||||||
|
|
||||||
@@ -900,7 +900,7 @@
|
|||||||
(db/delete! conn :file-library-rel {:library-file-id id})
|
(db/delete! conn :file-library-rel {:library-file-id id})
|
||||||
(db/update! conn :file
|
(db/update! conn :file
|
||||||
{:is-shared false
|
{:is-shared false
|
||||||
:modified-at (dt/now)}
|
:modified-at (ct/now)}
|
||||||
{:id id})
|
{:id id})
|
||||||
(select-keys file [:id :name :is-shared]))
|
(select-keys file [:id :name :is-shared]))
|
||||||
|
|
||||||
@@ -909,7 +909,7 @@
|
|||||||
(let [file (assoc file :is-shared true)]
|
(let [file (assoc file :is-shared true)]
|
||||||
(db/update! conn :file
|
(db/update! conn :file
|
||||||
{:is-shared true
|
{:is-shared true
|
||||||
:modified-at (dt/now)}
|
:modified-at (ct/now)}
|
||||||
{:id id})
|
{:id id})
|
||||||
file)
|
file)
|
||||||
|
|
||||||
@@ -945,7 +945,7 @@
|
|||||||
[conn team file-id]
|
[conn team file-id]
|
||||||
(let [delay (ldel/get-deletion-delay team)
|
(let [delay (ldel/get-deletion-delay team)
|
||||||
file (db/update! conn :file
|
file (db/update! conn :file
|
||||||
{:deleted-at (dt/in-future delay)}
|
{:deleted-at (ct/in-future delay)}
|
||||||
{:id file-id}
|
{:id file-id}
|
||||||
{::db/return-keys [:id :name :is-shared :deleted-at
|
{::db/return-keys [:id :name :is-shared :deleted-at
|
||||||
:project-id :created-at :modified-at]})]
|
:project-id :created-at :modified-at]})]
|
||||||
@@ -1043,7 +1043,7 @@
|
|||||||
(defn update-sync
|
(defn update-sync
|
||||||
[conn {:keys [file-id library-id] :as params}]
|
[conn {:keys [file-id library-id] :as params}]
|
||||||
(db/update! conn :file-library-rel
|
(db/update! conn :file-library-rel
|
||||||
{:synced-at (dt/now)}
|
{:synced-at (ct/now)}
|
||||||
{:file-id file-id
|
{:file-id file-id
|
||||||
:library-file-id library-id}
|
:library-file-id library-id}
|
||||||
{::db/return-keys true}))
|
{::db/return-keys true}))
|
||||||
@@ -1068,14 +1068,14 @@
|
|||||||
[conn {:keys [file-id date] :as params}]
|
[conn {:keys [file-id date] :as params}]
|
||||||
(db/update! conn :file
|
(db/update! conn :file
|
||||||
{:ignore-sync-until date
|
{:ignore-sync-until date
|
||||||
:modified-at (dt/now)}
|
:modified-at (ct/now)}
|
||||||
{:id file-id}
|
{:id file-id}
|
||||||
{::db/return-keys true}))
|
{::db/return-keys true}))
|
||||||
|
|
||||||
(def ^:private schema:ignore-file-library-sync-status
|
(def ^:private schema:ignore-file-library-sync-status
|
||||||
[:map {:title "ignore-file-library-sync-status"}
|
[:map {:title "ignore-file-library-sync-status"}
|
||||||
[:file-id ::sm/uuid]
|
[:file-id ::sm/uuid]
|
||||||
[:date ::dt/instant]])
|
[:date ::ct/inst]])
|
||||||
|
|
||||||
;; TODO: improve naming
|
;; TODO: improve naming
|
||||||
(sv/defmethod ::ignore-file-library-sync-status
|
(sv/defmethod ::ignore-file-library-sync-status
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
[app.binfile.common :as bfc]
|
[app.binfile.common :as bfc]
|
||||||
[app.common.features :as cfeat]
|
[app.common.features :as cfeat]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.file :as ctf]
|
[app.common.types.file :as ctf]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -22,7 +23,6 @@
|
|||||||
[app.rpc.quotes :as quotes]
|
[app.rpc.quotes :as quotes]
|
||||||
[app.util.pointer-map :as pmap]
|
[app.util.pointer-map :as pmap]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[clojure.set :as set]))
|
[clojure.set :as set]))
|
||||||
|
|
||||||
(defn create-file-role!
|
(defn create-file-role!
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
(create-file-role! conn))
|
(create-file-role! conn))
|
||||||
|
|
||||||
(db/update! conn :project
|
(db/update! conn :project
|
||||||
{:modified-at (dt/now)}
|
{:modified-at (ct/now)}
|
||||||
{:id project-id})
|
{:id project-id})
|
||||||
|
|
||||||
file)))
|
file)))
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
[app.common.files.migrations :as fmg]
|
[app.common.files.migrations :as fmg]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -26,7 +27,6 @@
|
|||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.util.blob :as blob]
|
[app.util.blob :as blob]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
(defn decode-row
|
(defn decode-row
|
||||||
@@ -69,8 +69,8 @@
|
|||||||
|
|
||||||
(defn- generate-snapshot-label
|
(defn- generate-snapshot-label
|
||||||
[]
|
[]
|
||||||
(let [ts (-> (dt/now)
|
(let [ts (-> (ct/now)
|
||||||
(dt/format-instant)
|
(ct/format-inst)
|
||||||
(str/replace #"[T:\.]" "-")
|
(str/replace #"[T:\.]" "-")
|
||||||
(str/rtrim "Z"))]
|
(str/rtrim "Z"))]
|
||||||
(str "snapshot-" ts)))
|
(str "snapshot-" ts)))
|
||||||
@@ -89,9 +89,9 @@
|
|||||||
deleted-at
|
deleted-at
|
||||||
(cond
|
(cond
|
||||||
(= deleted-at :default)
|
(= deleted-at :default)
|
||||||
(dt/plus (dt/now) (cf/get-deletion-delay))
|
(ct/plus (ct/now) (cf/get-deletion-delay))
|
||||||
|
|
||||||
(dt/instant? deleted-at)
|
(ct/inst? deleted-at)
|
||||||
deleted-at
|
deleted-at
|
||||||
|
|
||||||
:else
|
:else
|
||||||
@@ -304,7 +304,7 @@
|
|||||||
(defn- delete-file-snapshot!
|
(defn- delete-file-snapshot!
|
||||||
[conn snapshot-id]
|
[conn snapshot-id]
|
||||||
(db/update! conn :file-change
|
(db/update! conn :file-change
|
||||||
{:deleted-at (dt/now)}
|
{:deleted-at (ct/now)}
|
||||||
{:id snapshot-id}
|
{:id snapshot-id}
|
||||||
{::db/return-keys false})
|
{::db/return-keys false})
|
||||||
nil)
|
nil)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
[app.common.features :as cfeat]
|
[app.common.features :as cfeat]
|
||||||
[app.common.files.changes :as cpc]
|
[app.common.files.changes :as cpc]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -27,7 +28,6 @@
|
|||||||
[app.util.blob :as blob]
|
[app.util.blob :as blob]
|
||||||
[app.util.pointer-map :as pmap]
|
[app.util.pointer-map :as pmap]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[clojure.set :as set]))
|
[clojure.set :as set]))
|
||||||
|
|
||||||
;; --- MUTATION COMMAND: create-temp-file
|
;; --- MUTATION COMMAND: create-temp-file
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
params
|
params
|
||||||
(-> params
|
(-> params
|
||||||
(assoc :profile-id profile-id)
|
(assoc :profile-id profile-id)
|
||||||
(assoc :deleted-at (dt/in-future {:days 1}))
|
(assoc :deleted-at (ct/in-future {:days 1}))
|
||||||
(assoc :features features))]
|
(assoc :features features))]
|
||||||
|
|
||||||
(files.create/create-file cfg params)))
|
(files.create/create-file cfg params)))
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
{:id (uuid/next)
|
{:id (uuid/next)
|
||||||
:session-id session-id
|
:session-id session-id
|
||||||
:profile-id profile-id
|
:profile-id profile-id
|
||||||
:created-at (dt/now)
|
:created-at (ct/now)
|
||||||
:file-id id
|
:file-id id
|
||||||
:revn revn
|
:revn revn
|
||||||
:data nil
|
:data nil
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.thumbnails :as thc]
|
[app.common.thumbnails :as thc]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.shape-tree :as ctt]
|
[app.common.types.shape-tree :as ctt]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -30,13 +31,12 @@
|
|||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.util.pointer-map :as pmap]
|
[app.util.pointer-map :as pmap]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
;; --- FEATURES
|
;; --- FEATURES
|
||||||
|
|
||||||
(def long-cache-duration
|
(def long-cache-duration
|
||||||
(dt/duration {:days 7}))
|
(ct/duration {:days 7}))
|
||||||
|
|
||||||
;; --- COMMAND QUERY: get-file-object-thumbnails
|
;; --- COMMAND QUERY: get-file-object-thumbnails
|
||||||
|
|
||||||
@@ -247,7 +247,7 @@
|
|||||||
(defn- create-file-object-thumbnail!
|
(defn- create-file-object-thumbnail!
|
||||||
[{:keys [::sto/storage] :as cfg} file object-id media tag]
|
[{:keys [::sto/storage] :as cfg} file object-id media tag]
|
||||||
(let [file-id (:id file)
|
(let [file-id (:id file)
|
||||||
timestamp (dt/now)
|
timestamp (ct/now)
|
||||||
media (persist-thumbnail! storage media timestamp)
|
media (persist-thumbnail! storage media timestamp)
|
||||||
[th1 th2] (db/tx-run! cfg (fn [{:keys [::db/conn]}]
|
[th1 th2] (db/tx-run! cfg (fn [{:keys [::db/conn]}]
|
||||||
(let [th1 (db/exec-one! conn [sql:get-file-object-thumbnail file-id object-id tag])
|
(let [th1 (db/exec-one! conn [sql:get-file-object-thumbnail file-id object-id tag])
|
||||||
@@ -302,7 +302,7 @@
|
|||||||
{::sql/for-update true})]
|
{::sql/for-update true})]
|
||||||
(sto/touch-object! storage media-id)
|
(sto/touch-object! storage media-id)
|
||||||
(db/update! conn :file-tagged-object-thumbnail
|
(db/update! conn :file-tagged-object-thumbnail
|
||||||
{:deleted-at (dt/now)}
|
{:deleted-at (ct/now)}
|
||||||
{:file-id file-id
|
{:file-id file-id
|
||||||
:object-id object-id
|
:object-id object-id
|
||||||
:tag tag})))
|
:tag tag})))
|
||||||
@@ -338,7 +338,7 @@
|
|||||||
hash (sto/calculate-hash path)
|
hash (sto/calculate-hash path)
|
||||||
data (-> (sto/content path)
|
data (-> (sto/content path)
|
||||||
(sto/wrap-with-hash hash))
|
(sto/wrap-with-hash hash))
|
||||||
tnow (dt/now)
|
tnow (ct/now)
|
||||||
media (sto/put-object! storage
|
media (sto/put-object! storage
|
||||||
{::sto/content data
|
{::sto/content data
|
||||||
::sto/deduplicate? true
|
::sto/deduplicate? true
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
[app.common.files.validate :as val]
|
[app.common.files.validate :as val]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -36,7 +37,6 @@
|
|||||||
[app.util.blob :as blob]
|
[app.util.blob :as blob]
|
||||||
[app.util.pointer-map :as pmap]
|
[app.util.pointer-map :as pmap]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[promesa.exec :as px]))
|
[promesa.exec :as px]))
|
||||||
@@ -123,7 +123,7 @@
|
|||||||
[:update-file/global]]
|
[:update-file/global]]
|
||||||
|
|
||||||
::webhooks/event? true
|
::webhooks/event? true
|
||||||
::webhooks/batch-timeout (dt/duration "2m")
|
::webhooks/batch-timeout (ct/duration "2m")
|
||||||
::webhooks/batch-key (webhooks/key-fn ::rpc/profile-id :id)
|
::webhooks/batch-key (webhooks/key-fn ::rpc/profile-id :id)
|
||||||
|
|
||||||
::sm/params schema:update-file
|
::sm/params schema:update-file
|
||||||
@@ -156,9 +156,9 @@
|
|||||||
(assoc :file file)
|
(assoc :file file)
|
||||||
(assoc :changes changes))
|
(assoc :changes changes))
|
||||||
|
|
||||||
cfg (assoc cfg ::timestamp (dt/now))
|
cfg (assoc cfg ::timestamp (ct/now))
|
||||||
|
|
||||||
tpoint (dt/tpoint)]
|
tpoint (ct/tpoint)]
|
||||||
|
|
||||||
|
|
||||||
(when (not= (:vern params)
|
(when (not= (:vern params)
|
||||||
@@ -199,7 +199,7 @@
|
|||||||
(errors/request->context))]
|
(errors/request->context))]
|
||||||
(-> (update-file* cfg params)
|
(-> (update-file* cfg params)
|
||||||
(rph/with-defer #(let [elapsed (tpoint)]
|
(rph/with-defer #(let [elapsed (tpoint)]
|
||||||
(l/trace :hint "update-file" :time (dt/format-duration elapsed))))))))))
|
(l/trace :hint "update-file" :time (ct/format-duration elapsed))))))))))
|
||||||
|
|
||||||
(defn- update-file*
|
(defn- update-file*
|
||||||
"Internal function, part of the update-file process, that encapsulates
|
"Internal function, part of the update-file process, that encapsulates
|
||||||
@@ -244,8 +244,8 @@
|
|||||||
:created-at timestamp
|
:created-at timestamp
|
||||||
:updated-at timestamp
|
:updated-at timestamp
|
||||||
:deleted-at (if (::snapshot-data file)
|
:deleted-at (if (::snapshot-data file)
|
||||||
(dt/plus timestamp (ldel/get-deletion-delay team))
|
(ct/plus timestamp (ldel/get-deletion-delay team))
|
||||||
(dt/plus timestamp (dt/duration {:hours 1})))
|
(ct/plus timestamp (ct/duration {:hours 1})))
|
||||||
:file-id (:id file)
|
:file-id (:id file)
|
||||||
:revn (:revn file)
|
:revn (:revn file)
|
||||||
:version (:version file)
|
:version (:version file)
|
||||||
@@ -306,7 +306,7 @@
|
|||||||
[{:keys [::db/conn ::timestamp]} file]
|
[{:keys [::db/conn ::timestamp]} file]
|
||||||
(let [;; The timestamp can be nil because this function is also
|
(let [;; The timestamp can be nil because this function is also
|
||||||
;; intended to be used outside of this module
|
;; intended to be used outside of this module
|
||||||
modified-at (or timestamp (dt/now))]
|
modified-at (or timestamp (ct/now))]
|
||||||
|
|
||||||
(db/update! conn :project
|
(db/update! conn :project
|
||||||
{:modified-at modified-at}
|
{:modified-at modified-at}
|
||||||
@@ -360,7 +360,7 @@
|
|||||||
;; TODO: reuse operations if file is migrated
|
;; TODO: reuse operations if file is migrated
|
||||||
;; TODO: move encoding to a separated thread
|
;; TODO: move encoding to a separated thread
|
||||||
file (if (take-snapshot? file)
|
file (if (take-snapshot? file)
|
||||||
(let [tpoint (dt/tpoint)
|
(let [tpoint (ct/tpoint)
|
||||||
snapshot (-> (:data file)
|
snapshot (-> (:data file)
|
||||||
(feat.fdata/process-pointers deref)
|
(feat.fdata/process-pointers deref)
|
||||||
(feat.fdata/process-objects (partial into {}))
|
(feat.fdata/process-objects (partial into {}))
|
||||||
@@ -372,7 +372,7 @@
|
|||||||
:file-id (str (:id file))
|
:file-id (str (:id file))
|
||||||
:revn (:revn file)
|
:revn (:revn file)
|
||||||
:label label
|
:label label
|
||||||
:elapsed (dt/format-duration elapsed))
|
:elapsed (ct/format-duration elapsed))
|
||||||
|
|
||||||
(-> file
|
(-> file
|
||||||
(assoc ::snapshot-data snapshot)
|
(assoc ::snapshot-data snapshot)
|
||||||
@@ -452,11 +452,11 @@
|
|||||||
(when (contains? cf/flags :auto-file-snapshot)
|
(when (contains? cf/flags :auto-file-snapshot)
|
||||||
(let [freq (or (cf/get :auto-file-snapshot-every) 20)
|
(let [freq (or (cf/get :auto-file-snapshot-every) 20)
|
||||||
timeout (or (cf/get :auto-file-snapshot-timeout)
|
timeout (or (cf/get :auto-file-snapshot-timeout)
|
||||||
(dt/duration {:hours 1}))]
|
(ct/duration {:hours 1}))]
|
||||||
|
|
||||||
(or (= 1 freq)
|
(or (= 1 freq)
|
||||||
(zero? (mod revn freq))
|
(zero? (mod revn freq))
|
||||||
(> (inst-ms (dt/diff modified-at (dt/now)))
|
(> (inst-ms (ct/diff modified-at (ct/now)))
|
||||||
(inst-ms timeout))))))
|
(inst-ms timeout))))))
|
||||||
|
|
||||||
(def ^:private sql:lagged-changes
|
(def ^:private sql:lagged-changes
|
||||||
@@ -496,5 +496,5 @@
|
|||||||
:file-id (:id file)
|
:file-id (:id file)
|
||||||
:session-id session-id
|
:session-id session-id
|
||||||
:revn (:revn file)
|
:revn (:revn file)
|
||||||
:modified-at (dt/now)
|
:modified-at (ct/now)
|
||||||
:changes lchanges}))))
|
:changes lchanges}))))
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.db.sql :as-alias sql]
|
[app.db.sql :as-alias sql]
|
||||||
@@ -26,7 +27,6 @@
|
|||||||
[app.rpc.quotes :as quotes]
|
[app.rpc.quotes :as quotes]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as-alias wrk]
|
[app.worker :as-alias wrk]
|
||||||
[promesa.exec :as px]))
|
[promesa.exec :as px]))
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@
|
|||||||
content (-> (sto/content resource)
|
content (-> (sto/content resource)
|
||||||
(sto/wrap-with-hash hash))]
|
(sto/wrap-with-hash hash))]
|
||||||
{::sto/content content
|
{::sto/content content
|
||||||
::sto/touched-at (dt/now)
|
::sto/touched-at (ct/now)
|
||||||
::sto/deduplicate? true
|
::sto/deduplicate? true
|
||||||
:content-type mtype
|
:content-type mtype
|
||||||
:bucket "team-font-variant"})))
|
:bucket "team-font-variant"})))
|
||||||
@@ -217,7 +217,7 @@
|
|||||||
{::sql/for-update true})
|
{::sql/for-update true})
|
||||||
|
|
||||||
delay (ldel/get-deletion-delay team)
|
delay (ldel/get-deletion-delay team)
|
||||||
tnow (dt/in-future delay)]
|
tnow (ct/in-future delay)]
|
||||||
|
|
||||||
(teams/check-edition-permissions! (:permissions team))
|
(teams/check-edition-permissions! (:permissions team))
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@
|
|||||||
|
|
||||||
(teams/check-edition-permissions! (:permissions team))
|
(teams/check-edition-permissions! (:permissions team))
|
||||||
(db/update! conn :team-font-variant
|
(db/update! conn :team-font-variant
|
||||||
{:deleted-at (dt/in-future delay)}
|
{:deleted-at (ct/in-future delay)}
|
||||||
{:id (:id variant)}
|
{:id (:id variant)}
|
||||||
{::db/return-keys false})
|
{::db/return-keys false})
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.features :as cfeat]
|
[app.common.features :as cfeat]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -28,7 +29,6 @@
|
|||||||
[app.setup.templates :as tmpl]
|
[app.setup.templates :as tmpl]
|
||||||
[app.storage.tmp :as tmp]
|
[app.storage.tmp :as tmp]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as-alias wrk]
|
[app.worker :as-alias wrk]
|
||||||
[promesa.exec :as px]))
|
[promesa.exec :as px]))
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
(db/exec-one! conn ["SET CONSTRAINTS ALL DEFERRED"])
|
(db/exec-one! conn ["SET CONSTRAINTS ALL DEFERRED"])
|
||||||
|
|
||||||
(binding [bfc/*state* (volatile! {:index {file-id (uuid/next)}})]
|
(binding [bfc/*state* (volatile! {:index {file-id (uuid/next)}})]
|
||||||
(duplicate-file (assoc cfg ::bfc/timestamp (dt/now))
|
(duplicate-file (assoc cfg ::bfc/timestamp (ct/now))
|
||||||
(-> params
|
(-> params
|
||||||
(assoc :profile-id profile-id)
|
(assoc :profile-id profile-id)
|
||||||
(assoc :reset-shared-flag true)))))))
|
(assoc :reset-shared-flag true)))))))
|
||||||
@@ -164,7 +164,7 @@
|
|||||||
(db/tx-run! cfg (fn [cfg]
|
(db/tx-run! cfg (fn [cfg]
|
||||||
;; Defer all constraints
|
;; Defer all constraints
|
||||||
(db/exec-one! cfg ["SET CONSTRAINTS ALL DEFERRED"])
|
(db/exec-one! cfg ["SET CONSTRAINTS ALL DEFERRED"])
|
||||||
(-> (assoc cfg ::bfc/timestamp (dt/now))
|
(-> (assoc cfg ::bfc/timestamp (ct/now))
|
||||||
(duplicate-project (assoc params :profile-id profile-id))))))
|
(duplicate-project (assoc params :profile-id profile-id))))))
|
||||||
|
|
||||||
(defn duplicate-team
|
(defn duplicate-team
|
||||||
@@ -320,7 +320,7 @@
|
|||||||
;; trully different modification date to each file.
|
;; trully different modification date to each file.
|
||||||
(px/sleep 10)
|
(px/sleep 10)
|
||||||
(db/update! conn :project
|
(db/update! conn :project
|
||||||
{:modified-at (dt/now)}
|
{:modified-at (ct/now)}
|
||||||
{:id project-id}))
|
{:id project-id}))
|
||||||
|
|
||||||
nil))
|
nil))
|
||||||
@@ -425,7 +425,7 @@
|
|||||||
(db/tx-run! cfg
|
(db/tx-run! cfg
|
||||||
(fn [{:keys [::db/conn] :as cfg}]
|
(fn [{:keys [::db/conn] :as cfg}]
|
||||||
(db/update! conn :project
|
(db/update! conn :project
|
||||||
{:modified-at (dt/now)}
|
{:modified-at (ct/now)}
|
||||||
{:id project-id}
|
{:id project-id}
|
||||||
{::db/return-keys false})
|
{::db/return-keys false})
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.media :as cm]
|
[app.common.media :as cm]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -23,7 +24,6 @@
|
|||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.storage.tmp :as tmp]
|
[app.storage.tmp :as tmp]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as-alias wrk]
|
[app.worker :as-alias wrk]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[datoteka.io :as io]
|
[datoteka.io :as io]
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
mobj (create-file-media-object cfg params)]
|
mobj (create-file-media-object cfg params)]
|
||||||
|
|
||||||
(db/update! conn :file
|
(db/update! conn :file
|
||||||
{:modified-at (dt/now)
|
{:modified-at (ct/now)
|
||||||
:has-media-trimmed false}
|
:has-media-trimmed false}
|
||||||
{:id file-id}
|
{:id file-id}
|
||||||
{::db/return-keys false})
|
{::db/return-keys false})
|
||||||
@@ -192,7 +192,7 @@
|
|||||||
mobj (create-file-media-object-from-url cfg (assoc params :profile-id profile-id))]
|
mobj (create-file-media-object-from-url cfg (assoc params :profile-id profile-id))]
|
||||||
|
|
||||||
(db/update! pool :file
|
(db/update! pool :file
|
||||||
{:modified-at (dt/now)
|
{:modified-at (ct/now)
|
||||||
:has-media-trimmed false}
|
:has-media-trimmed false}
|
||||||
{:id file-id}
|
{:id file-id}
|
||||||
{::db/return-keys false})
|
{::db/return-keys false})
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.plugins :refer [schema:plugin-registry]]
|
[app.common.types.plugins :refer [schema:plugin-registry]]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
@@ -28,7 +29,6 @@
|
|||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.tokens :as tokens]
|
[app.tokens :as tokens]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[promesa.exec :as px]))
|
[promesa.exec :as px]))
|
||||||
@@ -70,8 +70,8 @@
|
|||||||
[:is-blocked {:optional true} ::sm/boolean]
|
[:is-blocked {:optional true} ::sm/boolean]
|
||||||
[:is-demo {:optional true} ::sm/boolean]
|
[:is-demo {:optional true} ::sm/boolean]
|
||||||
[:is-muted {:optional true} ::sm/boolean]
|
[:is-muted {:optional true} ::sm/boolean]
|
||||||
[:created-at {:optional true} ::sm/inst]
|
[:created-at {:optional true} ::ct/inst]
|
||||||
[:modified-at {:optional true} ::sm/inst]
|
[:modified-at {:optional true} ::ct/inst]
|
||||||
[:default-project-id {:optional true} ::sm/uuid]
|
[:default-project-id {:optional true} ::sm/uuid]
|
||||||
[:default-team-id {:optional true} ::sm/uuid]
|
[:default-team-id {:optional true} ::sm/uuid]
|
||||||
[:props {:optional true} schema:props]])
|
[:props {:optional true} schema:props]])
|
||||||
@@ -352,13 +352,13 @@
|
|||||||
[{:keys [::db/conn] :as cfg} {:keys [profile email] :as params}]
|
[{:keys [::db/conn] :as cfg} {:keys [profile email] :as params}]
|
||||||
(let [token (tokens/generate (::setup/props cfg)
|
(let [token (tokens/generate (::setup/props cfg)
|
||||||
{:iss :change-email
|
{:iss :change-email
|
||||||
:exp (dt/in-future "15m")
|
:exp (ct/in-future "15m")
|
||||||
:profile-id (:id profile)
|
:profile-id (:id profile)
|
||||||
:email email})
|
:email email})
|
||||||
ptoken (tokens/generate (::setup/props cfg)
|
ptoken (tokens/generate (::setup/props cfg)
|
||||||
{:iss :profile-identity
|
{:iss :profile-identity
|
||||||
:profile-id (:id profile)
|
:profile-id (:id profile)
|
||||||
:exp (dt/in-future {:days 30})})]
|
:exp (ct/in-future {:days 30})})]
|
||||||
|
|
||||||
(when (not= email (:email profile))
|
(when (not= email (:email profile))
|
||||||
(check-profile-existence! conn params))
|
(check-profile-existence! conn params))
|
||||||
@@ -444,7 +444,7 @@
|
|||||||
::db/transaction true}
|
::db/transaction true}
|
||||||
[{:keys [::db/conn] :as cfg} {:keys [::rpc/profile-id] :as params}]
|
[{:keys [::db/conn] :as cfg} {:keys [::rpc/profile-id] :as params}]
|
||||||
(let [teams (get-owned-teams conn profile-id)
|
(let [teams (get-owned-teams conn profile-id)
|
||||||
deleted-at (dt/now)]
|
deleted-at (ct/now)]
|
||||||
|
|
||||||
;; If we found owned teams with participants, we don't allow
|
;; If we found owned teams with participants, we don't allow
|
||||||
;; delete profile until the user properly transfer ownership or
|
;; delete profile until the user properly transfer ownership or
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.db.sql :as-alias sql]
|
[app.db.sql :as-alias sql]
|
||||||
[app.features.logical-deletion :as ldel]
|
[app.features.logical-deletion :as ldel]
|
||||||
@@ -21,7 +22,6 @@
|
|||||||
[app.rpc.permissions :as perms]
|
[app.rpc.permissions :as perms]
|
||||||
[app.rpc.quotes :as quotes]
|
[app.rpc.quotes :as quotes]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]))
|
[app.worker :as wrk]))
|
||||||
|
|
||||||
;; --- Check Project Permissions
|
;; --- Check Project Permissions
|
||||||
@@ -218,7 +218,7 @@
|
|||||||
(sv/defmethod ::update-project-pin
|
(sv/defmethod ::update-project-pin
|
||||||
{::doc/added "1.18"
|
{::doc/added "1.18"
|
||||||
::sm/params schema:update-project-pin
|
::sm/params schema:update-project-pin
|
||||||
::webhooks/batch-timeout (dt/duration "5s")
|
::webhooks/batch-timeout (ct/duration "5s")
|
||||||
::webhooks/batch-key (webhooks/key-fn ::rpc/profile-id :id)
|
::webhooks/batch-key (webhooks/key-fn ::rpc/profile-id :id)
|
||||||
::webhooks/event? true
|
::webhooks/event? true
|
||||||
::db/transaction true}
|
::db/transaction true}
|
||||||
@@ -257,7 +257,7 @@
|
|||||||
[conn team project-id]
|
[conn team project-id]
|
||||||
(let [delay (ldel/get-deletion-delay team)
|
(let [delay (ldel/get-deletion-delay team)
|
||||||
project (db/update! conn :project
|
project (db/update! conn :project
|
||||||
{:deleted-at (dt/in-future delay)}
|
{:deleted-at (ct/in-future delay)}
|
||||||
{:id project-id}
|
{:id project-id}
|
||||||
{::db/return-keys true})]
|
{::db/return-keys true})]
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.features :as cfeat]
|
[app.common.features :as cfeat]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.team :as tt]
|
[app.common.types.team :as tt]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
@@ -30,7 +31,6 @@
|
|||||||
[app.setup :as-alias setup]
|
[app.setup :as-alias setup]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[clojure.set :as set]))
|
[clojure.set :as set]))
|
||||||
|
|
||||||
@@ -666,7 +666,7 @@
|
|||||||
|
|
||||||
(let [delay (ldel/get-deletion-delay team)
|
(let [delay (ldel/get-deletion-delay team)
|
||||||
team (db/update! conn :team
|
team (db/update! conn :team
|
||||||
{:deleted-at (dt/in-future delay)}
|
{:deleted-at (ct/in-future delay)}
|
||||||
{:id id}
|
{:id id}
|
||||||
{::db/return-keys true})]
|
{::db/return-keys true})]
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
[app.common.features :as cfeat]
|
[app.common.features :as cfeat]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.team :as types.team]
|
[app.common.types.team :as types.team]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
@@ -29,7 +30,6 @@
|
|||||||
[app.setup :as-alias setup]
|
[app.setup :as-alias setup]
|
||||||
[app.tokens :as tokens]
|
[app.tokens :as tokens]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
;; --- Mutation: Create Team Invitation
|
;; --- Mutation: Create Team Invitation
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
(tokens/generate (::setup/props cfg)
|
(tokens/generate (::setup/props cfg)
|
||||||
{:iss :profile-identity
|
{:iss :profile-identity
|
||||||
:profile-id profile-id
|
:profile-id profile-id
|
||||||
:exp (dt/in-future {:days 30})}))
|
:exp (ct/in-future {:days 30})}))
|
||||||
|
|
||||||
(def ^:private schema:create-invitation
|
(def ^:private schema:create-invitation
|
||||||
[:map {:title "params:create-invitation"}
|
[:map {:title "params:create-invitation"}
|
||||||
@@ -126,7 +126,7 @@
|
|||||||
(teams/check-email-spam conn email true)
|
(teams/check-email-spam conn email true)
|
||||||
|
|
||||||
(let [id (uuid/next)
|
(let [id (uuid/next)
|
||||||
expire (dt/in-future "168h") ;; 7 days
|
expire (ct/in-future "168h") ;; 7 days
|
||||||
invitation (db/exec-one! conn [sql:upsert-team-invitation id
|
invitation (db/exec-one! conn [sql:upsert-team-invitation id
|
||||||
(:id team) (str/lower email)
|
(:id team) (str/lower email)
|
||||||
(:id profile)
|
(:id profile)
|
||||||
@@ -418,7 +418,7 @@
|
|||||||
:code :insufficient-permissions))
|
:code :insufficient-permissions))
|
||||||
|
|
||||||
(db/update! conn :team-invitation
|
(db/update! conn :team-invitation
|
||||||
{:role (name role) :updated-at (dt/now)}
|
{:role (name role) :updated-at (ct/now)}
|
||||||
{:team-id team-id :email-to (profile/clean-email email)})
|
{:team-id team-id :email-to (profile/clean-email email)})
|
||||||
|
|
||||||
nil))
|
nil))
|
||||||
@@ -471,7 +471,7 @@
|
|||||||
(when-let [request (db/get* conn :team-access-request
|
(when-let [request (db/get* conn :team-access-request
|
||||||
{:team-id team-id
|
{:team-id team-id
|
||||||
:requester-id profile-id})]
|
:requester-id profile-id})]
|
||||||
(when (dt/is-after? (:valid-until request) (dt/now))
|
(when (ct/is-after? (:valid-until request) (ct/now))
|
||||||
(ex/raise :type :validation
|
(ex/raise :type :validation
|
||||||
:code :request-already-sent
|
:code :request-already-sent
|
||||||
:hint "you have already made a request to join this team less than 24 hours ago"))))
|
:hint "you have already made a request to join this team less than 24 hours ago"))))
|
||||||
@@ -487,8 +487,8 @@
|
|||||||
"Create or update team access request for provided team and profile-id"
|
"Create or update team access request for provided team and profile-id"
|
||||||
[conn team-id requester-id]
|
[conn team-id requester-id]
|
||||||
(check-existing-team-access-request conn team-id requester-id)
|
(check-existing-team-access-request conn team-id requester-id)
|
||||||
(let [valid-until (dt/in-future {:hours 24})
|
(let [valid-until (ct/in-future {:hours 24})
|
||||||
auto-join-until (dt/in-future {:days 7})
|
auto-join-until (ct/in-future {:days 7})
|
||||||
request-id (uuid/next)]
|
request-id (uuid/next)]
|
||||||
(db/exec-one! conn [sql:upsert-team-access-request
|
(db/exec-one! conn [sql:upsert-team-access-request
|
||||||
request-id team-id requester-id
|
request-id team-id requester-id
|
||||||
|
|||||||
@@ -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.common.time :as ct]
|
||||||
[app.common.types.team :as types.team]
|
[app.common.types.team :as types.team]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -23,8 +24,7 @@
|
|||||||
[app.setup :as-alias setup]
|
[app.setup :as-alias setup]
|
||||||
[app.tokens :as tokens]
|
[app.tokens :as tokens]
|
||||||
[app.tokens.spec.team-invitation :as-alias spec.team-invitation]
|
[app.tokens.spec.team-invitation :as-alias spec.team-invitation]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]))
|
||||||
[app.util.time :as dt]))
|
|
||||||
|
|
||||||
(defmulti process-token (fn [_ _ claims] (:iss claims)))
|
(defmulti process-token (fn [_ _ claims] (:iss claims)))
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@
|
|||||||
(def schema:team-invitation-claims
|
(def schema:team-invitation-claims
|
||||||
[:map {:title "TeamInvitationClaims"}
|
[:map {:title "TeamInvitationClaims"}
|
||||||
[:iss :keyword]
|
[:iss :keyword]
|
||||||
[:exp ::dt/instant]
|
[:exp ::ct/inst]
|
||||||
[:profile-id ::sm/uuid]
|
[:profile-id ::sm/uuid]
|
||||||
[:role ::types.team/role]
|
[:role ::types.team/role]
|
||||||
[:team-id ::sm/uuid]
|
[:team-id ::sm/uuid]
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uri :as u]
|
[app.common.uri :as u]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -19,7 +20,6 @@
|
|||||||
[app.rpc.doc :as-alias doc]
|
[app.rpc.doc :as-alias doc]
|
||||||
[app.rpc.permissions :as perms]
|
[app.rpc.permissions :as perms]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
(defn get-webhooks-permissions
|
(defn get-webhooks-permissions
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
(http/req! cfg
|
(http/req! cfg
|
||||||
{:method :head
|
{:method :head
|
||||||
:uri (str (:uri params))
|
:uri (str (:uri params))
|
||||||
:timeout (dt/duration "3s")}
|
:timeout (ct/duration "3s")}
|
||||||
{:sync? true}))]
|
{:sync? true}))]
|
||||||
(if (ex/exception? response)
|
(if (ex/exception? response)
|
||||||
(if-let [hint (webhooks/interpret-exception response)]
|
(if-let [hint (webhooks/interpret-exception response)]
|
||||||
|
|||||||
@@ -10,9 +10,9 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@
|
|||||||
"- Total: ~(::total params) (INCR ~(::incr params 1))\n")]
|
"- Total: ~(::total params) (INCR ~(::incr params 1))\n")]
|
||||||
(wrk/submit! {::db/conn conn
|
(wrk/submit! {::db/conn conn
|
||||||
::wrk/task :sendmail
|
::wrk/task :sendmail
|
||||||
::wrk/delay (dt/duration "30s")
|
::wrk/delay (ct/duration "30s")
|
||||||
::wrk/max-retries 4
|
::wrk/max-retries 4
|
||||||
::wrk/priority 200
|
::wrk/priority 200
|
||||||
::wrk/dedupe true
|
::wrk/dedupe true
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uri :as uri]
|
[app.common.uri :as uri]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
@@ -58,7 +59,6 @@
|
|||||||
[app.rpc.rlimit.result :as-alias lresult]
|
[app.rpc.rlimit.result :as-alias lresult]
|
||||||
[app.util.inet :as inet]
|
[app.util.inet :as inet]
|
||||||
[app.util.services :as-alias sv]
|
[app.util.services :as-alias sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[clojure.edn :as edn]
|
[clojure.edn :as edn]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
[promesa.exec :as px]))
|
[promesa.exec :as px]))
|
||||||
|
|
||||||
(def ^:private default-timeout
|
(def ^:private default-timeout
|
||||||
(dt/duration 400))
|
(ct/duration 400))
|
||||||
|
|
||||||
(def ^:private default-options
|
(def ^:private default-options
|
||||||
{:codec rds/string-codec
|
{:codec rds/string-codec
|
||||||
@@ -94,6 +94,10 @@
|
|||||||
(defmulti parse-limit (fn [[_ strategy _]] strategy))
|
(defmulti parse-limit (fn [[_ strategy _]] strategy))
|
||||||
(defmulti process-limit (fn [_ _ _ o] (::strategy o)))
|
(defmulti process-limit (fn [_ _ _ o] (::strategy o)))
|
||||||
|
|
||||||
|
(defn- ->seconds
|
||||||
|
[d]
|
||||||
|
(-> d inst-ms (/ 1000) int))
|
||||||
|
|
||||||
(sm/register!
|
(sm/register!
|
||||||
{:type ::rpc/rlimit
|
{:type ::rpc/rlimit
|
||||||
:pred #(instance? clojure.lang.Agent %)})
|
:pred #(instance? clojure.lang.Agent %)})
|
||||||
@@ -115,7 +119,7 @@
|
|||||||
[:map
|
[:map
|
||||||
[::capacity ::sm/int]
|
[::capacity ::sm/int]
|
||||||
[::rate ::sm/int]
|
[::rate ::sm/int]
|
||||||
[::internal ::dt/duration]
|
[::internal ::ct/duration]
|
||||||
[::params [::sm/vec :any]]]
|
[::params [::sm/vec :any]]]
|
||||||
[:map
|
[:map
|
||||||
[::nreq ::sm/int]
|
[::nreq ::sm/int]
|
||||||
@@ -157,7 +161,7 @@
|
|||||||
(assert (valid-limit-tuple? vlimit) "expected valid limit tuple")
|
(assert (valid-limit-tuple? vlimit) "expected valid limit tuple")
|
||||||
|
|
||||||
(if-let [[_ capacity rate interval] (re-find bucket-opts-re opts)]
|
(if-let [[_ capacity rate interval] (re-find bucket-opts-re opts)]
|
||||||
(let [interval (dt/duration interval)
|
(let [interval (ct/duration interval)
|
||||||
rate (parse-long rate)
|
rate (parse-long rate)
|
||||||
capacity (parse-long capacity)]
|
capacity (parse-long capacity)]
|
||||||
{::name name
|
{::name name
|
||||||
@@ -166,7 +170,7 @@
|
|||||||
::rate rate
|
::rate rate
|
||||||
::interval interval
|
::interval interval
|
||||||
::opts opts
|
::opts opts
|
||||||
::params [(dt/->seconds interval) rate capacity]
|
::params [(->seconds interval) rate capacity]
|
||||||
::key (str "ratelimit.bucket." (d/name name))})
|
::key (str "ratelimit.bucket." (d/name name))})
|
||||||
(ex/raise :type :validation
|
(ex/raise :type :validation
|
||||||
:code :invalid-bucket-limit-opts
|
:code :invalid-bucket-limit-opts
|
||||||
@@ -176,7 +180,7 @@
|
|||||||
[redis user-id now {:keys [::key ::params ::service ::capacity ::interval ::rate] :as limit}]
|
[redis user-id now {:keys [::key ::params ::service ::capacity ::interval ::rate] :as limit}]
|
||||||
(let [script (-> bucket-rate-limit-script
|
(let [script (-> bucket-rate-limit-script
|
||||||
(assoc ::rscript/keys [(str key "." service "." user-id)])
|
(assoc ::rscript/keys [(str key "." service "." user-id)])
|
||||||
(assoc ::rscript/vals (conj params (dt/->seconds now))))
|
(assoc ::rscript/vals (conj params (->seconds now))))
|
||||||
result (rds/eval redis script)
|
result (rds/eval redis script)
|
||||||
allowed? (boolean (nth result 0))
|
allowed? (boolean (nth result 0))
|
||||||
remaining (nth result 1)
|
remaining (nth result 1)
|
||||||
@@ -191,16 +195,16 @@
|
|||||||
:remaining remaining)
|
:remaining remaining)
|
||||||
(-> limit
|
(-> limit
|
||||||
(assoc ::lresult/allowed allowed?)
|
(assoc ::lresult/allowed allowed?)
|
||||||
(assoc ::lresult/reset (dt/plus now reset))
|
(assoc ::lresult/reset (ct/plus now reset))
|
||||||
(assoc ::lresult/remaining remaining))))
|
(assoc ::lresult/remaining remaining))))
|
||||||
|
|
||||||
(defmethod process-limit :window
|
(defmethod process-limit :window
|
||||||
[redis user-id now {:keys [::nreq ::unit ::key ::service] :as limit}]
|
[redis user-id now {:keys [::nreq ::unit ::key ::service] :as limit}]
|
||||||
(let [ts (dt/truncate now unit)
|
(let [ts (ct/truncate now unit)
|
||||||
ttl (dt/diff now (dt/plus ts {unit 1}))
|
ttl (ct/diff now (ct/plus ts {unit 1}))
|
||||||
script (-> window-rate-limit-script
|
script (-> window-rate-limit-script
|
||||||
(assoc ::rscript/keys [(str key "." service "." user-id "." (dt/format-instant ts))])
|
(assoc ::rscript/keys [(str key "." service "." user-id "." (ct/format-inst ts))])
|
||||||
(assoc ::rscript/vals [nreq (dt/->seconds ttl)]))
|
(assoc ::rscript/vals [nreq (->seconds ttl)]))
|
||||||
result (rds/eval redis script)
|
result (rds/eval redis script)
|
||||||
allowed? (boolean (nth result 0))
|
allowed? (boolean (nth result 0))
|
||||||
remaining (nth result 1)]
|
remaining (nth result 1)]
|
||||||
@@ -214,7 +218,7 @@
|
|||||||
(-> limit
|
(-> limit
|
||||||
(assoc ::lresult/allowed allowed?)
|
(assoc ::lresult/allowed allowed?)
|
||||||
(assoc ::lresult/remaining remaining)
|
(assoc ::lresult/remaining remaining)
|
||||||
(assoc ::lresult/reset (dt/plus ts {unit 1})))))
|
(assoc ::lresult/reset (ct/plus ts {unit 1})))))
|
||||||
|
|
||||||
(defn- process-limits!
|
(defn- process-limits!
|
||||||
[redis user-id limits now]
|
[redis user-id limits now]
|
||||||
@@ -223,7 +227,7 @@
|
|||||||
(d/index-by ::name ::lresult/remaining)
|
(d/index-by ::name ::lresult/remaining)
|
||||||
(uri/map->query-string))
|
(uri/map->query-string))
|
||||||
reset (->> results
|
reset (->> results
|
||||||
(d/index-by ::name (comp dt/->seconds ::lresult/reset))
|
(d/index-by ::name (comp ->seconds ::lresult/reset))
|
||||||
(uri/map->query-string))
|
(uri/map->query-string))
|
||||||
|
|
||||||
rejected (d/seek (complement ::lresult/allowed) results)]
|
rejected (d/seek (complement ::lresult/allowed) results)]
|
||||||
@@ -261,7 +265,7 @@
|
|||||||
(let [redis (rds/get-or-connect redis ::rpc/rlimit default-options)
|
(let [redis (rds/get-or-connect redis ::rpc/rlimit default-options)
|
||||||
uid (get-uid params)
|
uid (get-uid params)
|
||||||
;; FIXME: why not clasic try/catch?
|
;; FIXME: why not clasic try/catch?
|
||||||
result (ex/try! (process-limits! redis uid limits (dt/now)))]
|
result (ex/try! (process-limits! redis uid limits (ct/now)))]
|
||||||
|
|
||||||
(l/trc :hint "process-limits"
|
(l/trc :hint "process-limits"
|
||||||
:service sname
|
:service sname
|
||||||
@@ -321,7 +325,7 @@
|
|||||||
(sm/check-fn schema:config))
|
(sm/check-fn schema:config))
|
||||||
|
|
||||||
(def ^:private check-refresh
|
(def ^:private check-refresh
|
||||||
(sm/check-fn ::dt/duration))
|
(sm/check-fn ::ct/duration))
|
||||||
|
|
||||||
(def ^:private check-limits
|
(def ^:private check-limits
|
||||||
(sm/check-fn schema:limits))
|
(sm/check-fn schema:limits))
|
||||||
@@ -351,7 +355,7 @@
|
|||||||
config)))]
|
config)))]
|
||||||
|
|
||||||
(when-let [config (some->> path slurp edn/read-string check-config)]
|
(when-let [config (some->> path slurp edn/read-string check-config)]
|
||||||
(let [refresh (->> config meta :refresh dt/duration check-refresh)
|
(let [refresh (->> config meta :refresh ct/duration check-refresh)
|
||||||
limits (->> config compile-pass-1 compile-pass-2 check-limits)]
|
limits (->> config compile-pass-1 compile-pass-2 check-limits)]
|
||||||
|
|
||||||
{::refresh refresh
|
{::refresh refresh
|
||||||
@@ -410,7 +414,7 @@
|
|||||||
(l/info :hint "initializing rlimit config reader" :path (str path))
|
(l/info :hint "initializing rlimit config reader" :path (str path))
|
||||||
|
|
||||||
;; Initialize the state with initial refresh value
|
;; Initialize the state with initial refresh value
|
||||||
(send-via executor state (constantly {::refresh (dt/duration "5s")}))
|
(send-via executor state (constantly {::refresh (ct/duration "5s")}))
|
||||||
|
|
||||||
;; Force a refresh
|
;; Force a refresh
|
||||||
(refresh-config (assoc cfg ::path path ::state state)))
|
(refresh-config (assoc cfg ::path path ::state state)))
|
||||||
|
|||||||
@@ -11,11 +11,11 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.json :as json]
|
[app.common.json :as json]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.srepl.cli :as cli]
|
[app.srepl.cli :as cli]
|
||||||
[app.srepl.main]
|
[app.srepl.main]
|
||||||
[app.util.locks :as locks]
|
[app.util.locks :as locks]
|
||||||
[app.util.time :as dt]
|
|
||||||
[clojure.core :as c]
|
[clojure.core :as c]
|
||||||
[clojure.core.server :as ccs]
|
[clojure.core.server :as ccs]
|
||||||
[clojure.main :as cm]
|
[clojure.main :as cm]
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
(loop []
|
(loop []
|
||||||
(when (try
|
(when (try
|
||||||
(let [data (read-line)
|
(let [data (read-line)
|
||||||
tpoint (dt/tpoint)]
|
tpoint (ct/tpoint)]
|
||||||
|
|
||||||
(l/dbg :hint "received" :data (if (= data ::eof) "EOF" data))
|
(l/dbg :hint "received" :data (if (= data ::eof) "EOF" data))
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,14 @@
|
|||||||
[app.auth :as auth]
|
[app.auth :as auth]
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.schema.generators :as sg]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.rpc.commands.auth :as cmd.auth]
|
[app.rpc.commands.auth :as cmd.auth]
|
||||||
[app.rpc.commands.profile :as cmd.profile]
|
[app.rpc.commands.profile :as cmd.profile]
|
||||||
[app.setup :as-alias setup]
|
[app.setup :as-alias setup]
|
||||||
[app.tokens :as tokens]
|
[app.tokens :as tokens]
|
||||||
[app.util.time :as dt]
|
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
(defn coercer
|
(defn coercer
|
||||||
@@ -101,7 +102,7 @@
|
|||||||
(fn [{:keys [::db/conn] :as system}]
|
(fn [{:keys [::db/conn] :as system}]
|
||||||
(let [res (if soft
|
(let [res (if soft
|
||||||
(db/update! conn :profile
|
(db/update! conn :profile
|
||||||
{:deleted-at (dt/now)}
|
{:deleted-at (ct/now)}
|
||||||
{:email email :deleted-at nil})
|
{:email email :deleted-at nil})
|
||||||
(db/delete! conn :profile
|
(db/delete! conn :profile
|
||||||
{:email email}))]
|
{:email email}))]
|
||||||
@@ -173,6 +174,21 @@
|
|||||||
:num-editors (get-customer-slots system id)
|
:num-editors (get-customer-slots system id)
|
||||||
:subscription (get props :subscription)})))
|
:subscription (get props :subscription)})))
|
||||||
|
|
||||||
|
(def ^:private schema:timestamp
|
||||||
|
(sm/type-schema
|
||||||
|
{:type ::timestamp
|
||||||
|
:pred ct/inst?
|
||||||
|
:type-properties
|
||||||
|
{:title "inst"
|
||||||
|
:description "The same as :app.common.time/inst but encodes to epoch"
|
||||||
|
:error/message "should be an instant"
|
||||||
|
:gen/gen (->> (sg/small-int)
|
||||||
|
(sg/fmap (fn [v] (ct/inst v))))
|
||||||
|
:decode/string ct/inst
|
||||||
|
:encode/string inst-ms
|
||||||
|
:decode/json ct/inst
|
||||||
|
:encode/json inst-ms}}))
|
||||||
|
|
||||||
(def ^:private schema:customer-subscription
|
(def ^:private schema:customer-subscription
|
||||||
[:map {:title "CustomerSubscription"}
|
[:map {:title "CustomerSubscription"}
|
||||||
[:id ::sm/text]
|
[:id ::sm/text]
|
||||||
@@ -198,15 +214,15 @@
|
|||||||
"year"]]
|
"year"]]
|
||||||
[:quantity :int]
|
[:quantity :int]
|
||||||
[:description [:maybe ::sm/text]]
|
[:description [:maybe ::sm/text]]
|
||||||
[:created-at ::sm/timestamp]
|
[:created-at schema:timestamp]
|
||||||
[:start-date [:maybe ::sm/timestamp]]
|
[:start-date [:maybe schema:timestamp]]
|
||||||
[:ended-at [:maybe ::sm/timestamp]]
|
[:ended-at [:maybe schema:timestamp]]
|
||||||
[:trial-end [:maybe ::sm/timestamp]]
|
[:trial-end [:maybe schema:timestamp]]
|
||||||
[:trial-start [:maybe ::sm/timestamp]]
|
[:trial-start [:maybe schema:timestamp]]
|
||||||
[:cancel-at [:maybe ::sm/timestamp]]
|
[:cancel-at [:maybe schema:timestamp]]
|
||||||
[:canceled-at [:maybe ::sm/timestamp]]
|
[:canceled-at [:maybe schema:timestamp]]
|
||||||
[:current-period-end [:maybe ::sm/timestamp]]
|
[:current-period-end [:maybe schema:timestamp]]
|
||||||
[:current-period-start [:maybe ::sm/timestamp]]
|
[:current-period-start [:maybe schema:timestamp]]
|
||||||
[:cancel-at-period-end :boolean]
|
[:cancel-at-period-end :boolean]
|
||||||
|
|
||||||
[:cancellation-details
|
[:cancellation-details
|
||||||
|
|||||||
@@ -12,11 +12,11 @@
|
|||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.files.migrations :as fmg]
|
[app.common.files.migrations :as fmg]
|
||||||
[app.common.files.validate :as cfv]
|
[app.common.files.validate :as cfv]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.main :as main]
|
[app.main :as main]
|
||||||
[app.rpc.commands.files :as files]
|
[app.rpc.commands.files :as files]
|
||||||
[app.rpc.commands.files-snapshot :as fsnap]
|
[app.rpc.commands.files-snapshot :as fsnap]))
|
||||||
[app.util.time :as dt]))
|
|
||||||
|
|
||||||
(def ^:dynamic *system* nil)
|
(def ^:dynamic *system* nil)
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@
|
|||||||
(when (string? label)
|
(when (string? label)
|
||||||
(fsnap/create-file-snapshot! system file
|
(fsnap/create-file-snapshot! system file
|
||||||
{:label label
|
{:label label
|
||||||
:deleted-at (dt/in-future {:days 30})
|
:deleted-at (ct/in-future {:days 30})
|
||||||
:created-by :admin}))
|
:created-by :admin}))
|
||||||
|
|
||||||
(let [file' (update file' :revn inc)]
|
(let [file' (update file' :revn inc)]
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
[app.common.pprint :as p]
|
[app.common.pprint :as p]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -38,7 +39,6 @@
|
|||||||
[app.srepl.helpers :as h]
|
[app.srepl.helpers :as h]
|
||||||
[app.util.blob :as blob]
|
[app.util.blob :as blob]
|
||||||
[app.util.pointer-map :as pmap]
|
[app.util.pointer-map :as pmap]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[clojure.pprint :refer [print-table]]
|
[clojure.pprint :refer [print-table]]
|
||||||
@@ -476,7 +476,7 @@
|
|||||||
:max-jobs max-jobs
|
:max-jobs max-jobs
|
||||||
:max-items max-items)
|
:max-items max-items)
|
||||||
|
|
||||||
(let [tpoint (dt/tpoint)
|
(let [tpoint (ct/tpoint)
|
||||||
factory (px/thread-factory :virtual false :prefix "penpot/file-process/")
|
factory (px/thread-factory :virtual false :prefix "penpot/file-process/")
|
||||||
executor (px/cached-executor :factory factory)
|
executor (px/cached-executor :factory factory)
|
||||||
sjobs (ps/create :permits max-jobs)
|
sjobs (ps/create :permits max-jobs)
|
||||||
@@ -506,7 +506,7 @@
|
|||||||
(Thread/sleep (int pause)))
|
(Thread/sleep (int pause)))
|
||||||
|
|
||||||
(ps/release! sjobs)
|
(ps/release! sjobs)
|
||||||
(let [elapsed (dt/format-duration (tpoint))]
|
(let [elapsed (ct/format-duration (tpoint))]
|
||||||
(l/trc :hint "process:file:end"
|
(l/trc :hint "process:file:end"
|
||||||
:tid thread-id
|
:tid thread-id
|
||||||
:file-id (str file-id)
|
:file-id (str file-id)
|
||||||
@@ -516,7 +516,7 @@
|
|||||||
process-file*
|
process-file*
|
||||||
(fn [idx file-id]
|
(fn [idx file-id]
|
||||||
(ps/acquire! sjobs)
|
(ps/acquire! sjobs)
|
||||||
(px/run! executor (partial process-file file-id idx (dt/tpoint)))
|
(px/run! executor (partial process-file file-id idx (ct/tpoint)))
|
||||||
(inc idx))
|
(inc idx))
|
||||||
|
|
||||||
process-files
|
process-files
|
||||||
@@ -542,7 +542,7 @@
|
|||||||
(l/dbg :hint "process:error" :cause cause))
|
(l/dbg :hint "process:error" :cause cause))
|
||||||
|
|
||||||
(finally
|
(finally
|
||||||
(let [elapsed (dt/format-duration (tpoint))]
|
(let [elapsed (ct/format-duration (tpoint))]
|
||||||
(l/dbg :hint "process:end"
|
(l/dbg :hint "process:end"
|
||||||
:rollback rollback?
|
:rollback rollback?
|
||||||
:elapsed elapsed))))))
|
:elapsed elapsed))))))
|
||||||
@@ -556,7 +556,7 @@
|
|||||||
"Mark a project for deletion"
|
"Mark a project for deletion"
|
||||||
[file-id]
|
[file-id]
|
||||||
(let [file-id (h/parse-uuid file-id)
|
(let [file-id (h/parse-uuid file-id)
|
||||||
tnow (dt/now)]
|
tnow (ct/now)]
|
||||||
|
|
||||||
(audit/insert! main/system
|
(audit/insert! main/system
|
||||||
{::audit/name "delete-file"
|
{::audit/name "delete-file"
|
||||||
@@ -618,7 +618,7 @@
|
|||||||
::audit/props file
|
::audit/props file
|
||||||
::audit/context {:triggered-by "srepl"
|
::audit/context {:triggered-by "srepl"
|
||||||
:cause "explicit call to restore-file!"}
|
:cause "explicit call to restore-file!"}
|
||||||
::audit/tracked-at (dt/now)})
|
::audit/tracked-at (ct/now)})
|
||||||
|
|
||||||
(restore-file* system file-id))))))
|
(restore-file* system file-id))))))
|
||||||
|
|
||||||
@@ -626,7 +626,7 @@
|
|||||||
"Mark a project for deletion"
|
"Mark a project for deletion"
|
||||||
[project-id]
|
[project-id]
|
||||||
(let [project-id (h/parse-uuid project-id)
|
(let [project-id (h/parse-uuid project-id)
|
||||||
tnow (dt/now)]
|
tnow (ct/now)]
|
||||||
|
|
||||||
(audit/insert! main/system
|
(audit/insert! main/system
|
||||||
{::audit/name "delete-project"
|
{::audit/name "delete-project"
|
||||||
@@ -673,7 +673,7 @@
|
|||||||
::audit/props project
|
::audit/props project
|
||||||
::audit/context {:triggered-by "srepl"
|
::audit/context {:triggered-by "srepl"
|
||||||
:cause "explicit call to restore-team!"}
|
:cause "explicit call to restore-team!"}
|
||||||
::audit/tracked-at (dt/now)})
|
::audit/tracked-at (ct/now)})
|
||||||
|
|
||||||
(restore-project* system project-id))))))
|
(restore-project* system project-id))))))
|
||||||
|
|
||||||
@@ -681,7 +681,7 @@
|
|||||||
"Mark a team for deletion"
|
"Mark a team for deletion"
|
||||||
[team-id]
|
[team-id]
|
||||||
(let [team-id (h/parse-uuid team-id)
|
(let [team-id (h/parse-uuid team-id)
|
||||||
tnow (dt/now)]
|
tnow (ct/now)]
|
||||||
|
|
||||||
(audit/insert! main/system
|
(audit/insert! main/system
|
||||||
{::audit/name "delete-team"
|
{::audit/name "delete-team"
|
||||||
@@ -733,7 +733,7 @@
|
|||||||
::audit/props team
|
::audit/props team
|
||||||
::audit/context {:triggered-by "srepl"
|
::audit/context {:triggered-by "srepl"
|
||||||
:cause "explicit call to restore-team!"}
|
:cause "explicit call to restore-team!"}
|
||||||
::audit/tracked-at (dt/now)})
|
::audit/tracked-at (ct/now)})
|
||||||
|
|
||||||
(restore-team* system team-id))))))
|
(restore-team* system team-id))))))
|
||||||
|
|
||||||
@@ -741,7 +741,7 @@
|
|||||||
"Mark a profile for deletion."
|
"Mark a profile for deletion."
|
||||||
[profile-id]
|
[profile-id]
|
||||||
(let [profile-id (h/parse-uuid profile-id)
|
(let [profile-id (h/parse-uuid profile-id)
|
||||||
tnow (dt/now)]
|
tnow (ct/now)]
|
||||||
|
|
||||||
(audit/insert! main/system
|
(audit/insert! main/system
|
||||||
{::audit/name "delete-profile"
|
{::audit/name "delete-profile"
|
||||||
@@ -775,7 +775,7 @@
|
|||||||
::audit/props (audit/profile->props profile)
|
::audit/props (audit/profile->props profile)
|
||||||
::audit/context {:triggered-by "srepl"
|
::audit/context {:triggered-by "srepl"
|
||||||
:cause "explicit call to restore-profile!"}
|
:cause "explicit call to restore-profile!"}
|
||||||
::audit/tracked-at (dt/now)})
|
::audit/tracked-at (ct/now)})
|
||||||
|
|
||||||
(db/update! system :profile
|
(db/update! system :profile
|
||||||
{:deleted-at nil}
|
{:deleted-at nil}
|
||||||
@@ -821,7 +821,7 @@
|
|||||||
{:deleted deleted :total total})))]
|
{:deleted deleted :total total})))]
|
||||||
|
|
||||||
(let [path (fs/path path)
|
(let [path (fs/path path)
|
||||||
deleted-at (dt/minus (dt/now) (cf/get-deletion-delay))]
|
deleted-at (ct/minus (ct/now) (cf/get-deletion-delay))]
|
||||||
|
|
||||||
(when-not (fs/exists? path)
|
(when-not (fs/exists? path)
|
||||||
(throw (ex-info "path does not exists" {:path path})))
|
(throw (ex-info "path does not exists" {:path path})))
|
||||||
@@ -905,7 +905,7 @@
|
|||||||
(db/tx-run! main/system
|
(db/tx-run! main/system
|
||||||
(fn [{:keys [::db/conn] :as cfg}]
|
(fn [{:keys [::db/conn] :as cfg}]
|
||||||
(db/exec-one! conn ["SET CONSTRAINTS ALL DEFERRED"])
|
(db/exec-one! conn ["SET CONSTRAINTS ALL DEFERRED"])
|
||||||
(let [team (-> (assoc cfg ::bfc/timestamp (dt/now))
|
(let [team (-> (assoc cfg ::bfc/timestamp (ct/now))
|
||||||
(mgmt/duplicate-team :team-id team-id :name name))
|
(mgmt/duplicate-team :team-id team-id :name name))
|
||||||
rels (db/query conn :team-profile-rel {:team-id team-id})]
|
rels (db/query conn :team-profile-rel {:team-id team-id})]
|
||||||
|
|
||||||
|
|||||||
@@ -12,13 +12,13 @@
|
|||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.storage.fs :as sfs]
|
[app.storage.fs :as sfs]
|
||||||
[app.storage.impl :as impl]
|
[app.storage.impl :as impl]
|
||||||
[app.storage.s3 :as ss3]
|
[app.storage.s3 :as ss3]
|
||||||
[app.util.time :as dt]
|
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[datoteka.fs :as fs]
|
[datoteka.fs :as fs]
|
||||||
[integrant.core :as ig])
|
[integrant.core :as ig])
|
||||||
@@ -122,7 +122,7 @@
|
|||||||
(dissoc :id))
|
(dissoc :id))
|
||||||
|
|
||||||
touched-at (if touch
|
touched-at (if touch
|
||||||
(or touched-at (dt/now))
|
(or touched-at (ct/now))
|
||||||
touched-at)
|
touched-at)
|
||||||
|
|
||||||
;; NOTE: for now we don't reuse the deleted objects, but in
|
;; NOTE: for now we don't reuse the deleted objects, but in
|
||||||
@@ -224,7 +224,7 @@
|
|||||||
(assert (valid-storage? storage))
|
(assert (valid-storage? storage))
|
||||||
(let [id (if (impl/object? object-or-id) (:id object-or-id) object-or-id)]
|
(let [id (if (impl/object? object-or-id) (:id object-or-id) object-or-id)]
|
||||||
(-> (db/update! connectable :storage-object
|
(-> (db/update! connectable :storage-object
|
||||||
{:touched-at (dt/now)}
|
{:touched-at (ct/now)}
|
||||||
{:id id})
|
{:id id})
|
||||||
(db/get-update-count)
|
(db/get-update-count)
|
||||||
(pos?))))
|
(pos?))))
|
||||||
@@ -235,7 +235,7 @@
|
|||||||
[storage object]
|
[storage object]
|
||||||
(assert (valid-storage? storage))
|
(assert (valid-storage? storage))
|
||||||
(when (or (nil? (:expired-at object))
|
(when (or (nil? (:expired-at object))
|
||||||
(dt/is-after? (:expired-at object) (dt/now)))
|
(ct/is-after? (:expired-at object) (ct/now)))
|
||||||
(-> (impl/resolve-backend storage (:backend object))
|
(-> (impl/resolve-backend storage (:backend object))
|
||||||
(impl/get-object-data object))))
|
(impl/get-object-data object))))
|
||||||
|
|
||||||
@@ -244,7 +244,7 @@
|
|||||||
[storage object]
|
[storage object]
|
||||||
(assert (valid-storage? storage))
|
(assert (valid-storage? storage))
|
||||||
(when (or (nil? (:expired-at object))
|
(when (or (nil? (:expired-at object))
|
||||||
(dt/is-after? (:expired-at object) (dt/now)))
|
(ct/is-after? (:expired-at object) (ct/now)))
|
||||||
(-> (impl/resolve-backend storage (:backend object))
|
(-> (impl/resolve-backend storage (:backend object))
|
||||||
(impl/get-object-bytes object))))
|
(impl/get-object-bytes object))))
|
||||||
|
|
||||||
@@ -254,7 +254,7 @@
|
|||||||
([storage object options]
|
([storage object options]
|
||||||
(assert (valid-storage? storage))
|
(assert (valid-storage? storage))
|
||||||
(when (or (nil? (:expired-at object))
|
(when (or (nil? (:expired-at object))
|
||||||
(dt/is-after? (:expired-at object) (dt/now)))
|
(ct/is-after? (:expired-at object) (ct/now)))
|
||||||
(-> (impl/resolve-backend storage (:backend object))
|
(-> (impl/resolve-backend storage (:backend object))
|
||||||
(impl/get-object-url object options)))))
|
(impl/get-object-url object options)))))
|
||||||
|
|
||||||
@@ -266,7 +266,7 @@
|
|||||||
(let [backend (impl/resolve-backend storage (:backend object))]
|
(let [backend (impl/resolve-backend storage (:backend object))]
|
||||||
(when (and (= :fs (::type backend))
|
(when (and (= :fs (::type backend))
|
||||||
(or (nil? (:expired-at object))
|
(or (nil? (:expired-at object))
|
||||||
(dt/is-after? (:expired-at object) (dt/now))))
|
(ct/is-after? (:expired-at object) (ct/now))))
|
||||||
(-> (impl/get-object-url backend object nil) file-url->path))))
|
(-> (impl/get-object-url backend object nil) file-url->path))))
|
||||||
|
|
||||||
(defn del-object!
|
(defn del-object!
|
||||||
@@ -274,7 +274,7 @@
|
|||||||
(assert (valid-storage? storage))
|
(assert (valid-storage? storage))
|
||||||
(let [id (if (impl/object? object-or-id) (:id object-or-id) object-or-id)
|
(let [id (if (impl/object? object-or-id) (:id object-or-id) object-or-id)
|
||||||
res (db/update! connectable :storage-object
|
res (db/update! connectable :storage-object
|
||||||
{:deleted-at (dt/now)}
|
{:deleted-at (ct/now)}
|
||||||
{:id id})]
|
{:id id})]
|
||||||
(pos? (db/get-update-count res))))
|
(pos? (db/get-update-count res))))
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,10 @@
|
|||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.storage.impl :as impl]
|
[app.storage.impl :as impl]
|
||||||
[app.util.time :as dt]
|
|
||||||
[integrant.core :as ig]))
|
[integrant.core :as ig]))
|
||||||
|
|
||||||
(def ^:private sql:lock-sobjects
|
(def ^:private sql:lock-sobjects
|
||||||
@@ -106,18 +106,18 @@
|
|||||||
|
|
||||||
(defmethod ig/expand-key ::handler
|
(defmethod ig/expand-key ::handler
|
||||||
[k v]
|
[k v]
|
||||||
{k (assoc v ::min-age (dt/duration {:hours 2}))})
|
{k (assoc v ::min-age (ct/duration {:hours 2}))})
|
||||||
|
|
||||||
(defmethod ig/init-key ::handler
|
(defmethod ig/init-key ::handler
|
||||||
[_ {:keys [::min-age] :as cfg}]
|
[_ {:keys [::min-age] :as cfg}]
|
||||||
(fn [{:keys [props] :as task}]
|
(fn [{:keys [props] :as task}]
|
||||||
(let [min-age (dt/duration (or (:min-age props) min-age))]
|
(let [min-age (ct/duration (or (:min-age props) min-age))]
|
||||||
(db/tx-run! cfg (fn [cfg]
|
(db/tx-run! cfg (fn [cfg]
|
||||||
(let [cfg (assoc cfg ::min-age min-age)
|
(let [cfg (assoc cfg ::min-age min-age)
|
||||||
total (clean-deleted! cfg)]
|
total (clean-deleted! cfg)]
|
||||||
|
|
||||||
(l/inf :hint "task finished"
|
(l/inf :hint "task finished"
|
||||||
:min-age (dt/format-duration min-age)
|
:min-age (ct/format-duration min-age)
|
||||||
:total total)
|
:total total)
|
||||||
|
|
||||||
{:deleted total}))))))
|
{:deleted total}))))))
|
||||||
|
|||||||
@@ -12,11 +12,11 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uri :as u]
|
[app.common.uri :as u]
|
||||||
[app.storage :as-alias sto]
|
[app.storage :as-alias sto]
|
||||||
[app.storage.impl :as impl]
|
[app.storage.impl :as impl]
|
||||||
[app.storage.tmp :as tmp]
|
[app.storage.tmp :as tmp]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as-alias wrk]
|
[app.worker :as-alias wrk]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[datoteka.fs :as fs]
|
[datoteka.fs :as fs]
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
20000)
|
20000)
|
||||||
|
|
||||||
(def default-timeout
|
(def default-timeout
|
||||||
(dt/duration {:seconds 30}))
|
(ct/duration {:seconds 30}))
|
||||||
|
|
||||||
(declare put-object)
|
(declare put-object)
|
||||||
(declare get-object-bytes)
|
(declare get-object-bytes)
|
||||||
@@ -338,11 +338,11 @@
|
|||||||
(p/fmap #(.asByteArray ^ResponseBytes %)))))
|
(p/fmap #(.asByteArray ^ResponseBytes %)))))
|
||||||
|
|
||||||
(def default-max-age
|
(def default-max-age
|
||||||
(dt/duration {:minutes 10}))
|
(ct/duration {:minutes 10}))
|
||||||
|
|
||||||
(defn- get-object-url
|
(defn- get-object-url
|
||||||
[{:keys [::presigner ::bucket ::prefix]} {:keys [id]} {:keys [max-age] :or {max-age default-max-age}}]
|
[{:keys [::presigner ::bucket ::prefix]} {:keys [id]} {:keys [max-age] :or {max-age default-max-age}}]
|
||||||
(assert (dt/duration? max-age) "expected valid duration instance")
|
(assert (ct/duration? max-age) "expected valid duration instance")
|
||||||
|
|
||||||
(let [gor (.. (GetObjectRequest/builder)
|
(let [gor (.. (GetObjectRequest/builder)
|
||||||
(bucket bucket)
|
(bucket bucket)
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
(:require
|
(:require
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[datoteka.fs :as fs]
|
[datoteka.fs :as fs]
|
||||||
[datoteka.io :as io]
|
[datoteka.io :as io]
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
(defmethod ig/expand-key ::cleaner
|
(defmethod ig/expand-key ::cleaner
|
||||||
[k v]
|
[k v]
|
||||||
{k (assoc v ::min-age (dt/duration "60m"))})
|
{k (assoc v ::min-age (ct/duration "60m"))})
|
||||||
|
|
||||||
(defmethod ig/init-key ::cleaner
|
(defmethod ig/init-key ::cleaner
|
||||||
[_ cfg]
|
[_ cfg]
|
||||||
@@ -52,13 +52,13 @@
|
|||||||
|
|
||||||
(defn- io-loop
|
(defn- io-loop
|
||||||
[{:keys [::min-age] :as cfg}]
|
[{:keys [::min-age] :as cfg}]
|
||||||
(l/inf :hint "started tmp cleaner" :default-min-age (dt/format-duration min-age))
|
(l/inf :hint "started tmp cleaner" :default-min-age (ct/format-duration min-age))
|
||||||
(try
|
(try
|
||||||
(loop []
|
(loop []
|
||||||
(when-let [[path min-age'] (sp/take! queue)]
|
(when-let [[path min-age'] (sp/take! queue)]
|
||||||
(let [min-age (or min-age' min-age)]
|
(let [min-age (or min-age' min-age)]
|
||||||
(l/dbg :hint "schedule tempfile deletion" :path path
|
(l/dbg :hint "schedule tempfile deletion" :path path
|
||||||
:expires-at (dt/plus (dt/now) min-age))
|
:expires-at (ct/plus (ct/now) min-age))
|
||||||
(px/schedule! (inst-ms min-age) (partial remove-temp-file cfg path))
|
(px/schedule! (inst-ms min-age) (partial remove-temp-file cfg path))
|
||||||
(recur))))
|
(recur))))
|
||||||
(catch InterruptedException _
|
(catch InterruptedException _
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
path (fs/join default-tmp-dir (str prefix (uuid/next) suffix))
|
path (fs/join default-tmp-dir (str prefix (uuid/next) suffix))
|
||||||
path (Files/createFile path attrs)]
|
path (Files/createFile path attrs)]
|
||||||
(fs/delete-on-exit! path)
|
(fs/delete-on-exit! path)
|
||||||
(sp/offer! queue [path (some-> min-age dt/duration)])
|
(sp/offer! queue [path (some-> min-age ct/duration)])
|
||||||
path))
|
path))
|
||||||
|
|
||||||
(defn tempfile-from
|
(defn tempfile-from
|
||||||
|
|||||||
@@ -8,10 +8,10 @@
|
|||||||
"A generic task for object deletion cascade handling"
|
"A generic task for object deletion cascade handling"
|
||||||
(:require
|
(:require
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.rpc.commands.files :as files]
|
[app.rpc.commands.files :as files]
|
||||||
[app.rpc.commands.profile :as profile]
|
[app.rpc.commands.profile :as profile]
|
||||||
[app.util.time :as dt]
|
|
||||||
[integrant.core :as ig]))
|
[integrant.core :as ig]))
|
||||||
|
|
||||||
(def ^:dynamic *team-deletion* false)
|
(def ^:dynamic *team-deletion* false)
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
[{:keys [::db/conn] :as cfg} {:keys [id deleted-at]}]
|
[{:keys [::db/conn] :as cfg} {:keys [id deleted-at]}]
|
||||||
(when-let [file (db/get* conn :file {:id id} {::db/remove-deleted false})]
|
(when-let [file (db/get* conn :file {:id id} {::db/remove-deleted false})]
|
||||||
(l/trc :hint "marking for deletion" :rel "file" :id (str id)
|
(l/trc :hint "marking for deletion" :rel "file" :id (str id)
|
||||||
:deleted-at (dt/format-instant deleted-at))
|
:deleted-at (ct/format-inst deleted-at))
|
||||||
|
|
||||||
(db/update! conn :file
|
(db/update! conn :file
|
||||||
{:deleted-at deleted-at}
|
{:deleted-at deleted-at}
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
(defmethod delete-object :project
|
(defmethod delete-object :project
|
||||||
[{:keys [::db/conn] :as cfg} {:keys [id deleted-at]}]
|
[{:keys [::db/conn] :as cfg} {:keys [id deleted-at]}]
|
||||||
(l/trc :hint "marking for deletion" :rel "project" :id (str id)
|
(l/trc :hint "marking for deletion" :rel "project" :id (str id)
|
||||||
:deleted-at (dt/format-instant deleted-at))
|
:deleted-at (ct/format-inst deleted-at))
|
||||||
|
|
||||||
(db/update! conn :project
|
(db/update! conn :project
|
||||||
{:deleted-at deleted-at}
|
{:deleted-at deleted-at}
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
(defmethod delete-object :team
|
(defmethod delete-object :team
|
||||||
[{:keys [::db/conn] :as cfg} {:keys [id deleted-at]}]
|
[{:keys [::db/conn] :as cfg} {:keys [id deleted-at]}]
|
||||||
(l/trc :hint "marking for deletion" :rel "team" :id (str id)
|
(l/trc :hint "marking for deletion" :rel "team" :id (str id)
|
||||||
:deleted-at (dt/format-instant deleted-at))
|
:deleted-at (ct/format-inst deleted-at))
|
||||||
(db/update! conn :team
|
(db/update! conn :team
|
||||||
{:deleted-at deleted-at}
|
{:deleted-at deleted-at}
|
||||||
{:id id}
|
{:id id}
|
||||||
@@ -101,7 +101,7 @@
|
|||||||
(defmethod delete-object :profile
|
(defmethod delete-object :profile
|
||||||
[{:keys [::db/conn] :as cfg} {:keys [id deleted-at]}]
|
[{:keys [::db/conn] :as cfg} {:keys [id deleted-at]}]
|
||||||
(l/trc :hint "marking for deletion" :rel "profile" :id (str id)
|
(l/trc :hint "marking for deletion" :rel "profile" :id (str id)
|
||||||
:deleted-at (dt/format-instant deleted-at))
|
:deleted-at (ct/format-inst deleted-at))
|
||||||
|
|
||||||
(db/update! conn :profile
|
(db/update! conn :profile
|
||||||
{:deleted-at deleted-at}
|
{:deleted-at deleted-at}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
[app.common.files.validate :as cfv]
|
[app.common.files.validate :as cfv]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.thumbnails :as thc]
|
[app.common.thumbnails :as thc]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.components-list :as ctkl]
|
[app.common.types.components-list :as ctkl]
|
||||||
[app.common.types.file :as ctf]
|
[app.common.types.file :as ctf]
|
||||||
[app.common.types.shape-tree :as ctt]
|
[app.common.types.shape-tree :as ctt]
|
||||||
@@ -23,7 +24,6 @@
|
|||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.features.fdata :as feat.fdata]
|
[app.features.fdata :as feat.fdata]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[integrant.core :as ig]))
|
[integrant.core :as ig]))
|
||||||
|
|
||||||
@@ -282,7 +282,7 @@
|
|||||||
(defmethod ig/init-key ::handler
|
(defmethod ig/init-key ::handler
|
||||||
[_ cfg]
|
[_ cfg]
|
||||||
(fn [{:keys [props] :as task}]
|
(fn [{:keys [props] :as task}]
|
||||||
(let [min-age (dt/duration (or (:min-age props)
|
(let [min-age (ct/duration (or (:min-age props)
|
||||||
(cf/get-deletion-delay)))
|
(cf/get-deletion-delay)))
|
||||||
file-id (get props :file-id)
|
file-id (get props :file-id)
|
||||||
cfg (-> cfg
|
cfg (-> cfg
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
"A maintenance task that is responsible of properly scheduling the
|
"A maintenance task that is responsible of properly scheduling the
|
||||||
file-gc task for all files that matches the eligibility threshold."
|
file-gc task for all files that matches the eligibility threshold."
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[integrant.core :as ig]))
|
[integrant.core :as ig]))
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
(defmethod ig/init-key ::handler
|
(defmethod ig/init-key ::handler
|
||||||
[_ cfg]
|
[_ cfg]
|
||||||
(fn [{:keys [props] :as task}]
|
(fn [{:keys [props] :as task}]
|
||||||
(let [min-age (dt/duration (or (:min-age props) (::min-age cfg)))]
|
(let [min-age (ct/duration (or (:min-age props) (::min-age cfg)))]
|
||||||
(-> cfg
|
(-> cfg
|
||||||
(assoc ::db/rollback (:rollback? props))
|
(assoc ::db/rollback (:rollback? props))
|
||||||
(assoc ::min-age min-age)
|
(assoc ::min-age min-age)
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
of deleted or unreachable objects."
|
of deleted or unreachable objects."
|
||||||
(:require
|
(:require
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.util.time :as dt]
|
|
||||||
[integrant.core :as ig]))
|
[integrant.core :as ig]))
|
||||||
|
|
||||||
(def ^:private sql:get-profiles
|
(def ^:private sql:get-profiles
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
(l/trc :hint "permanently delete"
|
(l/trc :hint "permanently delete"
|
||||||
:rel "team"
|
:rel "team"
|
||||||
:id (str id)
|
:id (str id)
|
||||||
:deleted-at (dt/format-instant deleted-at))
|
:deleted-at (ct/format-inst deleted-at))
|
||||||
|
|
||||||
;; Mark as deleted the storage object
|
;; Mark as deleted the storage object
|
||||||
(some->> photo-id (sto/touch-object! storage))
|
(some->> photo-id (sto/touch-object! storage))
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
:rel "team-font-variant"
|
:rel "team-font-variant"
|
||||||
:id (str id)
|
:id (str id)
|
||||||
:team-id (str team-id)
|
:team-id (str team-id)
|
||||||
:deleted-at (dt/format-instant deleted-at))
|
:deleted-at (ct/format-inst deleted-at))
|
||||||
|
|
||||||
;; Mark as deleted the all related storage objects
|
;; Mark as deleted the all related storage objects
|
||||||
(some->> (:woff1-file-id font) (sto/touch-object! storage))
|
(some->> (:woff1-file-id font) (sto/touch-object! storage))
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
:rel "project"
|
:rel "project"
|
||||||
:id (str id)
|
:id (str id)
|
||||||
:team-id (str team-id)
|
:team-id (str team-id)
|
||||||
:deleted-at (dt/format-instant deleted-at))
|
:deleted-at (ct/format-inst deleted-at))
|
||||||
|
|
||||||
;; And finally, permanently delete the project.
|
;; And finally, permanently delete the project.
|
||||||
(db/delete! conn :project {:id id})
|
(db/delete! conn :project {:id id})
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
:rel "file"
|
:rel "file"
|
||||||
:id (str id)
|
:id (str id)
|
||||||
:project-id (str project-id)
|
:project-id (str project-id)
|
||||||
:deleted-at (dt/format-instant deleted-at))
|
:deleted-at (ct/format-inst deleted-at))
|
||||||
|
|
||||||
(when (= "objects-storage" (:data-backend file))
|
(when (= "objects-storage" (:data-backend file))
|
||||||
(sto/touch-object! storage (:data-ref-id file)))
|
(sto/touch-object! storage (:data-ref-id file)))
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
:rel "file-thumbnail"
|
:rel "file-thumbnail"
|
||||||
:file-id (str file-id)
|
:file-id (str file-id)
|
||||||
:revn revn
|
:revn revn
|
||||||
:deleted-at (dt/format-instant deleted-at))
|
:deleted-at (ct/format-inst deleted-at))
|
||||||
|
|
||||||
;; Mark as deleted the storage object
|
;; Mark as deleted the storage object
|
||||||
(some->> media-id (sto/touch-object! storage))
|
(some->> media-id (sto/touch-object! storage))
|
||||||
@@ -198,7 +198,7 @@
|
|||||||
:rel "file-tagged-object-thumbnail"
|
:rel "file-tagged-object-thumbnail"
|
||||||
:file-id (str file-id)
|
:file-id (str file-id)
|
||||||
:object-id object-id
|
:object-id object-id
|
||||||
:deleted-at (dt/format-instant deleted-at))
|
:deleted-at (ct/format-inst deleted-at))
|
||||||
|
|
||||||
;; Mark as deleted the storage object
|
;; Mark as deleted the storage object
|
||||||
(some->> media-id (sto/touch-object! storage))
|
(some->> media-id (sto/touch-object! storage))
|
||||||
@@ -227,7 +227,7 @@
|
|||||||
:rel "file-data-fragment"
|
:rel "file-data-fragment"
|
||||||
:id (str id)
|
:id (str id)
|
||||||
:file-id (str file-id)
|
:file-id (str file-id)
|
||||||
:deleted-at (dt/format-instant deleted-at))
|
:deleted-at (ct/format-inst deleted-at))
|
||||||
|
|
||||||
(some->> data-ref-id (sto/touch-object! storage))
|
(some->> data-ref-id (sto/touch-object! storage))
|
||||||
(db/delete! conn :file-data-fragment {:file-id file-id :id id})
|
(db/delete! conn :file-data-fragment {:file-id file-id :id id})
|
||||||
@@ -253,7 +253,7 @@
|
|||||||
:rel "file-media-object"
|
:rel "file-media-object"
|
||||||
:id (str id)
|
:id (str id)
|
||||||
:file-id (str file-id)
|
:file-id (str file-id)
|
||||||
:deleted-at (dt/format-instant deleted-at))
|
:deleted-at (ct/format-inst deleted-at))
|
||||||
|
|
||||||
;; Mark as deleted the all related storage objects
|
;; Mark as deleted the all related storage objects
|
||||||
(some->> (:media-id fmo) (sto/touch-object! storage))
|
(some->> (:media-id fmo) (sto/touch-object! storage))
|
||||||
@@ -282,7 +282,7 @@
|
|||||||
:rel "file-change"
|
:rel "file-change"
|
||||||
:id (str id)
|
:id (str id)
|
||||||
:file-id (str file-id)
|
:file-id (str file-id)
|
||||||
:deleted-at (dt/format-instant deleted-at))
|
:deleted-at (ct/format-inst deleted-at))
|
||||||
|
|
||||||
(when (= "objects-storage" (:data-backend xlog))
|
(when (= "objects-storage" (:data-backend xlog))
|
||||||
(sto/touch-object! storage (:data-ref-id xlog)))
|
(sto/touch-object! storage (:data-ref-id xlog)))
|
||||||
@@ -328,7 +328,7 @@
|
|||||||
(defmethod ig/init-key ::handler
|
(defmethod ig/init-key ::handler
|
||||||
[_ cfg]
|
[_ cfg]
|
||||||
(fn [{:keys [props] :as task}]
|
(fn [{:keys [props] :as task}]
|
||||||
(let [threshold (dt/duration (get props :deletion-threshold 0))
|
(let [threshold (ct/duration (get props :deletion-threshold 0))
|
||||||
cfg (assoc cfg ::deletion-threshold (db/interval threshold))]
|
cfg (assoc cfg ::deletion-threshold (db/interval threshold))]
|
||||||
(loop [procs (map deref deletion-proc-vars)
|
(loop [procs (map deref deletion-proc-vars)
|
||||||
total 0]
|
total 0]
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.util.time :as dt]
|
|
||||||
[buddy.sign.jwe :as jwe]))
|
[buddy.sign.jwe :as jwe]))
|
||||||
|
|
||||||
(defn generate
|
(defn generate
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
(bytes? tokens-key))
|
(bytes? tokens-key))
|
||||||
|
|
||||||
(let [payload (-> claims
|
(let [payload (-> claims
|
||||||
(assoc :iat (dt/now))
|
(assoc :iat (ct/now))
|
||||||
(d/without-nils)
|
(d/without-nils)
|
||||||
(t/encode))]
|
(t/encode))]
|
||||||
(jwe/encrypt payload tokens-key {:alg :a256kw :enc :a256gcm})))
|
(jwe/encrypt payload tokens-key {:alg :a256kw :enc :a256gcm})))
|
||||||
@@ -35,8 +35,8 @@
|
|||||||
(defn verify
|
(defn verify
|
||||||
[sprops {:keys [token] :as params}]
|
[sprops {:keys [token] :as params}]
|
||||||
(let [claims (decode sprops token)]
|
(let [claims (decode sprops token)]
|
||||||
(when (and (dt/instant? (:exp claims))
|
(when (and (ct/inst? (:exp claims))
|
||||||
(dt/is-before? (:exp claims) (dt/now)))
|
(ct/is-before? (:exp claims) (ct/now)))
|
||||||
(ex/raise :type :validation
|
(ex/raise :type :validation
|
||||||
:code :invalid-token
|
:code :invalid-token
|
||||||
:reason :token-expired
|
:reason :token-expired
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
(:refer-clojure :exclude [get])
|
(:refer-clojure :exclude [get])
|
||||||
(:require
|
(:require
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.util.time :as dt]
|
[app.common.time :as ct]
|
||||||
[promesa.exec :as px])
|
[promesa.exec :as px])
|
||||||
(:import
|
(:import
|
||||||
com.github.benmanes.caffeine.cache.AsyncCache
|
com.github.benmanes.caffeine.cache.AsyncCache
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
(let [cache (as-> (Caffeine/newBuilder) builder
|
(let [cache (as-> (Caffeine/newBuilder) builder
|
||||||
(if (fn? on-remove) (.removalListener builder (create-listener on-remove)) builder)
|
(if (fn? on-remove) (.removalListener builder (create-listener on-remove)) builder)
|
||||||
(if executor (.executor builder ^Executor (px/resolve-executor executor)) builder)
|
(if executor (.executor builder ^Executor (px/resolve-executor executor)) builder)
|
||||||
(if keepalive (.expireAfterAccess builder ^Duration (dt/duration keepalive)) builder)
|
(if keepalive (.expireAfterAccess builder ^Duration (ct/duration keepalive)) builder)
|
||||||
(if (int? max-size) (.maximumSize builder (long max-size)) builder)
|
(if (int? max-size) (.maximumSize builder (long max-size)) builder)
|
||||||
(.recordStats builder)
|
(.recordStats builder)
|
||||||
(.buildAsync builder))
|
(.buildAsync builder))
|
||||||
|
|||||||
138
backend/src/app/util/cron.clj
Normal file
138
backend/src/app/util/cron.clj
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
;; 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.util.cron
|
||||||
|
(:require
|
||||||
|
[app.common.exceptions :as ex])
|
||||||
|
(:import
|
||||||
|
java.time.Instant
|
||||||
|
java.util.Date
|
||||||
|
org.apache.logging.log4j.core.util.CronExpression))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Cron Expression
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
;; Cron expressions are comprised of 6 required fields and one
|
||||||
|
;; optional field separated by white space. The fields respectively
|
||||||
|
;; are described as follows:
|
||||||
|
;;
|
||||||
|
;; Field Name Allowed Values Allowed Special Characters
|
||||||
|
;; Seconds 0-59 , - * /
|
||||||
|
;; Minutes 0-59 , - * /
|
||||||
|
;; Hours 0-23 , - * /
|
||||||
|
;; Day-of-month 1-31 , - * ? / L W
|
||||||
|
;; Month 0-11 or JAN-DEC , - * /
|
||||||
|
;; Day-of-Week 1-7 or SUN-SAT , - * ? / L #
|
||||||
|
;; Year (Optional) empty, 1970-2199 , - * /
|
||||||
|
;;
|
||||||
|
;; The '*' character is used to specify all values. For example, "*"
|
||||||
|
;; in the minute field means "every minute".
|
||||||
|
;;
|
||||||
|
;; The '?' character is allowed for the day-of-month and day-of-week
|
||||||
|
;; fields. It is used to specify 'no specific value'. This is useful
|
||||||
|
;; when you need to specify something in one of the two fields, but
|
||||||
|
;; not the other.
|
||||||
|
;;
|
||||||
|
;; The '-' character is used to specify ranges For example "10-12" in
|
||||||
|
;; the hour field means "the hours 10, 11 and 12".
|
||||||
|
;;
|
||||||
|
;; The ',' character is used to specify additional values. For
|
||||||
|
;; example "MON,WED,FRI" in the day-of-week field means "the days
|
||||||
|
;; Monday, Wednesday, and Friday".
|
||||||
|
;;
|
||||||
|
;; The '/' character is used to specify increments. For example "0/15"
|
||||||
|
;; in the seconds field means "the seconds 0, 15, 30, and
|
||||||
|
;; 45". And "5/15" in the seconds field means "the seconds 5, 20, 35,
|
||||||
|
;; and 50". Specifying '*' before the '/' is equivalent to specifying
|
||||||
|
;; 0 is the value to start with. Essentially, for each field in the
|
||||||
|
;; expression, there is a set of numbers that can be turned on or
|
||||||
|
;; off. For seconds and minutes, the numbers range from 0 to 59. For
|
||||||
|
;; hours 0 to 23, for days of the month 0 to 31, and for months 0 to
|
||||||
|
;; 11 (JAN to DEC). The "/" character simply helps you turn on
|
||||||
|
;; every "nth" value in the given set. Thus "7/6" in the month field
|
||||||
|
;; only turns on month "7", it does NOT mean every 6th month, please
|
||||||
|
;; note that subtlety.
|
||||||
|
;;
|
||||||
|
;; The 'L' character is allowed for the day-of-month and day-of-week
|
||||||
|
;; fields. This character is short-hand for "last", but it has
|
||||||
|
;; different meaning in each of the two fields. For example, the
|
||||||
|
;; value "L" in the day-of-month field means "the last day of the
|
||||||
|
;; month" - day 31 for January, day 28 for February on non-leap
|
||||||
|
;; years. If used in the day-of-week field by itself, it simply
|
||||||
|
;; means "7" or "SAT". But if used in the day-of-week field after
|
||||||
|
;; another value, it means "the last xxx day of the month" - for
|
||||||
|
;; example "6L" means "the last friday of the month". You can also
|
||||||
|
;; specify an offset from the last day of the month, such as "L-3"
|
||||||
|
;; which would mean the third-to-last day of the calendar month. When
|
||||||
|
;; using the 'L' option, it is important not to specify lists, or
|
||||||
|
;; ranges of values, as you'll get confusing/unexpected results.
|
||||||
|
;;
|
||||||
|
;; The 'W' character is allowed for the day-of-month field. This
|
||||||
|
;; character is used to specify the weekday (Monday-Friday) nearest
|
||||||
|
;; the given day. As an example, if you were to specify "15W" as the
|
||||||
|
;; value for the day-of-month field, the meaning is: "the nearest
|
||||||
|
;; weekday to the 15th of the month". So if the 15th is a Saturday,
|
||||||
|
;; the trigger will fire on Friday the 14th. If the 15th is a Sunday,
|
||||||
|
;; the trigger will fire on Monday the 16th. If the 15th is a Tuesday,
|
||||||
|
;; then it will fire on Tuesday the 15th. However if you specify "1W"
|
||||||
|
;; as the value for day-of-month, and the 1st is a Saturday, the
|
||||||
|
;; trigger will fire on Monday the 3rd, as it will not 'jump' over the
|
||||||
|
;; boundary of a month's days. The 'W' character can only be specified
|
||||||
|
;; when the day-of-month is a single day, not a range or list of days.
|
||||||
|
;;
|
||||||
|
;; The 'L' and 'W' characters can also be combined for the
|
||||||
|
;; day-of-month expression to yield 'LW', which translates to "last
|
||||||
|
;; weekday of the month".
|
||||||
|
;;
|
||||||
|
;; The '#' character is allowed for the day-of-week field. This
|
||||||
|
;; character is used to specify "the nth" XXX day of the month. For
|
||||||
|
;; example, the value of "6#3" in the day-of-week field means the
|
||||||
|
;; third Friday of the month (day 6 = Friday and "#3" = the 3rd one in
|
||||||
|
;; the month). Other examples: "2#1" = the first Monday of the month
|
||||||
|
;; and "4#5" = the fifth Wednesday of the month. Note that if you
|
||||||
|
;; specify "#5" and there is not 5 of the given day-of-week in the
|
||||||
|
;; month, then no firing will occur that month. If the '#' character
|
||||||
|
;; is used, there can only be one expression in the day-of-week
|
||||||
|
;; field ("3#1,6#3" is not valid, since there are two expressions).
|
||||||
|
;;
|
||||||
|
;; The legal characters and the names of months and days of the week
|
||||||
|
;; are not case sensitive.
|
||||||
|
|
||||||
|
(defn cron
|
||||||
|
"Creates an instance of CronExpression from string."
|
||||||
|
[s]
|
||||||
|
(try
|
||||||
|
(CronExpression. s)
|
||||||
|
(catch java.text.ParseException e
|
||||||
|
(ex/raise :type :parse
|
||||||
|
:code :invalid-cron-expression
|
||||||
|
:cause e
|
||||||
|
:context {:expr s}))))
|
||||||
|
|
||||||
|
(defn cron-expr?
|
||||||
|
[v]
|
||||||
|
(instance? CronExpression v))
|
||||||
|
|
||||||
|
(defn next-valid-instant-from
|
||||||
|
[^CronExpression cron ^Instant now]
|
||||||
|
(assert (cron-expr? cron))
|
||||||
|
(.toInstant (.getNextValidTimeAfter cron (Date/from now))))
|
||||||
|
|
||||||
|
(defn get-next
|
||||||
|
[cron tnow]
|
||||||
|
(let [nt (next-valid-instant-from cron tnow)]
|
||||||
|
(cons nt (lazy-seq (get-next cron nt)))))
|
||||||
|
|
||||||
|
(defmethod print-method CronExpression
|
||||||
|
[o w]
|
||||||
|
(print-dup o w))
|
||||||
|
|
||||||
|
(defmethod print-dup CronExpression
|
||||||
|
[mv ^java.io.Writer writer]
|
||||||
|
;; Do not delete this comment
|
||||||
|
;; (print-ctor o (fn [o w] (print-dup (.toString ^CronExpression o) w)) w)
|
||||||
|
(.write writer (str "#penpot/cron \"" (.toString ^CronExpression mv) "\"")))
|
||||||
@@ -37,9 +37,9 @@
|
|||||||
|
|
||||||
(:require
|
(:require
|
||||||
[app.common.fressian :as fres]
|
[app.common.fressian :as fres]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.util.time :as dt]
|
|
||||||
[clojure.core :as c]
|
[clojure.core :as c]
|
||||||
[clojure.data.json :as json])
|
[clojure.data.json :as json])
|
||||||
(:import
|
(:import
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
|
|
||||||
(clone [this]
|
(clone [this]
|
||||||
(when-not loaded? (load! this))
|
(when-not loaded? (load! this))
|
||||||
(let [mdata (assoc mdata :created-at (dt/now))
|
(let [mdata (assoc mdata :created-at (ct/now))
|
||||||
id (uuid/next)
|
id (uuid/next)
|
||||||
pmap (PointerMap. id
|
pmap (PointerMap. id
|
||||||
mdata
|
mdata
|
||||||
@@ -179,7 +179,7 @@
|
|||||||
(let [odata' (assoc odata key val)]
|
(let [odata' (assoc odata key val)]
|
||||||
(if (identical? odata odata')
|
(if (identical? odata odata')
|
||||||
this
|
this
|
||||||
(let [mdata (assoc mdata :created-at (dt/now))
|
(let [mdata (assoc mdata :created-at (ct/now))
|
||||||
id (if modified? id (uuid/next))
|
id (if modified? id (uuid/next))
|
||||||
pmap (PointerMap. id
|
pmap (PointerMap. id
|
||||||
mdata
|
mdata
|
||||||
@@ -197,7 +197,7 @@
|
|||||||
(let [odata' (dissoc odata key)]
|
(let [odata' (dissoc odata key)]
|
||||||
(if (identical? odata odata')
|
(if (identical? odata odata')
|
||||||
this
|
this
|
||||||
(let [mdata (assoc mdata :created-at (dt/now))
|
(let [mdata (assoc mdata :created-at (ct/now))
|
||||||
id (if modified? id (uuid/next))
|
id (if modified? id (uuid/next))
|
||||||
pmap (PointerMap. id
|
pmap (PointerMap. id
|
||||||
mdata
|
mdata
|
||||||
@@ -220,7 +220,7 @@
|
|||||||
(defn create
|
(defn create
|
||||||
([]
|
([]
|
||||||
(let [id (uuid/next)
|
(let [id (uuid/next)
|
||||||
mdata (assoc *metadata* :created-at (dt/now))
|
mdata (assoc *metadata* :created-at (ct/now))
|
||||||
pmap (PointerMap. id mdata {} true true)]
|
pmap (PointerMap. id mdata {} true true)]
|
||||||
(some-> *tracked* (swap! assoc id pmap))
|
(some-> *tracked* (swap! assoc id pmap))
|
||||||
pmap))
|
pmap))
|
||||||
@@ -239,7 +239,7 @@
|
|||||||
(do
|
(do
|
||||||
(some-> *tracked* (swap! assoc (get-id data) data))
|
(some-> *tracked* (swap! assoc (get-id data) data))
|
||||||
data)
|
data)
|
||||||
(let [mdata (assoc (meta data) :created-at (dt/now))
|
(let [mdata (assoc (meta data) :created-at (ct/now))
|
||||||
id (uuid/next)
|
id (uuid/next)
|
||||||
pmap (PointerMap. id
|
pmap (PointerMap. id
|
||||||
mdata
|
mdata
|
||||||
|
|||||||
@@ -1,399 +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.util.time
|
|
||||||
(:require
|
|
||||||
[app.common.data.macros :as dm]
|
|
||||||
[app.common.exceptions :as ex]
|
|
||||||
[app.common.schema :as sm]
|
|
||||||
[app.common.schema.openapi :as-alias oapi]
|
|
||||||
[app.common.time :as common-time]
|
|
||||||
[clojure.spec.alpha :as s]
|
|
||||||
[clojure.test.check.generators :as tgen]
|
|
||||||
[cuerdas.core :as str]
|
|
||||||
[fipp.ednize :as fez])
|
|
||||||
(:import
|
|
||||||
java.nio.file.attribute.FileTime
|
|
||||||
java.time.Duration
|
|
||||||
java.time.Instant
|
|
||||||
java.time.OffsetDateTime
|
|
||||||
java.time.ZoneId
|
|
||||||
java.time.ZonedDateTime
|
|
||||||
java.time.format.DateTimeFormatter
|
|
||||||
java.time.temporal.ChronoUnit
|
|
||||||
java.time.temporal.Temporal
|
|
||||||
java.time.temporal.TemporalAmount
|
|
||||||
java.time.temporal.TemporalUnit
|
|
||||||
java.util.Date
|
|
||||||
org.apache.logging.log4j.core.util.CronExpression))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Instant & Duration
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
(defn temporal-unit
|
|
||||||
[o]
|
|
||||||
(if (instance? TemporalUnit o)
|
|
||||||
o
|
|
||||||
(case o
|
|
||||||
:nanos ChronoUnit/NANOS
|
|
||||||
:millis ChronoUnit/MILLIS
|
|
||||||
:micros ChronoUnit/MICROS
|
|
||||||
:seconds ChronoUnit/SECONDS
|
|
||||||
:minutes ChronoUnit/MINUTES
|
|
||||||
:hours ChronoUnit/HOURS
|
|
||||||
:days ChronoUnit/DAYS)))
|
|
||||||
|
|
||||||
;; --- DURATION
|
|
||||||
|
|
||||||
(defn- obj->duration
|
|
||||||
[params]
|
|
||||||
(reduce-kv (fn [o k v]
|
|
||||||
(.plus ^Duration o ^long v ^TemporalUnit (temporal-unit k)))
|
|
||||||
(Duration/ofMillis 0)
|
|
||||||
params))
|
|
||||||
|
|
||||||
(defn duration?
|
|
||||||
[v]
|
|
||||||
(instance? Duration v))
|
|
||||||
|
|
||||||
(defn duration
|
|
||||||
[ms-or-obj]
|
|
||||||
(cond
|
|
||||||
(string? ms-or-obj)
|
|
||||||
(Duration/parse (str "PT" ms-or-obj))
|
|
||||||
|
|
||||||
(duration? ms-or-obj)
|
|
||||||
ms-or-obj
|
|
||||||
|
|
||||||
(integer? ms-or-obj)
|
|
||||||
(Duration/ofMillis ms-or-obj)
|
|
||||||
|
|
||||||
:else
|
|
||||||
(obj->duration ms-or-obj)))
|
|
||||||
|
|
||||||
(defn ->seconds
|
|
||||||
[d]
|
|
||||||
(-> d inst-ms (/ 1000) int))
|
|
||||||
|
|
||||||
(defn diff
|
|
||||||
[t1 t2]
|
|
||||||
(Duration/between t1 t2))
|
|
||||||
|
|
||||||
(defn truncate
|
|
||||||
[o unit]
|
|
||||||
(let [unit (temporal-unit unit)]
|
|
||||||
(cond
|
|
||||||
(instance? Instant o)
|
|
||||||
(.truncatedTo ^Instant o ^TemporalUnit unit)
|
|
||||||
|
|
||||||
(instance? Duration o)
|
|
||||||
(.truncatedTo ^Duration o ^TemporalUnit unit)
|
|
||||||
|
|
||||||
:else
|
|
||||||
(throw (IllegalArgumentException. "only instant and duration allowed")))))
|
|
||||||
|
|
||||||
(s/def ::duration
|
|
||||||
(s/conformer
|
|
||||||
(fn [v]
|
|
||||||
(cond
|
|
||||||
(duration? v) v
|
|
||||||
|
|
||||||
(string? v)
|
|
||||||
(try
|
|
||||||
(duration v)
|
|
||||||
(catch java.time.format.DateTimeParseException _e
|
|
||||||
::s/invalid))
|
|
||||||
|
|
||||||
:else
|
|
||||||
::s/invalid))
|
|
||||||
(fn [v]
|
|
||||||
(subs (str v) 2))))
|
|
||||||
|
|
||||||
(extend-protocol clojure.core/Inst
|
|
||||||
java.time.Duration
|
|
||||||
(inst-ms* [v] (.toMillis ^Duration v))
|
|
||||||
|
|
||||||
OffsetDateTime
|
|
||||||
(inst-ms* [v] (.toEpochMilli (.toInstant ^OffsetDateTime v)))
|
|
||||||
|
|
||||||
FileTime
|
|
||||||
(inst-ms* [v] (.toMillis ^FileTime v)))
|
|
||||||
|
|
||||||
(defmethod print-method Duration
|
|
||||||
[mv ^java.io.Writer writer]
|
|
||||||
(.write writer (str "#app/duration \"" (str/lower (subs (str mv) 2)) "\"")))
|
|
||||||
|
|
||||||
(defmethod print-dup Duration [o w]
|
|
||||||
(print-method o w))
|
|
||||||
|
|
||||||
(extend-protocol fez/IEdn
|
|
||||||
Duration
|
|
||||||
(-edn [o]
|
|
||||||
(tagged-literal 'app/duration (str o))))
|
|
||||||
|
|
||||||
(defn format-duration
|
|
||||||
[o]
|
|
||||||
(str/lower (subs (str o) 2)))
|
|
||||||
|
|
||||||
;; --- INSTANT
|
|
||||||
|
|
||||||
(defn instant?
|
|
||||||
[v]
|
|
||||||
(instance? Instant v))
|
|
||||||
|
|
||||||
(defn instant
|
|
||||||
([s]
|
|
||||||
(cond
|
|
||||||
(instant? s) s
|
|
||||||
(int? s) (Instant/ofEpochMilli s)
|
|
||||||
:else (Instant/parse s)))
|
|
||||||
([s fmt]
|
|
||||||
(case fmt
|
|
||||||
:rfc1123 (Instant/from (.parse DateTimeFormatter/RFC_1123_DATE_TIME ^String s))
|
|
||||||
:iso (Instant/from (.parse DateTimeFormatter/ISO_INSTANT ^String s))
|
|
||||||
:iso8601 (Instant/from (.parse DateTimeFormatter/ISO_INSTANT ^String s)))))
|
|
||||||
|
|
||||||
(defn is-after?
|
|
||||||
"Analgous to: da > db"
|
|
||||||
[da db]
|
|
||||||
(.isAfter ^Instant da ^Instant db))
|
|
||||||
|
|
||||||
(defn is-before?
|
|
||||||
[da db]
|
|
||||||
(.isBefore ^Instant da ^Instant db))
|
|
||||||
|
|
||||||
(defn plus
|
|
||||||
[d ta]
|
|
||||||
(let [^TemporalAmount ta (duration ta)]
|
|
||||||
(cond
|
|
||||||
(instance? Duration d)
|
|
||||||
(.plus ^Duration d ta)
|
|
||||||
|
|
||||||
(instance? Temporal d)
|
|
||||||
(.plus ^Temporal d ta)
|
|
||||||
|
|
||||||
:else
|
|
||||||
(throw (UnsupportedOperationException. "unsupported type")))))
|
|
||||||
|
|
||||||
(defn minus
|
|
||||||
[d ta]
|
|
||||||
(let [^TemporalAmount ta (duration ta)]
|
|
||||||
(cond
|
|
||||||
(instance? Duration d)
|
|
||||||
(.minus ^Duration d ta)
|
|
||||||
|
|
||||||
(instance? Temporal d)
|
|
||||||
(.minus ^Temporal d ta)
|
|
||||||
|
|
||||||
:else
|
|
||||||
(throw (UnsupportedOperationException. "unsupported type")))))
|
|
||||||
|
|
||||||
(dm/export common-time/now)
|
|
||||||
|
|
||||||
(defn in-future
|
|
||||||
[v]
|
|
||||||
(plus (now) v))
|
|
||||||
|
|
||||||
(defn in-past
|
|
||||||
[v]
|
|
||||||
(minus (now) v))
|
|
||||||
|
|
||||||
(defn instant->zoned-date-time
|
|
||||||
[v]
|
|
||||||
(ZonedDateTime/ofInstant v (ZoneId/of "UTC")))
|
|
||||||
|
|
||||||
(defn format-instant
|
|
||||||
([v] (.format DateTimeFormatter/ISO_INSTANT ^Instant v))
|
|
||||||
([v fmt]
|
|
||||||
(case fmt
|
|
||||||
:iso
|
|
||||||
(.format DateTimeFormatter/ISO_INSTANT ^Instant v)
|
|
||||||
|
|
||||||
:iso-local-time
|
|
||||||
(.format DateTimeFormatter/ISO_LOCAL_TIME
|
|
||||||
^ZonedDateTime (instant->zoned-date-time v))
|
|
||||||
|
|
||||||
:rfc1123
|
|
||||||
(.format DateTimeFormatter/RFC_1123_DATE_TIME
|
|
||||||
^ZonedDateTime (instant->zoned-date-time v)))))
|
|
||||||
|
|
||||||
(defmethod print-method Instant
|
|
||||||
[mv ^java.io.Writer writer]
|
|
||||||
(.write writer (str "#app/instant \"" (format-instant mv) "\"")))
|
|
||||||
|
|
||||||
(defmethod print-dup Instant [o w]
|
|
||||||
(print-method o w))
|
|
||||||
|
|
||||||
(extend-protocol fez/IEdn
|
|
||||||
Instant
|
|
||||||
(-edn [o] (tagged-literal 'app/instant (format-instant o))))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Cron Expression
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; Cron expressions are comprised of 6 required fields and one
|
|
||||||
;; optional field separated by white space. The fields respectively
|
|
||||||
;; are described as follows:
|
|
||||||
;;
|
|
||||||
;; Field Name Allowed Values Allowed Special Characters
|
|
||||||
;; Seconds 0-59 , - * /
|
|
||||||
;; Minutes 0-59 , - * /
|
|
||||||
;; Hours 0-23 , - * /
|
|
||||||
;; Day-of-month 1-31 , - * ? / L W
|
|
||||||
;; Month 0-11 or JAN-DEC , - * /
|
|
||||||
;; Day-of-Week 1-7 or SUN-SAT , - * ? / L #
|
|
||||||
;; Year (Optional) empty, 1970-2199 , - * /
|
|
||||||
;;
|
|
||||||
;; The '*' character is used to specify all values. For example, "*"
|
|
||||||
;; in the minute field means "every minute".
|
|
||||||
;;
|
|
||||||
;; The '?' character is allowed for the day-of-month and day-of-week
|
|
||||||
;; fields. It is used to specify 'no specific value'. This is useful
|
|
||||||
;; when you need to specify something in one of the two fields, but
|
|
||||||
;; not the other.
|
|
||||||
;;
|
|
||||||
;; The '-' character is used to specify ranges For example "10-12" in
|
|
||||||
;; the hour field means "the hours 10, 11 and 12".
|
|
||||||
;;
|
|
||||||
;; The ',' character is used to specify additional values. For
|
|
||||||
;; example "MON,WED,FRI" in the day-of-week field means "the days
|
|
||||||
;; Monday, Wednesday, and Friday".
|
|
||||||
;;
|
|
||||||
;; The '/' character is used to specify increments. For example "0/15"
|
|
||||||
;; in the seconds field means "the seconds 0, 15, 30, and
|
|
||||||
;; 45". And "5/15" in the seconds field means "the seconds 5, 20, 35,
|
|
||||||
;; and 50". Specifying '*' before the '/' is equivalent to specifying
|
|
||||||
;; 0 is the value to start with. Essentially, for each field in the
|
|
||||||
;; expression, there is a set of numbers that can be turned on or
|
|
||||||
;; off. For seconds and minutes, the numbers range from 0 to 59. For
|
|
||||||
;; hours 0 to 23, for days of the month 0 to 31, and for months 0 to
|
|
||||||
;; 11 (JAN to DEC). The "/" character simply helps you turn on
|
|
||||||
;; every "nth" value in the given set. Thus "7/6" in the month field
|
|
||||||
;; only turns on month "7", it does NOT mean every 6th month, please
|
|
||||||
;; note that subtlety.
|
|
||||||
;;
|
|
||||||
;; The 'L' character is allowed for the day-of-month and day-of-week
|
|
||||||
;; fields. This character is short-hand for "last", but it has
|
|
||||||
;; different meaning in each of the two fields. For example, the
|
|
||||||
;; value "L" in the day-of-month field means "the last day of the
|
|
||||||
;; month" - day 31 for January, day 28 for February on non-leap
|
|
||||||
;; years. If used in the day-of-week field by itself, it simply
|
|
||||||
;; means "7" or "SAT". But if used in the day-of-week field after
|
|
||||||
;; another value, it means "the last xxx day of the month" - for
|
|
||||||
;; example "6L" means "the last friday of the month". You can also
|
|
||||||
;; specify an offset from the last day of the month, such as "L-3"
|
|
||||||
;; which would mean the third-to-last day of the calendar month. When
|
|
||||||
;; using the 'L' option, it is important not to specify lists, or
|
|
||||||
;; ranges of values, as you'll get confusing/unexpected results.
|
|
||||||
;;
|
|
||||||
;; The 'W' character is allowed for the day-of-month field. This
|
|
||||||
;; character is used to specify the weekday (Monday-Friday) nearest
|
|
||||||
;; the given day. As an example, if you were to specify "15W" as the
|
|
||||||
;; value for the day-of-month field, the meaning is: "the nearest
|
|
||||||
;; weekday to the 15th of the month". So if the 15th is a Saturday,
|
|
||||||
;; the trigger will fire on Friday the 14th. If the 15th is a Sunday,
|
|
||||||
;; the trigger will fire on Monday the 16th. If the 15th is a Tuesday,
|
|
||||||
;; then it will fire on Tuesday the 15th. However if you specify "1W"
|
|
||||||
;; as the value for day-of-month, and the 1st is a Saturday, the
|
|
||||||
;; trigger will fire on Monday the 3rd, as it will not 'jump' over the
|
|
||||||
;; boundary of a month's days. The 'W' character can only be specified
|
|
||||||
;; when the day-of-month is a single day, not a range or list of days.
|
|
||||||
;;
|
|
||||||
;; The 'L' and 'W' characters can also be combined for the
|
|
||||||
;; day-of-month expression to yield 'LW', which translates to "last
|
|
||||||
;; weekday of the month".
|
|
||||||
;;
|
|
||||||
;; The '#' character is allowed for the day-of-week field. This
|
|
||||||
;; character is used to specify "the nth" XXX day of the month. For
|
|
||||||
;; example, the value of "6#3" in the day-of-week field means the
|
|
||||||
;; third Friday of the month (day 6 = Friday and "#3" = the 3rd one in
|
|
||||||
;; the month). Other examples: "2#1" = the first Monday of the month
|
|
||||||
;; and "4#5" = the fifth Wednesday of the month. Note that if you
|
|
||||||
;; specify "#5" and there is not 5 of the given day-of-week in the
|
|
||||||
;; month, then no firing will occur that month. If the '#' character
|
|
||||||
;; is used, there can only be one expression in the day-of-week
|
|
||||||
;; field ("3#1,6#3" is not valid, since there are two expressions).
|
|
||||||
;;
|
|
||||||
;; The legal characters and the names of months and days of the week
|
|
||||||
;; are not case sensitive.
|
|
||||||
|
|
||||||
(defn cron
|
|
||||||
"Creates an instance of CronExpression from string."
|
|
||||||
[s]
|
|
||||||
(try
|
|
||||||
(CronExpression. s)
|
|
||||||
(catch java.text.ParseException e
|
|
||||||
(ex/raise :type :parse
|
|
||||||
:code :invalid-cron-expression
|
|
||||||
:cause e
|
|
||||||
:context {:expr s}))))
|
|
||||||
|
|
||||||
(defn cron?
|
|
||||||
[v]
|
|
||||||
(instance? CronExpression v))
|
|
||||||
|
|
||||||
(defn next-valid-instant-from
|
|
||||||
[^CronExpression cron ^Instant now]
|
|
||||||
(s/assert cron? cron)
|
|
||||||
(.toInstant (.getNextValidTimeAfter cron (Date/from now))))
|
|
||||||
|
|
||||||
(defn get-next
|
|
||||||
[cron tnow]
|
|
||||||
(let [nt (next-valid-instant-from cron tnow)]
|
|
||||||
(cons nt (lazy-seq (get-next cron nt)))))
|
|
||||||
|
|
||||||
(defmethod print-method CronExpression
|
|
||||||
[mv ^java.io.Writer writer]
|
|
||||||
(.write writer (str "#app/cron \"" (.toString ^CronExpression mv) "\"")))
|
|
||||||
|
|
||||||
(defmethod print-dup CronExpression
|
|
||||||
[o w]
|
|
||||||
(print-ctor o (fn [o w] (print-dup (.toString ^CronExpression o) w)) w))
|
|
||||||
|
|
||||||
(extend-protocol fez/IEdn
|
|
||||||
CronExpression
|
|
||||||
(-edn [o] (pr-str o)))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Measurement Helpers
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
(defn tpoint
|
|
||||||
"Create a measurement checkpoint for time measurement of potentially
|
|
||||||
asynchronous flow."
|
|
||||||
[]
|
|
||||||
(let [p1 (System/nanoTime)]
|
|
||||||
#(duration {:nanos (- (System/nanoTime) p1)})))
|
|
||||||
|
|
||||||
(sm/register!
|
|
||||||
{:type ::instant
|
|
||||||
:pred instant?
|
|
||||||
:type-properties
|
|
||||||
{:error/message "should be an instant"
|
|
||||||
:title "instant"
|
|
||||||
:decode/string instant
|
|
||||||
:encode/string format-instant
|
|
||||||
:decode/json instant
|
|
||||||
:encode/json format-instant
|
|
||||||
:gen/gen (tgen/fmap (fn [i] (in-past i)) tgen/pos-int)
|
|
||||||
::oapi/type "string"
|
|
||||||
::oapi/format "iso"}})
|
|
||||||
|
|
||||||
(sm/register!
|
|
||||||
{:type ::duration
|
|
||||||
:pred duration?
|
|
||||||
:type-properties
|
|
||||||
{:error/message "should be a duration"
|
|
||||||
:gen/gen (tgen/fmap duration tgen/pos-int)
|
|
||||||
:title "duration"
|
|
||||||
:decode/string duration
|
|
||||||
:encode/string format-duration
|
|
||||||
:decode/json duration
|
|
||||||
:encode/json format-duration
|
|
||||||
::oapi/type "string"
|
|
||||||
::oapi/format "duration"}})
|
|
||||||
@@ -9,10 +9,10 @@
|
|||||||
(:require
|
(:require
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.util.inet :as inet]
|
[app.util.inet :as inet]
|
||||||
[app.util.time :as dt]
|
|
||||||
[promesa.exec :as px]
|
[promesa.exec :as px]
|
||||||
[promesa.exec.csp :as sp]
|
[promesa.exec.csp :as sp]
|
||||||
[promesa.util :as pu]
|
[promesa.util :as pu]
|
||||||
@@ -93,7 +93,7 @@
|
|||||||
(assoc ::id id)
|
(assoc ::id id)
|
||||||
(assoc ::state state)
|
(assoc ::state state)
|
||||||
(assoc ::beats beats)
|
(assoc ::beats beats)
|
||||||
(assoc ::created-at (dt/now))
|
(assoc ::created-at (ct/now))
|
||||||
(assoc ::input-ch input-ch)
|
(assoc ::input-ch input-ch)
|
||||||
(assoc ::heartbeat-ch hbeat-ch)
|
(assoc ::heartbeat-ch hbeat-ch)
|
||||||
(assoc ::output-ch output-ch)
|
(assoc ::output-ch output-ch)
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
(let [options (-> options
|
(let [options (-> options
|
||||||
(assoc ::channel channel)
|
(assoc ::channel channel)
|
||||||
(on-connect))
|
(on-connect))
|
||||||
timeout (dt/duration idle-timeout)]
|
timeout (ct/duration idle-timeout)]
|
||||||
|
|
||||||
(yws/set-idle-timeout! channel timeout)
|
(yws/set-idle-timeout! channel timeout)
|
||||||
(px/submit! :vthread (partial start-io-loop! options))))
|
(px/submit! :vthread (partial start-io-loop! options))))
|
||||||
@@ -128,7 +128,7 @@
|
|||||||
(fn on-message [_channel message]
|
(fn on-message [_channel message]
|
||||||
(when (string? message)
|
(when (string? message)
|
||||||
(sp/offer! input-ch message)
|
(sp/offer! input-ch message)
|
||||||
(swap! state assoc ::last-activity-at (dt/now))))
|
(swap! state assoc ::last-activity-at (ct/now))))
|
||||||
|
|
||||||
:on-pong
|
:on-pong
|
||||||
(fn on-pong [_channel data]
|
(fn on-pong [_channel data]
|
||||||
|
|||||||
@@ -10,11 +10,11 @@
|
|||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.metrics :as mtx]
|
[app.metrics :as mtx]
|
||||||
[app.util.time :as dt]
|
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[integrant.core :as ig]))
|
[integrant.core :as ig]))
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
[f metrics tname]
|
[f metrics tname]
|
||||||
(let [labels (into-array String [tname])]
|
(let [labels (into-array String [tname])]
|
||||||
(fn [params]
|
(fn [params]
|
||||||
(let [tp (dt/tpoint)]
|
(let [tp (ct/tpoint)]
|
||||||
(try
|
(try
|
||||||
(f params)
|
(f params)
|
||||||
(finally
|
(finally
|
||||||
@@ -95,7 +95,7 @@
|
|||||||
[::task [:or ::sm/text :keyword]]
|
[::task [:or ::sm/text :keyword]]
|
||||||
[::label {:optional true} ::sm/text]
|
[::label {:optional true} ::sm/text]
|
||||||
[::delay {:optional true}
|
[::delay {:optional true}
|
||||||
[:or ::sm/int ::dt/duration]]
|
[:or ::sm/int ::ct/duration]]
|
||||||
[::queue {:optional true} [:or ::sm/text :keyword]]
|
[::queue {:optional true} [:or ::sm/text :keyword]]
|
||||||
[::priority {:optional true} ::sm/int]
|
[::priority {:optional true} ::sm/int]
|
||||||
[::max-retries {:optional true} ::sm/int]
|
[::max-retries {:optional true} ::sm/int]
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
|
|
||||||
(check-options! options)
|
(check-options! options)
|
||||||
|
|
||||||
(let [duration (dt/duration delay)
|
(let [duration (ct/duration delay)
|
||||||
interval (db/interval duration)
|
interval (db/interval duration)
|
||||||
props (db/tjson params)
|
props (db/tjson params)
|
||||||
id (uuid/next)
|
id (uuid/next)
|
||||||
@@ -129,7 +129,7 @@
|
|||||||
:queue queue
|
:queue queue
|
||||||
:label label
|
:label label
|
||||||
:dedupe (boolean dedupe)
|
:dedupe (boolean dedupe)
|
||||||
:delay (dt/format-duration duration)
|
:delay (ct/format-duration duration)
|
||||||
:replace (or deleted 0))
|
:replace (or deleted 0))
|
||||||
|
|
||||||
(db/exec-one! conn [sql:insert-new-task id task props queue
|
(db/exec-one! conn [sql:insert-new-task id task props queue
|
||||||
|
|||||||
@@ -10,8 +10,9 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.util.time :as dt]
|
[app.util.cron :as cron]
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[app.worker.runner :refer [get-error-context]]
|
[app.worker.runner :refer [get-error-context]]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
@@ -49,7 +50,7 @@
|
|||||||
[cfg {:keys [id cron] :as task}]
|
[cfg {:keys [id cron] :as task}]
|
||||||
(px/thread
|
(px/thread
|
||||||
{:name (str "penpot/cron-task/" id)}
|
{:name (str "penpot/cron-task/" id)}
|
||||||
(let [tpoint (dt/tpoint)]
|
(let [tpoint (ct/tpoint)]
|
||||||
(try
|
(try
|
||||||
(db/tx-run! cfg (fn [{:keys [::db/conn]}]
|
(db/tx-run! cfg (fn [{:keys [::db/conn]}]
|
||||||
(db/exec-one! conn ["SET LOCAL statement_timeout=0;"])
|
(db/exec-one! conn ["SET LOCAL statement_timeout=0;"])
|
||||||
@@ -57,20 +58,20 @@
|
|||||||
(when (lock-scheduled-task! conn id)
|
(when (lock-scheduled-task! conn id)
|
||||||
(db/update! conn :scheduled-task
|
(db/update! conn :scheduled-task
|
||||||
{:cron-expr (str cron)
|
{:cron-expr (str cron)
|
||||||
:modified-at (dt/now)}
|
:modified-at (ct/now)}
|
||||||
{:id id}
|
{:id id}
|
||||||
{::db/return-keys false})
|
{::db/return-keys false})
|
||||||
(l/dbg :hint "start" :id id)
|
(l/dbg :hint "start" :id id)
|
||||||
((:fn task) task)
|
((:fn task) task)
|
||||||
(let [elapsed (dt/format-duration (tpoint))]
|
(let [elapsed (ct/format-duration (tpoint))]
|
||||||
(l/dbg :hint "end" :id id :elapsed elapsed)))))
|
(l/dbg :hint "end" :id id :elapsed elapsed)))))
|
||||||
|
|
||||||
(catch InterruptedException _
|
(catch InterruptedException _
|
||||||
(let [elapsed (dt/format-duration (tpoint))]
|
(let [elapsed (ct/format-duration (tpoint))]
|
||||||
(l/debug :hint "task interrupted" :id id :elapsed elapsed)))
|
(l/debug :hint "task interrupted" :id id :elapsed elapsed)))
|
||||||
|
|
||||||
(catch Throwable cause
|
(catch Throwable cause
|
||||||
(let [elapsed (dt/format-duration (tpoint))]
|
(let [elapsed (ct/format-duration (tpoint))]
|
||||||
(binding [l/*context* (get-error-context cause task)]
|
(binding [l/*context* (get-error-context cause task)]
|
||||||
(l/err :hint "unhandled exception on running task"
|
(l/err :hint "unhandled exception on running task"
|
||||||
:id id
|
:id id
|
||||||
@@ -82,10 +83,10 @@
|
|||||||
|
|
||||||
(defn- ms-until-valid
|
(defn- ms-until-valid
|
||||||
[cron]
|
[cron]
|
||||||
(assert (dt/cron? cron) "expected cron instance")
|
(assert (cron/cron-expr? cron) "expected cron instance")
|
||||||
(let [now (dt/now)
|
(let [now (ct/now)
|
||||||
next (dt/next-valid-instant-from cron now)]
|
next (cron/next-valid-instant-from cron now)]
|
||||||
(dt/diff now next)))
|
(ct/diff now next)))
|
||||||
|
|
||||||
(defn- schedule-cron-task
|
(defn- schedule-cron-task
|
||||||
[{:keys [::running] :as cfg} {:keys [cron id] :as task}]
|
[{:keys [::running] :as cfg} {:keys [cron id] :as task}]
|
||||||
@@ -93,8 +94,8 @@
|
|||||||
ft (px/schedule! ts (partial execute-cron-task cfg task))]
|
ft (px/schedule! ts (partial execute-cron-task cfg task))]
|
||||||
|
|
||||||
(l/dbg :hint "schedule" :id id
|
(l/dbg :hint "schedule" :id id
|
||||||
:ts (dt/format-duration ts)
|
:ts (ct/format-duration ts)
|
||||||
:at (dt/format-instant (dt/in-future ts)))
|
:at (ct/format-inst (ct/in-future ts)))
|
||||||
|
|
||||||
(swap! running #(into #{ft} (filter p/pending?) %))))
|
(swap! running #(into #{ft} (filter p/pending?) %))))
|
||||||
|
|
||||||
@@ -104,7 +105,7 @@
|
|||||||
[:vector
|
[:vector
|
||||||
[:maybe
|
[:maybe
|
||||||
[:map
|
[:map
|
||||||
[:cron [:fn dt/cron?]]
|
[:cron [:fn cron/cron-expr?]]
|
||||||
[:task :keyword]
|
[:task :keyword]
|
||||||
[:props {:optional true} :map]
|
[:props {:optional true} :map]
|
||||||
[:id {:optional true} :keyword]]]]]
|
[:id {:optional true} :keyword]]]]]
|
||||||
|
|||||||
@@ -10,11 +10,11 @@
|
|||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.metrics :as mtx]
|
[app.metrics :as mtx]
|
||||||
[app.redis :as rds]
|
[app.redis :as rds]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as-alias wrk]
|
[app.worker :as-alias wrk]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[integrant.core :as ig]
|
[integrant.core :as ig]
|
||||||
@@ -32,9 +32,9 @@
|
|||||||
(defmethod ig/expand-key ::wrk/dispatcher
|
(defmethod ig/expand-key ::wrk/dispatcher
|
||||||
[k v]
|
[k v]
|
||||||
{k (-> (d/without-nils v)
|
{k (-> (d/without-nils v)
|
||||||
(assoc ::timeout (dt/duration "10s"))
|
(assoc ::timeout (ct/duration "10s"))
|
||||||
(assoc ::batch-size 100)
|
(assoc ::batch-size 100)
|
||||||
(assoc ::wait-duration (dt/duration "5s")))})
|
(assoc ::wait-duration (ct/duration "5s")))})
|
||||||
|
|
||||||
(defmethod ig/assert-key ::wrk/dispatcher
|
(defmethod ig/assert-key ::wrk/dispatcher
|
||||||
[_ cfg]
|
[_ cfg]
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.metrics :as mtx]
|
[app.metrics :as mtx]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as-alias wrk]
|
[app.worker :as-alias wrk]
|
||||||
[integrant.core :as ig]
|
[integrant.core :as ig]
|
||||||
[promesa.exec :as px])
|
[promesa.exec :as px])
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
(defmethod ig/expand-key ::wrk/monitor
|
(defmethod ig/expand-key ::wrk/monitor
|
||||||
[k v]
|
[k v]
|
||||||
{k (-> (d/without-nils v)
|
{k (-> (d/without-nils v)
|
||||||
(assoc ::interval (dt/duration "2s")))})
|
(assoc ::interval (ct/duration "2s")))})
|
||||||
|
|
||||||
(defmethod ig/init-key ::wrk/monitor
|
(defmethod ig/init-key ::wrk/monitor
|
||||||
[_ {:keys [::wrk/executor ::mtx/metrics ::interval ::wrk/name]}]
|
[_ {:keys [::wrk/executor ::mtx/metrics ::interval ::wrk/name]}]
|
||||||
|
|||||||
@@ -12,11 +12,11 @@
|
|||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.metrics :as mtx]
|
[app.metrics :as mtx]
|
||||||
[app.redis :as rds]
|
[app.redis :as rds]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[integrant.core :as ig]
|
[integrant.core :as ig]
|
||||||
@@ -29,10 +29,10 @@
|
|||||||
[:id ::sm/uuid]
|
[:id ::sm/uuid]
|
||||||
[:queue :string]
|
[:queue :string]
|
||||||
[:name :string]
|
[:name :string]
|
||||||
[:created-at ::sm/inst]
|
[:created-at ::ct/inst]
|
||||||
[:modified-at ::sm/inst]
|
[:modified-at ::ct/inst]
|
||||||
[:scheduled-at {:optional true} ::sm/inst]
|
[:scheduled-at {:optional true} ::ct/inst]
|
||||||
[:completed-at {:optional true} ::sm/inst]
|
[:completed-at {:optional true} ::ct/inst]
|
||||||
[:error {:optional true} :string]
|
[:error {:optional true} :string]
|
||||||
[:max-retries :int]
|
[:max-retries :int]
|
||||||
[:retry-num :int]
|
[:retry-num :int]
|
||||||
@@ -76,10 +76,10 @@
|
|||||||
:queue queue
|
:queue queue
|
||||||
:runner-id id
|
:runner-id id
|
||||||
:retry (:retry-num task))
|
:retry (:retry-num task))
|
||||||
(let [tpoint (dt/tpoint)
|
(let [tpoint (ct/tpoint)
|
||||||
task-fn (wrk/get-task registry (:name task))
|
task-fn (wrk/get-task registry (:name task))
|
||||||
result (when task-fn (task-fn task))
|
result (when task-fn (task-fn task))
|
||||||
elapsed (dt/format-duration (tpoint))
|
elapsed (ct/format-duration (tpoint))
|
||||||
result (if (valid-task-result? result)
|
result (if (valid-task-result? result)
|
||||||
result
|
result
|
||||||
{:status "completed"})]
|
{:status "completed"})]
|
||||||
@@ -105,7 +105,7 @@
|
|||||||
(:max-retries task))
|
(:max-retries task))
|
||||||
(= ::retry (:type edata)))
|
(= ::retry (:type edata)))
|
||||||
(cond-> {:status "retry" :error cause}
|
(cond-> {:status "retry" :error cause}
|
||||||
(dt/duration? (:delay edata))
|
(ct/duration? (:delay edata))
|
||||||
(assoc :delay (:delay edata))
|
(assoc :delay (:delay edata))
|
||||||
|
|
||||||
(= ::noop (:strategy edata))
|
(= ::noop (:strategy edata))
|
||||||
@@ -156,13 +156,13 @@
|
|||||||
(str error))
|
(str error))
|
||||||
task (-> result meta ::task)
|
task (-> result meta ::task)
|
||||||
nretry (+ (:retry-num task) inc-by)
|
nretry (+ (:retry-num task) inc-by)
|
||||||
now (dt/now)
|
now (ct/now)
|
||||||
delay (->> (iterate #(* % 2) delay) (take nretry) (last))]
|
delay (->> (iterate #(* % 2) delay) (take nretry) (last))]
|
||||||
(db/update! pool :task
|
(db/update! pool :task
|
||||||
{:error explain
|
{:error explain
|
||||||
:status "retry"
|
:status "retry"
|
||||||
:modified-at now
|
:modified-at now
|
||||||
:scheduled-at (dt/plus now delay)
|
:scheduled-at (ct/plus now delay)
|
||||||
:retry-num nretry}
|
:retry-num nretry}
|
||||||
{:id (:id task)})
|
{:id (:id task)})
|
||||||
nil))
|
nil))
|
||||||
@@ -172,14 +172,14 @@
|
|||||||
explain (ex-message error)]
|
explain (ex-message error)]
|
||||||
(db/update! pool :task
|
(db/update! pool :task
|
||||||
{:error explain
|
{:error explain
|
||||||
:modified-at (dt/now)
|
:modified-at (ct/now)
|
||||||
:status "failed"}
|
:status "failed"}
|
||||||
{:id (:id task)})
|
{:id (:id task)})
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
(handle-task-completion [result]
|
(handle-task-completion [result]
|
||||||
(let [task (-> result meta ::task)
|
(let [task (-> result meta ::task)
|
||||||
now (dt/now)]
|
now (ct/now)]
|
||||||
(db/update! pool :task
|
(db/update! pool :task
|
||||||
{:completed-at now
|
{:completed-at now
|
||||||
:modified-at now
|
:modified-at now
|
||||||
@@ -255,7 +255,7 @@
|
|||||||
(let [cfg (-> cfg
|
(let [cfg (-> cfg
|
||||||
(assoc ::rds/rconn rconn)
|
(assoc ::rds/rconn rconn)
|
||||||
(assoc ::queue (str/ffmt "%:%" tenant queue))
|
(assoc ::queue (str/ffmt "%:%" tenant queue))
|
||||||
(assoc ::timeout (dt/duration "5s")))]
|
(assoc ::timeout (ct/duration "5s")))]
|
||||||
(loop []
|
(loop []
|
||||||
(when (px/interrupted?)
|
(when (px/interrupted?)
|
||||||
(throw (InterruptedException. "interrupted")))
|
(throw (InterruptedException. "interrupted")))
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
{app/instant app.util.time/instant
|
{penpot/inst app.common.time/inst
|
||||||
app/cron app.util.time/cron
|
penpot/cron app.util.cron/cron
|
||||||
app/duration app.util.time/duration}
|
penpot/duration app.common.time/duration}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.storage.tmp :as tmp]
|
[app.storage.tmp :as tmp]
|
||||||
[app.util.time :as dt]
|
|
||||||
[backend-tests.helpers :as th]
|
[backend-tests.helpers :as th]
|
||||||
[clojure.test :as t]
|
[clojure.test :as t]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
|
|
||||||
(ns backend-tests.bounce-handling-test
|
(ns backend-tests.bounce-handling-test
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.email :as email]
|
[app.email :as email]
|
||||||
[app.http.awsns :as awsns]
|
[app.http.awsns :as awsns]
|
||||||
[app.tokens :as tokens]
|
[app.tokens :as tokens]
|
||||||
[app.util.time :as dt]
|
|
||||||
[backend-tests.helpers :as th]
|
[backend-tests.helpers :as th]
|
||||||
[clojure.pprint :refer [pprint]]
|
[clojure.pprint :refer [pprint]]
|
||||||
[clojure.test :as t]
|
[clojure.test :as t]
|
||||||
@@ -250,7 +250,7 @@
|
|||||||
|
|
||||||
(let [profile (th/create-profile* 1)
|
(let [profile (th/create-profile* 1)
|
||||||
pool (:app.db/pool th/*system*)]
|
pool (:app.db/pool th/*system*)]
|
||||||
(th/create-complaint-for pool {:type :bounce :id (:id profile) :created-at (dt/in-past {:days 8})})
|
(th/create-complaint-for pool {:type :bounce :id (:id profile) :created-at (ct/in-past {:days 8})})
|
||||||
(th/create-complaint-for pool {:type :bounce :id (:id profile)})
|
(th/create-complaint-for pool {:type :bounce :id (:id profile)})
|
||||||
(th/create-complaint-for pool {:type :bounce :id (:id profile)})
|
(th/create-complaint-for pool {:type :bounce :id (:id profile)})
|
||||||
|
|
||||||
@@ -268,8 +268,8 @@
|
|||||||
:profile-complaint-threshold 2})}]
|
:profile-complaint-threshold 2})}]
|
||||||
(let [profile (th/create-profile* 1)
|
(let [profile (th/create-profile* 1)
|
||||||
pool (:app.db/pool th/*system*)]
|
pool (:app.db/pool th/*system*)]
|
||||||
(th/create-complaint-for pool {:type :bounce :id (:id profile) :created-at (dt/in-past {:days 8})})
|
(th/create-complaint-for pool {:type :bounce :id (:id profile) :created-at (ct/in-past {:days 8})})
|
||||||
(th/create-complaint-for pool {:type :bounce :id (:id profile) :created-at (dt/in-past {:days 8})})
|
(th/create-complaint-for pool {:type :bounce :id (:id profile) :created-at (ct/in-past {:days 8})})
|
||||||
(th/create-complaint-for pool {:type :bounce :id (:id profile)})
|
(th/create-complaint-for pool {:type :bounce :id (:id profile)})
|
||||||
(th/create-complaint-for pool {:type :bounce :id (:id profile)})
|
(th/create-complaint-for pool {:type :bounce :id (:id profile)})
|
||||||
(th/create-complaint-for pool {:type :complaint :id (:id profile)})
|
(th/create-complaint-for pool {:type :complaint :id (:id profile)})
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
[app.common.pprint :as pp]
|
[app.common.pprint :as pp]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.transit :as tr]
|
[app.common.transit :as tr]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
@@ -33,7 +34,6 @@
|
|||||||
[app.rpc.helpers :as rph]
|
[app.rpc.helpers :as rph]
|
||||||
[app.util.blob :as blob]
|
[app.util.blob :as blob]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[app.worker.runner]
|
[app.worker.runner]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
@@ -263,7 +263,7 @@
|
|||||||
(dm/with-open [conn (db/open system)]
|
(dm/with-open [conn (db/open system)]
|
||||||
(db/insert! conn :profile-complaint-report
|
(db/insert! conn :profile-complaint-report
|
||||||
{:profile-id id
|
{:profile-id id
|
||||||
:created-at (or created-at (dt/now))
|
:created-at (or created-at (ct/now))
|
||||||
:type (name type)
|
:type (name type)
|
||||||
:content (db/tjson {})})))
|
:content (db/tjson {})})))
|
||||||
|
|
||||||
@@ -273,7 +273,7 @@
|
|||||||
(db/insert! conn :global-complaint-report
|
(db/insert! conn :global-complaint-report
|
||||||
{:email email
|
{:email email
|
||||||
:type (name type)
|
:type (name type)
|
||||||
:created-at (or created-at (dt/now))
|
:created-at (or created-at (ct/now))
|
||||||
:content (db/tjson {})})))
|
:content (db/tjson {})})))
|
||||||
|
|
||||||
(defn create-team-role*
|
(defn create-team-role*
|
||||||
@@ -305,7 +305,7 @@
|
|||||||
([system {:keys [file-id changes session-id profile-id revn]
|
([system {:keys [file-id changes session-id profile-id revn]
|
||||||
:or {session-id (uuid/next) revn 0}}]
|
:or {session-id (uuid/next) revn 0}}]
|
||||||
(-> system
|
(-> system
|
||||||
(assoc ::files.update/timestamp (dt/now))
|
(assoc ::files.update/timestamp (ct/now))
|
||||||
(db/tx-run! (fn [{:keys [::db/conn] :as system}]
|
(db/tx-run! (fn [{:keys [::db/conn] :as system}]
|
||||||
(let [file (files.update/get-file conn file-id)]
|
(let [file (files.update/get-file conn file-id)]
|
||||||
(#'files.update/update-file* system
|
(#'files.update/update-file* system
|
||||||
@@ -379,7 +379,7 @@
|
|||||||
;; (app.common.pprint/pprint (:app.rpc/methods *system*))
|
;; (app.common.pprint/pprint (:app.rpc/methods *system*))
|
||||||
(try-on! (method-fn (-> data
|
(try-on! (method-fn (-> data
|
||||||
(dissoc ::type)
|
(dissoc ::type)
|
||||||
(assoc :app.rpc/request-at (dt/now)))))))
|
(assoc :app.rpc/request-at (ct/now)))))))
|
||||||
|
|
||||||
(defn run-task!
|
(defn run-task!
|
||||||
([name]
|
([name]
|
||||||
@@ -525,7 +525,7 @@
|
|||||||
|
|
||||||
(defn sleep
|
(defn sleep
|
||||||
[ms-or-duration]
|
[ms-or-duration]
|
||||||
(Thread/sleep (inst-ms (dt/duration ms-or-duration))))
|
(Thread/sleep (inst-ms (ct/duration ms-or-duration))))
|
||||||
|
|
||||||
(defn config-get-mock
|
(defn config-get-mock
|
||||||
[data]
|
[data]
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
(ns backend-tests.rpc-audit-test
|
(ns backend-tests.rpc-audit-test
|
||||||
(:require
|
(:require
|
||||||
[app.common.pprint :as pp]
|
[app.common.pprint :as pp]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.util.time :as dt]
|
|
||||||
[backend-tests.helpers :as th]
|
[backend-tests.helpers :as th]
|
||||||
[clojure.test :as t]
|
[clojure.test :as t]
|
||||||
[yetti.request]))
|
[yetti.request]))
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
:route "dashboard-files"}
|
:route "dashboard-files"}
|
||||||
:context {:engine "blink"}
|
:context {:engine "blink"}
|
||||||
:profile-id (:id prof)
|
:profile-id (:id prof)
|
||||||
:timestamp (dt/now)
|
:timestamp (ct/now)
|
||||||
:type "action"}]}
|
:type "action"}]}
|
||||||
|
|
||||||
params (with-meta params
|
params (with-meta params
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
:route "dashboard-files"}
|
:route "dashboard-files"}
|
||||||
:context {:engine "blink"}
|
:context {:engine "blink"}
|
||||||
:profile-id uuid/zero
|
:profile-id uuid/zero
|
||||||
:timestamp (dt/now)
|
:timestamp (ct/now)
|
||||||
:type "action"}]}
|
:type "action"}]}
|
||||||
params (with-meta params
|
params (with-meta params
|
||||||
{:app.http/request http-request})
|
{:app.http/request http-request})
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
(ns backend-tests.rpc-comment-test
|
(ns backend-tests.rpc-comment-test
|
||||||
(:require
|
(:require
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.http :as http]
|
[app.http :as http]
|
||||||
@@ -14,7 +15,6 @@
|
|||||||
[app.rpc.commands.comments :as comments]
|
[app.rpc.commands.comments :as comments]
|
||||||
[app.rpc.cond :as cond]
|
[app.rpc.cond :as cond]
|
||||||
[app.rpc.quotes :as-alias quotes]
|
[app.rpc.quotes :as-alias quotes]
|
||||||
[app.util.time :as dt]
|
|
||||||
[backend-tests.helpers :as th]
|
[backend-tests.helpers :as th]
|
||||||
[clojure.test :as t]
|
[clojure.test :as t]
|
||||||
[datoteka.fs :as fs]
|
[datoteka.fs :as fs]
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
|
|
||||||
(let [{:keys [result] :as out} (th/command! data)]
|
(let [{:keys [result] :as out} (th/command! data)]
|
||||||
(t/is (th/success? out))
|
(t/is (th/success? out))
|
||||||
(t/is (dt/instant? (:modified-at result))))
|
(t/is (ct/inst? (:modified-at result))))
|
||||||
|
|
||||||
(let [status' (th/db-get :comment-thread-status
|
(let [status' (th/db-get :comment-thread-status
|
||||||
{:thread-id (:id thread)
|
{:thread-id (:id thread)
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
[app.http :as http]
|
[app.http :as http]
|
||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.util.time :as dt]
|
|
||||||
[backend-tests.helpers :as th]
|
[backend-tests.helpers :as th]
|
||||||
[clojure.test :as t]
|
[clojure.test :as t]
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
[app.common.features :as cfeat]
|
[app.common.features :as cfeat]
|
||||||
[app.common.pprint :as pp]
|
[app.common.pprint :as pp]
|
||||||
[app.common.thumbnails :as thc]
|
[app.common.thumbnails :as thc]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.shape :as cts]
|
[app.common.types.shape :as cts]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
@@ -18,7 +19,6 @@
|
|||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.rpc.commands.files :as files]
|
[app.rpc.commands.files :as files]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.util.time :as dt]
|
|
||||||
[backend-tests.helpers :as th]
|
[backend-tests.helpers :as th]
|
||||||
[clojure.test :as t]
|
[clojure.test :as t]
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
@@ -135,7 +135,7 @@
|
|||||||
(t/is (nil? (:users result))))))
|
(t/is (nil? (:users result))))))
|
||||||
|
|
||||||
(th/db-update! :file
|
(th/db-update! :file
|
||||||
{:deleted-at (dt/now)}
|
{:deleted-at (ct/now)}
|
||||||
{:id file-id})
|
{:id file-id})
|
||||||
|
|
||||||
(t/testing "query single file after delete and wait"
|
(t/testing "query single file after delete and wait"
|
||||||
@@ -1844,7 +1844,7 @@
|
|||||||
|
|
||||||
(th/run-task! :delete-object
|
(th/run-task! :delete-object
|
||||||
{:object :file
|
{:object :file
|
||||||
:deleted-at (dt/now)
|
:deleted-at (ct/now)
|
||||||
:id (:id file-1)})
|
:id (:id file-1)})
|
||||||
|
|
||||||
;; Check that file media object references are marked all for deletion
|
;; Check that file media object references are marked all for deletion
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
[app.rpc.commands.auth :as cauth]
|
[app.rpc.commands.auth :as cauth]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.tokens :as tokens]
|
[app.tokens :as tokens]
|
||||||
[app.util.time :as dt]
|
|
||||||
[backend-tests.helpers :as th]
|
[backend-tests.helpers :as th]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[clojure.test :as t]
|
[clojure.test :as t]
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
|
|
||||||
(ns backend-tests.rpc-media-test
|
(ns backend-tests.rpc-media-test
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.util.time :as dt]
|
|
||||||
[backend-tests.helpers :as th]
|
[backend-tests.helpers :as th]
|
||||||
[clojure.test :as t]
|
[clojure.test :as t]
|
||||||
[datoteka.fs :as fs]))
|
[datoteka.fs :as fs]))
|
||||||
@@ -257,7 +257,7 @@
|
|||||||
:is-shared false})
|
:is-shared false})
|
||||||
|
|
||||||
_ (th/db-update! :file
|
_ (th/db-update! :file
|
||||||
{:deleted-at (dt/now)}
|
{:deleted-at (ct/now)}
|
||||||
{:id (:id file)})
|
{:id (:id file)})
|
||||||
|
|
||||||
mfile {:filename "sample.jpg"
|
mfile {:filename "sample.jpg"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
(ns backend-tests.rpc-profile-test
|
(ns backend-tests.rpc-profile-test
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -14,7 +15,6 @@
|
|||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.rpc.commands.profile :as profile]
|
[app.rpc.commands.profile :as profile]
|
||||||
[app.tokens :as tokens]
|
[app.tokens :as tokens]
|
||||||
[app.util.time :as dt]
|
|
||||||
[backend-tests.helpers :as th]
|
[backend-tests.helpers :as th]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[clojure.test :as t]
|
[clojure.test :as t]
|
||||||
@@ -158,7 +158,7 @@
|
|||||||
(let [row (th/db-get :team
|
(let [row (th/db-get :team
|
||||||
{:id (:default-team-id prof)}
|
{:id (:default-team-id prof)}
|
||||||
{::db/remove-deleted false})]
|
{::db/remove-deleted false})]
|
||||||
(t/is (dt/instant? (:deleted-at row))))
|
(t/is (ct/inst? (:deleted-at row))))
|
||||||
|
|
||||||
;; execute permanent deletion task
|
;; execute permanent deletion task
|
||||||
(let [result (th/run-task! :objects-gc {:min-age 0})]
|
(let [result (th/run-task! :objects-gc {:min-age 0})]
|
||||||
@@ -212,7 +212,7 @@
|
|||||||
;; (th/print-result! out)
|
;; (th/print-result! out)
|
||||||
|
|
||||||
(let [team (th/db-get :team {:id (:id team1)} {::db/remove-deleted false})]
|
(let [team (th/db-get :team {:id (:id team1)} {::db/remove-deleted false})]
|
||||||
(t/is (dt/instant? (:deleted-at team)))))
|
(t/is (ct/inst? (:deleted-at team)))))
|
||||||
|
|
||||||
;; Request profile to be deleted
|
;; Request profile to be deleted
|
||||||
(let [params {::th/type :delete-profile
|
(let [params {::th/type :delete-profile
|
||||||
@@ -517,7 +517,7 @@
|
|||||||
(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
|
||||||
:exp (dt/in-future "48h")
|
:exp (ct/in-future "48h")
|
||||||
:role :editor
|
:role :editor
|
||||||
:team-id uuid/zero
|
:team-id uuid/zero
|
||||||
:member-email "user@example.com"})
|
:member-email "user@example.com"})
|
||||||
@@ -546,7 +546,7 @@
|
|||||||
(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
|
||||||
:exp (dt/in-future "48h")
|
:exp (ct/in-future "48h")
|
||||||
:role :editor
|
:role :editor
|
||||||
:team-id uuid/zero
|
:team-id uuid/zero
|
||||||
:member-email "user2@example.com"})
|
:member-email "user2@example.com"})
|
||||||
@@ -568,7 +568,7 @@
|
|||||||
(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
|
||||||
:exp (dt/in-future "48h")
|
:exp (ct/in-future "48h")
|
||||||
:role :editor
|
:role :editor
|
||||||
:team-id uuid/zero
|
:team-id uuid/zero
|
||||||
:member-email "user@example.com"})
|
:member-email "user@example.com"})
|
||||||
@@ -589,7 +589,7 @@
|
|||||||
(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
|
||||||
:exp (dt/in-future "48h")
|
:exp (ct/in-future "48h")
|
||||||
:role :editor
|
:role :editor
|
||||||
:team-id uuid/zero
|
:team-id uuid/zero
|
||||||
:member-email "user2@example.com"})
|
:member-email "user2@example.com"})
|
||||||
@@ -611,7 +611,7 @@
|
|||||||
(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
|
||||||
:exp (dt/in-future "48h")
|
:exp (ct/in-future "48h")
|
||||||
:role :editor
|
:role :editor
|
||||||
:team-id uuid/zero
|
:team-id uuid/zero
|
||||||
:member-email "user2@example.com"})
|
:member-email "user2@example.com"})
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.http :as http]
|
[app.http :as http]
|
||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.util.time :as dt]
|
|
||||||
[backend-tests.helpers :as th]
|
[backend-tests.helpers :as th]
|
||||||
[clojure.test :as t]))
|
[clojure.test :as t]))
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
(ns backend-tests.rpc-team-test
|
(ns backend-tests.rpc-team-test
|
||||||
(:require
|
(:require
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
@@ -14,7 +15,6 @@
|
|||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.tokens :as tokens]
|
[app.tokens :as tokens]
|
||||||
[app.util.time :as dt]
|
|
||||||
[backend-tests.helpers :as th]
|
[backend-tests.helpers :as th]
|
||||||
[clojure.test :as t]
|
[clojure.test :as t]
|
||||||
[datoteka.fs :as fs]
|
[datoteka.fs :as fs]
|
||||||
@@ -163,7 +163,7 @@
|
|||||||
|
|
||||||
;; Proceed to delete the requester user
|
;; Proceed to delete the requester user
|
||||||
(th/db-update! :profile
|
(th/db-update! :profile
|
||||||
{:deleted-at (dt/in-past "1h")}
|
{:deleted-at (ct/in-past "1h")}
|
||||||
{:id (:id requester)})
|
{:id (:id requester)})
|
||||||
|
|
||||||
;; Create a new profile with the same email
|
;; Create a new profile with the same email
|
||||||
@@ -271,7 +271,7 @@
|
|||||||
|
|
||||||
(let [token (tokens/generate sprops
|
(let [token (tokens/generate sprops
|
||||||
{:iss :team-invitation
|
{:iss :team-invitation
|
||||||
:exp (dt/in-future "1h")
|
:exp (ct/in-future "1h")
|
||||||
:profile-id (:id profile1)
|
:profile-id (:id profile1)
|
||||||
:role :editor
|
:role :editor
|
||||||
:team-id (:id team)
|
:team-id (:id team)
|
||||||
@@ -283,7 +283,7 @@
|
|||||||
{:team-id (:id team)
|
{:team-id (:id team)
|
||||||
:email-to (:email profile2)
|
:email-to (:email profile2)
|
||||||
:role "editor"
|
:role "editor"
|
||||||
:valid-until (dt/in-future "48h")})
|
:valid-until (ct/in-future "48h")})
|
||||||
|
|
||||||
(let [data {::th/type :verify-token :token token}
|
(let [data {::th/type :verify-token :token token}
|
||||||
out (th/command! data)]
|
out (th/command! data)]
|
||||||
@@ -328,7 +328,7 @@
|
|||||||
{:team-id (:id team)
|
{:team-id (:id team)
|
||||||
:email-to (:email profile3)
|
:email-to (:email profile3)
|
||||||
:role "editor"
|
:role "editor"
|
||||||
:valid-until (dt/in-future "48h")})
|
:valid-until (ct/in-future "48h")})
|
||||||
|
|
||||||
(let [data {::th/type :verify-token
|
(let [data {::th/type :verify-token
|
||||||
::rpc/profile-id (:id profile1)
|
::rpc/profile-id (:id profile1)
|
||||||
@@ -381,14 +381,14 @@
|
|||||||
{:team-id (:team-id data)
|
{:team-id (:team-id data)
|
||||||
:email-to "test1@mail.com"
|
:email-to "test1@mail.com"
|
||||||
:role "editor"
|
:role "editor"
|
||||||
:valid-until (dt/in-future "48h")})
|
:valid-until (ct/in-future "48h")})
|
||||||
|
|
||||||
;; insert an entry on the database with an expired invitation
|
;; insert an entry on the database with an expired invitation
|
||||||
(db/insert! th/*pool* :team-invitation
|
(db/insert! th/*pool* :team-invitation
|
||||||
{:team-id (:team-id data)
|
{:team-id (:team-id data)
|
||||||
:email-to "test2@mail.com"
|
:email-to "test2@mail.com"
|
||||||
:role "editor"
|
:role "editor"
|
||||||
:valid-until (dt/in-past "48h")})
|
:valid-until (ct/in-past "48h")})
|
||||||
|
|
||||||
(let [out (th/command! data)]
|
(let [out (th/command! data)]
|
||||||
(t/is (th/success? out))
|
(t/is (th/success? out))
|
||||||
@@ -415,7 +415,7 @@
|
|||||||
{:team-id (:team-id data)
|
{:team-id (:team-id data)
|
||||||
:email-to "test1@mail.com"
|
:email-to "test1@mail.com"
|
||||||
:role "editor"
|
:role "editor"
|
||||||
:valid-until (dt/in-future "48h")})
|
:valid-until (ct/in-future "48h")})
|
||||||
|
|
||||||
(let [out (th/command! data)
|
(let [out (th/command! data)
|
||||||
;; retrieve the value from the database and check its content
|
;; retrieve the value from the database and check its content
|
||||||
@@ -438,7 +438,7 @@
|
|||||||
{:team-id (:team-id data)
|
{:team-id (:team-id data)
|
||||||
:email-to "test1@mail.com"
|
:email-to "test1@mail.com"
|
||||||
:role "editor"
|
:role "editor"
|
||||||
:valid-until (dt/in-future "48h")})
|
:valid-until (ct/in-future "48h")})
|
||||||
|
|
||||||
(let [out (th/command! data)
|
(let [out (th/command! data)
|
||||||
;; retrieve the value from the database and check its content
|
;; retrieve the value from the database and check its content
|
||||||
@@ -582,7 +582,7 @@
|
|||||||
|
|
||||||
(let [rows (th/db-exec! ["select * from team where id = ?" (:id team)])]
|
(let [rows (th/db-exec! ["select * from team where id = ?" (:id team)])]
|
||||||
(t/is (= 1 (count rows)))
|
(t/is (= 1 (count rows)))
|
||||||
(t/is (dt/instant? (:deleted-at (first rows)))))
|
(t/is (ct/inst? (:deleted-at (first rows)))))
|
||||||
|
|
||||||
(let [result (th/run-task! :objects-gc {:deletion-threshold (cf/get-deletion-delay)})]
|
(let [result (th/run-task! :objects-gc {:deletion-threshold (cf/get-deletion-delay)})]
|
||||||
(t/is (= 5 (:processed result))))))
|
(t/is (= 5 (:processed result))))))
|
||||||
@@ -626,7 +626,7 @@
|
|||||||
(th/reset-mock! mock)
|
(th/reset-mock! mock)
|
||||||
|
|
||||||
(th/db-update! :team-access-request
|
(th/db-update! :team-access-request
|
||||||
{:valid-until (dt/in-past "1h")}
|
{:valid-until (ct/in-past "1h")}
|
||||||
{:team-id (:id team)
|
{:team-id (:id team)
|
||||||
:requester-id (:id requester)})
|
:requester-id (:id requester)})
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
(ns backend-tests.storage-test
|
(ns backend-tests.storage-test
|
||||||
(:require
|
(:require
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.util.time :as dt]
|
|
||||||
[backend-tests.helpers :as th]
|
[backend-tests.helpers :as th]
|
||||||
[clojure.test :as t]
|
[clojure.test :as t]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
@@ -53,12 +53,12 @@
|
|||||||
(configure-storage-backend))
|
(configure-storage-backend))
|
||||||
content (sto/content "content")
|
content (sto/content "content")
|
||||||
object (sto/put-object! storage {::sto/content content
|
object (sto/put-object! storage {::sto/content content
|
||||||
::sto/expired-at (dt/in-future {:seconds 1})
|
::sto/expired-at (ct/in-future {:seconds 1})
|
||||||
:content-type "text/plain"})]
|
:content-type "text/plain"})]
|
||||||
|
|
||||||
(t/is (sto/object? object))
|
(t/is (sto/object? object))
|
||||||
(t/is (dt/instant? (:expired-at object)))
|
(t/is (ct/inst? (:expired-at object)))
|
||||||
(t/is (dt/is-after? (:expired-at object) (dt/now)))
|
(t/is (ct/is-after? (:expired-at object) (ct/now)))
|
||||||
(t/is (= object (sto/get-object storage (:id object))))
|
(t/is (= object (sto/get-object storage (:id object))))
|
||||||
|
|
||||||
(th/sleep 1000)
|
(th/sleep 1000)
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
content (sto/content "content")
|
content (sto/content "content")
|
||||||
object (sto/put-object! storage {::sto/content content
|
object (sto/put-object! storage {::sto/content content
|
||||||
:content-type "text/plain"
|
:content-type "text/plain"
|
||||||
:expired-at (dt/in-future {:seconds 1})})]
|
:expired-at (ct/in-future {:seconds 1})})]
|
||||||
(t/is (sto/object? object))
|
(t/is (sto/object? object))
|
||||||
(t/is (true? (sto/del-object! storage object)))
|
(t/is (true? (sto/del-object! storage object)))
|
||||||
|
|
||||||
@@ -95,13 +95,13 @@
|
|||||||
content3 (sto/content "content3")
|
content3 (sto/content "content3")
|
||||||
|
|
||||||
object1 (sto/put-object! storage {::sto/content content1
|
object1 (sto/put-object! storage {::sto/content content1
|
||||||
::sto/expired-at (dt/now)
|
::sto/expired-at (ct/now)
|
||||||
:content-type "text/plain"})
|
:content-type "text/plain"})
|
||||||
object2 (sto/put-object! storage {::sto/content content2
|
object2 (sto/put-object! storage {::sto/content content2
|
||||||
::sto/expired-at (dt/in-past {:hours 2})
|
::sto/expired-at (ct/in-past {:hours 2})
|
||||||
:content-type "text/plain"})
|
:content-type "text/plain"})
|
||||||
object3 (sto/put-object! storage {::sto/content content3
|
object3 (sto/put-object! storage {::sto/content content3
|
||||||
::sto/expired-at (dt/in-past {:hours 1})
|
::sto/expired-at (ct/in-past {:hours 1})
|
||||||
:content-type "text/plain"})]
|
:content-type "text/plain"})]
|
||||||
|
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@
|
|||||||
(t/is (= (:media-id result-1) (:media-id result-2)))
|
(t/is (= (:media-id result-1) (:media-id result-2)))
|
||||||
|
|
||||||
(th/db-update! :file-media-object
|
(th/db-update! :file-media-object
|
||||||
{:deleted-at (dt/now)}
|
{:deleted-at (ct/now)}
|
||||||
{:id (:id result-1)})
|
{:id (:id result-1)})
|
||||||
|
|
||||||
;; run the objects gc task for permanent deletion
|
;; run the objects gc task for permanent deletion
|
||||||
@@ -239,7 +239,7 @@
|
|||||||
result-2 (:result out2)]
|
result-2 (:result out2)]
|
||||||
|
|
||||||
(th/db-update! :team-font-variant
|
(th/db-update! :team-font-variant
|
||||||
{:deleted-at (dt/now)}
|
{:deleted-at (ct/now)}
|
||||||
{:id (:id result-2)})
|
{:id (:id result-2)})
|
||||||
|
|
||||||
;; run the objects gc task for permanent deletion
|
;; run the objects gc task for permanent deletion
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
(ns backend-tests.tasks-telemetry-test
|
(ns backend-tests.tasks-telemetry-test
|
||||||
(:require
|
(:require
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.util.time :as dt]
|
|
||||||
[backend-tests.helpers :as th]
|
[backend-tests.helpers :as th]
|
||||||
[clojure.pprint :refer [pprint]]
|
[clojure.pprint :refer [pprint]]
|
||||||
[clojure.test :as t]
|
[clojure.test :as t]
|
||||||
|
|||||||
@@ -10,15 +10,15 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/penpot/penpot"
|
"url": "https://github.com/penpot/penpot"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
|
||||||
"luxon": "^3.6.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^9.1.2",
|
"concurrently": "^9.1.2",
|
||||||
"nodemon": "^3.1.10",
|
"nodemon": "^3.1.10",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"ws": "^8.18.2"
|
"ws": "^8.18.2"
|
||||||
},
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"date-fns": "^4.1.0"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"fmt:clj:check": "cljfmt check --parallel=false src/ test/",
|
"fmt:clj:check": "cljfmt check --parallel=false src/ test/",
|
||||||
"fmt:clj": "cljfmt fix --parallel=true src/ test/",
|
"fmt:clj": "cljfmt fix --parallel=true src/ test/",
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
[app.common.schema.generators :as sg]
|
[app.common.schema.generators :as sg]
|
||||||
[app.common.schema.openapi :as-alias oapi]
|
[app.common.schema.openapi :as-alias oapi]
|
||||||
[app.common.schema.registry :as sr]
|
[app.common.schema.registry :as sr]
|
||||||
[app.common.time :as tm]
|
|
||||||
[app.common.uri :as u]
|
[app.common.uri :as u]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[clojure.core :as c]
|
[clojure.core :as c]
|
||||||
@@ -850,38 +849,38 @@
|
|||||||
{:title "contains any"
|
{:title "contains any"
|
||||||
:description "contains predicate"}}))})
|
:description "contains predicate"}}))})
|
||||||
|
|
||||||
(register!
|
;; (register!
|
||||||
{:type ::inst
|
;; {:type ::inst
|
||||||
:pred inst?
|
;; :pred tm/instant?
|
||||||
:type-properties
|
;; :type-properties
|
||||||
{:title "inst"
|
;; {:title "inst"
|
||||||
:description "Satisfies Inst protocol"
|
;; :description "Satisfies Inst protocol"
|
||||||
:error/message "should be an instant"
|
;; :error/message "should be an instant"
|
||||||
:gen/gen (->> (sg/small-int :min 0 :max 100000)
|
;; :gen/gen (->> (sg/small-int :min 0 :max 100000)
|
||||||
(sg/fmap (fn [v] (tm/parse-instant v))))
|
;; (sg/fmap (fn [v] (tm/parse-inst v))))
|
||||||
|
|
||||||
:decode/string tm/parse-instant
|
;; :decode/string tm/parse-inst
|
||||||
:encode/string tm/format-instant
|
;; :encode/string tm/format-inst
|
||||||
:decode/json tm/parse-instant
|
;; :decode/json tm/parse-inst
|
||||||
:encode/json tm/format-instant
|
;; :encode/json tm/format-inst
|
||||||
::oapi/type "string"
|
;; ::oapi/type "string"
|
||||||
::oapi/format "iso"}})
|
;; ::oapi/format "iso"}})
|
||||||
|
|
||||||
(register!
|
;; (register!
|
||||||
{:type ::timestamp
|
;; {:type ::timestamp
|
||||||
:pred inst?
|
;; :pred tm/instant?
|
||||||
:type-properties
|
;; :type-properties
|
||||||
{:title "inst"
|
;; {:title "inst"
|
||||||
:description "Satisfies Inst protocol"
|
;; :description "Satisfies Inst protocol, the same as ::inst but encodes to epoch"
|
||||||
:error/message "should be an instant"
|
;; :error/message "should be an instant"
|
||||||
:gen/gen (->> (sg/small-int)
|
;; :gen/gen (->> (sg/small-int)
|
||||||
(sg/fmap (fn [v] (tm/parse-instant v))))
|
;; (sg/fmap (fn [v] (tm/parse-inst v))))
|
||||||
:decode/string tm/parse-instant
|
;; :decode/string tm/parse-inst
|
||||||
:encode/string inst-ms
|
;; :encode/string inst-ms
|
||||||
:decode/json tm/parse-instant
|
;; :decode/json tm/parse-inst
|
||||||
:encode/json inst-ms
|
;; :encode/json inst-ms
|
||||||
::oapi/type "string"
|
;; ::oapi/type "string"
|
||||||
::oapi/format "number"}})
|
;; ::oapi/format "number"}})
|
||||||
|
|
||||||
(register!
|
(register!
|
||||||
{:type ::fn
|
{:type ::fn
|
||||||
|
|||||||
@@ -4,28 +4,152 @@
|
|||||||
;;
|
;;
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
#_{:clj-kondo/ignore [:unused-namespace]}
|
||||||
(ns app.common.time
|
(ns app.common.time
|
||||||
"Minimal cross-platoform date time api for specific use cases on types
|
"Minimal cross-platoform date time api for specific use cases on types
|
||||||
definition and other common code."
|
definition and other common code."
|
||||||
#?(:cljs
|
(:refer-clojure :exclude [inst?])
|
||||||
(:require
|
(:require
|
||||||
["luxon" :as lxn])
|
#?@(:cljs [["date-fns/format$default" :as dfn-format]
|
||||||
:clj
|
["date-fns/formatISO$default" :as dfn-format-iso]
|
||||||
|
["date-fns/setDefaultOptions$default" :as dfn-set-default-options]
|
||||||
|
["date-fns/differenceInMilliseconds$default" :as dfn-diff]
|
||||||
|
["date-fns/formatDistanceToNowStrict$default" :as dfn-distance-to-now]
|
||||||
|
["date-fns/add$default" :as dfn-add]
|
||||||
|
["date-fns/sub$default" :as dfn-sub]
|
||||||
|
["date-fns/parseISO$default" :as dfn-parse-iso]
|
||||||
|
["date-fns/locale/ar-SA$default" :as dfn-ar]
|
||||||
|
["date-fns/locale/ca$default" :as dfn-ca]
|
||||||
|
["date-fns/locale/cs$default" :as dfn-cs]
|
||||||
|
["date-fns/locale/de$default" :as dfn-de]
|
||||||
|
["date-fns/locale/el$default" :as dfn-el]
|
||||||
|
["date-fns/locale/en-US$default" :as df-en-us]
|
||||||
|
["date-fns/locale/es$default" :as dfn-es]
|
||||||
|
["date-fns/locale/eu$default" :as dfn-eu]
|
||||||
|
["date-fns/locale/fa-IR$default" :as dfn-fa-ir]
|
||||||
|
["date-fns/locale/fr$default" :as dfn-fr]
|
||||||
|
["date-fns/locale/gl$default" :as dfn-gl]
|
||||||
|
["date-fns/locale/he$default" :as dfn-he]
|
||||||
|
["date-fns/locale/hr$default" :as dfn-hr]
|
||||||
|
["date-fns/locale/id$default" :as dfn-id]
|
||||||
|
["date-fns/locale/it$default" :as dfn-it]
|
||||||
|
["date-fns/locale/ja$default" :as dfn-ja]
|
||||||
|
["date-fns/locale/ko$default" :as dfn-ko]
|
||||||
|
["date-fns/locale/lv$default" :as dfn-lv]
|
||||||
|
["date-fns/locale/nb$default" :as dfn-nb]
|
||||||
|
["date-fns/locale/nl$default" :as dfn-nl]
|
||||||
|
["date-fns/locale/pl$default" :as dfn-pl]
|
||||||
|
["date-fns/locale/pt$default" :as dfn-pt]
|
||||||
|
["date-fns/locale/pt-BR$default" :as dfn-pt-br]
|
||||||
|
["date-fns/locale/ro$default" :as dfn-ro]
|
||||||
|
["date-fns/locale/ru$default" :as dfn-ru]
|
||||||
|
["date-fns/locale/tr$default" :as dfn-tr]
|
||||||
|
["date-fns/locale/uk$default" :as dfn-uk]
|
||||||
|
["date-fns/locale/zh-CN$default" :as dfn-zh-cn]])
|
||||||
|
[app.common.schema :as sm]
|
||||||
|
[app.common.schema.generators :as sg]
|
||||||
|
[app.common.schema.openapi :as-alias oapi]
|
||||||
|
[cuerdas.core :as str])
|
||||||
|
#?(:clj
|
||||||
(:import
|
(:import
|
||||||
java.time.format.DateTimeFormatter
|
java.time.Duration
|
||||||
java.time.Instant
|
java.time.Instant
|
||||||
java.time.Duration)))
|
java.time.OffsetDateTime
|
||||||
|
java.time.ZoneId
|
||||||
#?(:cljs
|
java.time.ZonedDateTime
|
||||||
(def DateTime lxn/DateTime))
|
java.time.format.DateTimeFormatter
|
||||||
|
java.time.temporal.ChronoUnit
|
||||||
#?(:cljs
|
java.time.temporal.Temporal
|
||||||
(def Duration lxn/Duration))
|
java.time.temporal.TemporalAmount
|
||||||
|
java.time.temporal.TemporalUnit)))
|
||||||
|
|
||||||
(defn now
|
(defn now
|
||||||
[]
|
[]
|
||||||
#?(:clj (Instant/now)
|
#?(:clj (Instant/now)
|
||||||
:cljs (.local ^js DateTime)))
|
:cljs (new js/Date)))
|
||||||
|
|
||||||
|
;; --- DURATION
|
||||||
|
|
||||||
|
(defn- resolve-temporal-unit
|
||||||
|
[o]
|
||||||
|
(case o
|
||||||
|
(:nanos :nano)
|
||||||
|
#?(:clj ChronoUnit/NANOS
|
||||||
|
:cljs (throw (js/Error. "not supported nanos")))
|
||||||
|
|
||||||
|
(:micros :microsecond :micro)
|
||||||
|
#?(:clj ChronoUnit/MICROS
|
||||||
|
:cljs (throw (js/Error. "not supported nanos")))
|
||||||
|
|
||||||
|
(:millis :millisecond :milli)
|
||||||
|
#?(:clj ChronoUnit/MILLIS
|
||||||
|
:cljs "millisecond")
|
||||||
|
|
||||||
|
(:seconds :second)
|
||||||
|
#?(:clj ChronoUnit/SECONDS
|
||||||
|
:cljs "second")
|
||||||
|
|
||||||
|
(:minutes :minute)
|
||||||
|
#?(:clj ChronoUnit/MINUTES
|
||||||
|
:cljs "minute")
|
||||||
|
|
||||||
|
(:hours :hour)
|
||||||
|
#?(:clj ChronoUnit/HOURS
|
||||||
|
:cljs "hour")
|
||||||
|
|
||||||
|
(:days :day)
|
||||||
|
#?(:clj ChronoUnit/DAYS
|
||||||
|
:cljs "day")))
|
||||||
|
|
||||||
|
(defn temporal-unit
|
||||||
|
[o]
|
||||||
|
#?(:clj (if (instance? TemporalUnit o) o (resolve-temporal-unit o))
|
||||||
|
:cljs (resolve-temporal-unit o)))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defn- obj->duration
|
||||||
|
[params]
|
||||||
|
(reduce-kv (fn [o k v]
|
||||||
|
(.plus ^Duration o ^long v ^TemporalUnit (temporal-unit k)))
|
||||||
|
(Duration/ofMillis 0)
|
||||||
|
params)))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defn duration?
|
||||||
|
[o]
|
||||||
|
(instance? Duration o)))
|
||||||
|
|
||||||
|
(defn duration
|
||||||
|
[ms-or-obj]
|
||||||
|
#?(:clj
|
||||||
|
(cond
|
||||||
|
(string? ms-or-obj)
|
||||||
|
(Duration/parse (str "PT" ms-or-obj))
|
||||||
|
|
||||||
|
(duration? ms-or-obj)
|
||||||
|
ms-or-obj
|
||||||
|
|
||||||
|
(integer? ms-or-obj)
|
||||||
|
|
||||||
|
(Duration/ofMillis ms-or-obj)
|
||||||
|
|
||||||
|
:else
|
||||||
|
(obj->duration ms-or-obj))
|
||||||
|
|
||||||
|
:cljs
|
||||||
|
(clj->js ms-or-obj)))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defn parse-duration
|
||||||
|
[s]
|
||||||
|
(duration s)))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defn format-duration
|
||||||
|
[o]
|
||||||
|
(str/lower (subs (str o) 2))))
|
||||||
|
|
||||||
|
;; --- INSTNANT & DATETIME
|
||||||
|
|
||||||
(defn is-after?
|
(defn is-after?
|
||||||
"Analgous to: da > db"
|
"Analgous to: da > db"
|
||||||
@@ -44,65 +168,261 @@
|
|||||||
(zero? result) false
|
(zero? result) false
|
||||||
:else false)))
|
:else false)))
|
||||||
|
|
||||||
(defn instant?
|
(defn inst?
|
||||||
[o]
|
[o]
|
||||||
#?(:clj (instance? Instant o)
|
#?(:clj (instance? Instant o)
|
||||||
:cljs (instance? DateTime o)))
|
:cljs (instance? js/Date o)))
|
||||||
|
|
||||||
(defn parse-instant
|
(defn seconds
|
||||||
|
[d]
|
||||||
|
(-> d inst-ms (/ 1000) int))
|
||||||
|
|
||||||
|
(defn format-inst
|
||||||
|
([v] (format-inst v :iso))
|
||||||
|
([v fmt]
|
||||||
|
(case fmt
|
||||||
|
(:iso :iso8601)
|
||||||
|
#?(:clj (.format DateTimeFormatter/ISO_INSTANT ^Instant v)
|
||||||
|
:cljs (dfn-format-iso v))
|
||||||
|
|
||||||
|
:iso-date
|
||||||
|
#?(:clj (.format DateTimeFormatter/ISO_LOCAL_DATE
|
||||||
|
^ZonedDateTime (ZonedDateTime/ofInstant v (ZoneId/of "UTC")))
|
||||||
|
:cljs (dfn-format-iso v #js {:representation "date"}))
|
||||||
|
|
||||||
|
(:rfc1123 :http)
|
||||||
|
#?(:clj (.format DateTimeFormatter/RFC_1123_DATE_TIME
|
||||||
|
^ZonedDateTime (ZonedDateTime/ofInstant v (ZoneId/of "UTC")))
|
||||||
|
:cljs (dfn-format v "EEE, dd LLL yyyy HH:mm:ss 'GMT'"))
|
||||||
|
|
||||||
|
#?@(:cljs [:time-24-simple
|
||||||
|
(dfn-format v "HH:mm")
|
||||||
|
|
||||||
|
;; DEPRECATED
|
||||||
|
:date-full
|
||||||
|
(dfn-format v "PPP")
|
||||||
|
|
||||||
|
:localized-date
|
||||||
|
(dfn-format v "PPP")
|
||||||
|
|
||||||
|
:localized-time
|
||||||
|
(dfn-format v "p")
|
||||||
|
|
||||||
|
:localized-date-time
|
||||||
|
(dfn-format v "PPPp")
|
||||||
|
|
||||||
|
(if (string? fmt)
|
||||||
|
(dfn-format v fmt)
|
||||||
|
(throw (js/Error. "unpexted format")))]))))
|
||||||
|
|
||||||
|
#?(:cljs
|
||||||
|
(def locales
|
||||||
|
#js {:ar dfn-ar
|
||||||
|
:ca dfn-ca
|
||||||
|
:de dfn-de
|
||||||
|
:el dfn-el
|
||||||
|
:en df-en-us
|
||||||
|
:en_us df-en-us
|
||||||
|
:es dfn-es
|
||||||
|
:es_es dfn-es
|
||||||
|
:fa dfn-fa-ir
|
||||||
|
:fa_ir dfn-fa-ir
|
||||||
|
:fr dfn-fr
|
||||||
|
:he dfn-he
|
||||||
|
:pt dfn-pt
|
||||||
|
:pt_pt dfn-pt
|
||||||
|
:pt_br dfn-pt-br
|
||||||
|
:ro dfn-ro
|
||||||
|
:ru dfn-ru
|
||||||
|
:tr dfn-tr
|
||||||
|
:zh-cn dfn-zh-cn
|
||||||
|
:nl dfn-nl
|
||||||
|
:eu dfn-eu
|
||||||
|
:gl dfn-gl
|
||||||
|
:hr dfn-hr
|
||||||
|
:it dfn-it
|
||||||
|
:nb dfn-nb
|
||||||
|
:nb_no dfn-nb
|
||||||
|
:pl dfn-pl
|
||||||
|
:id dfn-id
|
||||||
|
:uk dfn-uk
|
||||||
|
:cs dfn-cs
|
||||||
|
:lv dfn-lv
|
||||||
|
:ko dfn-ko
|
||||||
|
:ja dfn-ja
|
||||||
|
:ja_jp dfn-ja}))
|
||||||
|
|
||||||
|
#?(:cljs
|
||||||
|
(defn timeago
|
||||||
|
[v]
|
||||||
|
(when v
|
||||||
|
(dfn-distance-to-now v #js {:includeSeconds true
|
||||||
|
:addSuffix true}))))
|
||||||
|
|
||||||
|
(defn inst
|
||||||
[s]
|
[s]
|
||||||
(cond
|
(cond
|
||||||
(instant? s)
|
(inst? s)
|
||||||
s
|
s
|
||||||
|
|
||||||
(int? s)
|
(int? s)
|
||||||
#?(:clj (Instant/ofEpochMilli s)
|
#?(:clj (Instant/ofEpochMilli s)
|
||||||
:cljs (.fromMillis ^js DateTime s #js {:zone "local" :setZone false}))
|
:cljs (new js/Date s))
|
||||||
|
|
||||||
(string? s)
|
(string? s)
|
||||||
#?(:clj (Instant/parse s)
|
#?(:clj (Instant/from (.parse DateTimeFormatter/ISO_DATE_TIME ^String s))
|
||||||
:cljs (.fromISO ^js DateTime s))))
|
:cljs (dfn-parse-iso s))
|
||||||
|
|
||||||
(defn format-instant
|
:else
|
||||||
|
(throw (ex-info "invalid parameters" {}))))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defn truncate
|
||||||
|
[o unit]
|
||||||
|
(let [unit (temporal-unit unit)]
|
||||||
|
(cond
|
||||||
|
(inst? o)
|
||||||
|
(.truncatedTo ^Instant o ^TemporalUnit unit)
|
||||||
|
|
||||||
|
(instance? Duration o)
|
||||||
|
(.truncatedTo ^Duration o ^TemporalUnit unit)
|
||||||
|
|
||||||
|
:else
|
||||||
|
(throw (IllegalArgumentException. "only instant and duration allowed"))))))
|
||||||
|
|
||||||
|
(defn plus
|
||||||
|
[d ta]
|
||||||
|
(let [ta (duration ta)]
|
||||||
|
(cond
|
||||||
|
#?@(:clj [(duration? d) (.plus ^Duration d ^TemporalAmount ta)])
|
||||||
|
|
||||||
|
#?(:cljs (inst? d)
|
||||||
|
:clj (instance? Temporal d))
|
||||||
|
#?(:cljs (dfn-add d ta)
|
||||||
|
:clj (.plus ^Temporal d ^Duration ta))
|
||||||
|
|
||||||
|
:else
|
||||||
|
(throw #?(:clj (UnsupportedOperationException. "unsupported type")
|
||||||
|
:cljs (js/Error. "unsupported type"))))))
|
||||||
|
|
||||||
|
(defn minus
|
||||||
|
[d ta]
|
||||||
|
(let [^TemporalAmount ta (duration ta)]
|
||||||
|
(cond
|
||||||
|
#?@(:clj [(duration? d) (.minus ^Duration d ^TemporalAmount ta)])
|
||||||
|
|
||||||
|
#?(:cljs (inst? d) :clj (instance? Temporal d))
|
||||||
|
#?(:cljs (dfn-sub d ta)
|
||||||
|
:clj (.minus ^Temporal d ^Duration ta))
|
||||||
|
|
||||||
|
:else
|
||||||
|
(throw #?(:clj (UnsupportedOperationException. "unsupported type")
|
||||||
|
:cljs (js/Error. "unsupported type"))))))
|
||||||
|
|
||||||
|
(defn in-future
|
||||||
[v]
|
[v]
|
||||||
#?(:clj (.format DateTimeFormatter/ISO_INSTANT ^Instant v)
|
(plus (now) v))
|
||||||
:cljs (.toISO ^js v)))
|
|
||||||
|
|
||||||
;; To check for valid date time we can just use the core inst? function
|
(defn in-past
|
||||||
|
[v]
|
||||||
|
(minus (now) v))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defn diff
|
||||||
|
[t1 t2]
|
||||||
|
(Duration/between t1 t2)))
|
||||||
|
|
||||||
#?(:cljs
|
#?(:cljs
|
||||||
(extend-protocol IComparable
|
(defn diff-ms
|
||||||
DateTime
|
[t1 t2]
|
||||||
(-compare [it other]
|
(dfn-diff t2 t1)))
|
||||||
(if ^boolean (.equals it other)
|
|
||||||
0
|
|
||||||
(if (< (inst-ms it) (inst-ms other)) -1 1)))
|
|
||||||
|
|
||||||
Duration
|
|
||||||
(-compare [it other]
|
|
||||||
(if ^boolean (.equals it other)
|
|
||||||
0
|
|
||||||
(if (< (inst-ms it) (inst-ms other)) -1 1)))))
|
|
||||||
|
|
||||||
#?(:cljs
|
#?(:cljs
|
||||||
(extend-type DateTime
|
(defn set-default-locale!
|
||||||
cljs.core/IEquiv
|
[locale]
|
||||||
(-equiv [o other]
|
(when-let [locale (unchecked-get locales locale)]
|
||||||
(and (instance? DateTime other)
|
(dfn-set-default-options #js {:locale locale}))))
|
||||||
(== (.valueOf o) (.valueOf other))))))
|
|
||||||
|
;; --- HELPERS
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defn tpoint
|
||||||
|
"Create a measurement checkpoint for time measurement of potentially
|
||||||
|
asynchronous flow."
|
||||||
|
[]
|
||||||
|
(let [p1 (System/nanoTime)]
|
||||||
|
#(duration {:nanos (- (System/nanoTime) p1)}))))
|
||||||
|
|
||||||
#?(:cljs
|
#?(:cljs
|
||||||
(extend-protocol cljs.core/Inst
|
(defn tpoint-ms
|
||||||
DateTime
|
"Create a measurement checkpoint for time measurement of potentially
|
||||||
(inst-ms* [inst] (.toMillis ^js inst))
|
asynchronous flow."
|
||||||
|
[]
|
||||||
|
(let [p1 (.now js/performance)]
|
||||||
|
#(- (.now js/performance) p1))))
|
||||||
|
|
||||||
Duration
|
;; --- EXTENSIONS
|
||||||
(inst-ms* [inst] (.toMillis ^js inst)))
|
|
||||||
|
|
||||||
:clj
|
#?(:clj
|
||||||
(extend-protocol clojure.core/Inst
|
(extend-protocol clojure.core/Inst
|
||||||
Duration
|
Duration
|
||||||
(inst-ms* [v] (.toMillis ^Duration v))
|
(inst-ms* [v] (.toMillis ^Duration v))
|
||||||
|
|
||||||
|
OffsetDateTime
|
||||||
|
(inst-ms* [v] (.toEpochMilli (.toInstant ^OffsetDateTime v)))
|
||||||
|
|
||||||
Instant
|
Instant
|
||||||
(inst-ms* [v] (.toEpochMilli ^Instant v))))
|
(inst-ms* [v] (.toEpochMilli ^Instant v))))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defmethod print-method Duration
|
||||||
|
[o w]
|
||||||
|
(print-dup o w)))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defmethod print-dup Duration
|
||||||
|
[mv ^java.io.Writer writer]
|
||||||
|
(.write writer (str "#penpot/duration \"" (str/lower (subs (str mv) 2)) "\""))))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defmethod print-method Instant
|
||||||
|
[o w]
|
||||||
|
(print-dup o w)))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defmethod print-dup Instant
|
||||||
|
[mv ^java.io.Writer writer]
|
||||||
|
(.write writer (str "#penpot/inst \"" (format-inst mv) "\""))))
|
||||||
|
|
||||||
|
(def schema:inst
|
||||||
|
(sm/register!
|
||||||
|
{:type ::inst
|
||||||
|
:pred inst?
|
||||||
|
:type-properties
|
||||||
|
{:error/message "should be an instant"
|
||||||
|
:title "instant"
|
||||||
|
:decode/string inst
|
||||||
|
:encode/string format-inst
|
||||||
|
:decode/json inst
|
||||||
|
:encode/json format-inst
|
||||||
|
:gen/gen (->> (sg/small-int :min 0)
|
||||||
|
(sg/fmap (fn [i] (in-past i))))
|
||||||
|
::oapi/type "string"
|
||||||
|
::oapi/format "iso"}}))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(def schema:duration
|
||||||
|
(sm/register!
|
||||||
|
{:type ::duration
|
||||||
|
:pred duration?
|
||||||
|
:type-properties
|
||||||
|
{:error/message "should be a duration"
|
||||||
|
:gen/gen (->> (sg/small-int :min 0)
|
||||||
|
(sg/fmap duration))
|
||||||
|
:title "duration"
|
||||||
|
:decode/string parse-duration
|
||||||
|
:encode/string format-duration
|
||||||
|
:decode/json parse-duration
|
||||||
|
:encode/json format-duration
|
||||||
|
::oapi/type "string"
|
||||||
|
::oapi/format "duration"}})))
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
(ns app.common.transit
|
(ns app.common.transit
|
||||||
(:require
|
(:require
|
||||||
#?(:clj [datoteka.fs :as fs])
|
#?(:clj [datoteka.fs :as fs])
|
||||||
#?(:cljs ["luxon" :as lxn])
|
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.uri :as uri]
|
[app.common.uri :as uri]
|
||||||
[cognitect.transit :as t]
|
[cognitect.transit :as t]
|
||||||
@@ -130,20 +129,18 @@
|
|||||||
:wfn vec
|
:wfn vec
|
||||||
:rfn #(into lks/empty-linked-set %)}
|
:rfn #(into lks/empty-linked-set %)}
|
||||||
|
|
||||||
{:id "duration"
|
#?(:clj
|
||||||
:class #?(:clj Duration :cljs lxn/Duration)
|
{:id "duration"
|
||||||
:rfn (fn [v]
|
:class Duration
|
||||||
#?(:clj (Duration/ofMillis v)
|
:rfn (fn [v] (Duration/ofMillis v))
|
||||||
:cljs (.fromMillis ^js lxn/Duration v)))
|
:wfn inst-ms})
|
||||||
:wfn inst-ms}
|
|
||||||
|
|
||||||
{:id "m"
|
{:id "m"
|
||||||
:class #?(:clj Instant :cljs lxn/DateTime)
|
:class #?(:clj Instant :cljs js/Date)
|
||||||
:rfn (fn [v]
|
:rfn (fn [v]
|
||||||
#?(:clj (-> (Long/parseLong v)
|
#?(:clj (-> (Long/parseLong v)
|
||||||
(Instant/ofEpochMilli))
|
(Instant/ofEpochMilli))
|
||||||
:cljs (let [ms (js/parseInt v 10)]
|
:cljs (new js/Date (js/parseInt v 10))))
|
||||||
(.fromMillis ^js lxn/DateTime ms))))
|
|
||||||
:wfn (comp str inst-ms)}
|
:wfn (comp str inst-ms)}
|
||||||
|
|
||||||
{:id "penpot/pointer"
|
{:id "penpot/pointer"
|
||||||
@@ -204,12 +201,30 @@
|
|||||||
(with-open [input (ByteArrayInputStream. ^bytes data)]
|
(with-open [input (ByteArrayInputStream. ^bytes data)]
|
||||||
(t/read (reader input opts))))))
|
(t/read (reader input opts))))))
|
||||||
|
|
||||||
|
#?(:cljs
|
||||||
|
(defn- is-date-like?
|
||||||
|
[obj]
|
||||||
|
(and ^boolean (some? obj)
|
||||||
|
^boolean (fn? (.-getTime obj))
|
||||||
|
^boolean (some? (.getTime obj)))))
|
||||||
|
|
||||||
|
#_:clj-kondo/ignore
|
||||||
|
(def ^:private date-write-handler
|
||||||
|
(t/write-handler (constantly "m")
|
||||||
|
(comp str inst-ms)))
|
||||||
|
|
||||||
(defn encode-str
|
(defn encode-str
|
||||||
([data] (encode-str data nil))
|
([data] (encode-str data nil))
|
||||||
([data opts]
|
([data opts]
|
||||||
#?(:cljs
|
#?(:cljs
|
||||||
(let [type (:type opts :json)
|
(let [type (:type opts :json)
|
||||||
params {:handlers @write-handler-map}
|
params {:handlers @write-handler-map
|
||||||
|
;; NOTE: this is necessary because the plugin
|
||||||
|
;; secure context alters the js/Date constructor
|
||||||
|
:handlerForForeign (fn [x _]
|
||||||
|
(if (is-date-like? x)
|
||||||
|
date-write-handler
|
||||||
|
nil))}
|
||||||
params (if (:with-meta opts)
|
params (if (:with-meta opts)
|
||||||
(assoc params :transform t/write-meta)
|
(assoc params :transform t/write-meta)
|
||||||
params)
|
params)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.schema.generators :as sg]
|
[app.common.schema.generators :as sg]
|
||||||
[app.common.schema.openapi :as-alias oapi]
|
[app.common.schema.openapi :as-alias oapi]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.plugins :as ctpg]
|
[app.common.types.plugins :as ctpg]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
@@ -136,7 +137,7 @@
|
|||||||
[:name ::sm/text]
|
[:name ::sm/text]
|
||||||
[:path {:optional true} :string]
|
[:path {:optional true} :string]
|
||||||
[:opacity {:optional true} [::sm/number {:min 0 :max 1}]]
|
[:opacity {:optional true} [::sm/number {:min 0 :max 1}]]
|
||||||
[:modified-at {:optional true} ::sm/inst]
|
[:modified-at {:optional true} ::ct/inst]
|
||||||
[:plugin-data {:optional true} ::ctpg/plugin-data]])
|
[:plugin-data {:optional true} ::ctpg/plugin-data]])
|
||||||
|
|
||||||
(def schema:library-color
|
(def schema:library-color
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as-alias ct]
|
||||||
[app.common.types.page :as ctp]
|
[app.common.types.page :as ctp]
|
||||||
[app.common.types.plugins :as ctpg]
|
[app.common.types.plugins :as ctpg]
|
||||||
[app.common.types.variant :as ctv]
|
[app.common.types.variant :as ctv]
|
||||||
@@ -25,7 +26,7 @@
|
|||||||
[:id ::sm/uuid]
|
[:id ::sm/uuid]
|
||||||
[:name :string]
|
[:name :string]
|
||||||
[:path {:optional true} [:maybe :string]]
|
[:path {:optional true} [:maybe :string]]
|
||||||
[:modified-at {:optional true} ::sm/inst]
|
[:modified-at {:optional true} ::ct/inst]
|
||||||
[:objects {:gen/max 10 :optional true} ctp/schema:objects]
|
[:objects {:gen/max 10 :optional true} ctp/schema:objects]
|
||||||
[:main-instance-id ::sm/uuid]
|
[:main-instance-id ::sm/uuid]
|
||||||
[:main-instance-page ::sm/uuid]
|
[:main-instance-page ::sm/uuid]
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as-alias ct]
|
||||||
[app.common.types.component :as ctk]
|
[app.common.types.component :as ctk]
|
||||||
[app.common.types.components-list :as ctkl]
|
[app.common.types.components-list :as ctkl]
|
||||||
[app.common.types.pages-list :as ctpl]
|
[app.common.types.pages-list :as ctpl]
|
||||||
@@ -39,7 +40,7 @@
|
|||||||
[::sm/one-of valid-container-types]]
|
[::sm/one-of valid-container-types]]
|
||||||
[:name :string]
|
[:name :string]
|
||||||
[:path {:optional true} [:maybe :string]]
|
[:path {:optional true} [:maybe :string]]
|
||||||
[:modified-at {:optional true} ::sm/inst]
|
[:modified-at {:optional true} ::ct/inst]
|
||||||
[:objects {:optional true}
|
[:objects {:optional true}
|
||||||
[:map-of {:gen/max 10} ::sm/uuid :map]]
|
[:map-of {:gen/max 10} ::sm/uuid :map]]
|
||||||
[:plugin-data {:optional true} schema:plugin-data]]))
|
[:plugin-data {:optional true} schema:plugin-data]]))
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
[app.common.geom.shapes.tree-seq :as gsts]
|
[app.common.geom.shapes.tree-seq :as gsts]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.time :as dt]
|
[app.common.time :as ct]
|
||||||
[app.common.types.color :as ctc]
|
[app.common.types.color :as ctc]
|
||||||
[app.common.types.component :as ctk]
|
[app.common.types.component :as ctk]
|
||||||
[app.common.types.components-list :as ctkl]
|
[app.common.types.components-list :as ctkl]
|
||||||
@@ -34,7 +34,6 @@
|
|||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; CONSTANTS
|
;; CONSTANTS
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -49,8 +48,8 @@
|
|||||||
"A schema that represents the file media object"
|
"A schema that represents the file media object"
|
||||||
[:map {:title "FileMedia"}
|
[:map {:title "FileMedia"}
|
||||||
[:id ::sm/uuid]
|
[:id ::sm/uuid]
|
||||||
[:created-at {:optional true} ::sm/inst]
|
[:created-at {:optional true} ::ct/inst]
|
||||||
[:deleted-at {:optional true} ::sm/inst]
|
[:deleted-at {:optional true} ::ct/inst]
|
||||||
[:name :string]
|
[:name :string]
|
||||||
[:width ::sm/safe-int]
|
[:width ::sm/safe-int]
|
||||||
[:height ::sm/safe-int]
|
[:height ::sm/safe-int]
|
||||||
@@ -96,9 +95,9 @@
|
|||||||
[:name :string]
|
[:name :string]
|
||||||
[:revn :int]
|
[:revn :int]
|
||||||
[:vern {:optional true} :int]
|
[:vern {:optional true} :int]
|
||||||
[:created-at ::sm/inst]
|
[:created-at ::ct/inst]
|
||||||
[:modified-at ::sm/inst]
|
[:modified-at ::ct/inst]
|
||||||
[:deleted-at {:optional true} ::sm/inst]
|
[:deleted-at {:optional true} ::ct/inst]
|
||||||
[:project-id {:optional true} ::sm/uuid]
|
[:project-id {:optional true} ::sm/uuid]
|
||||||
[:team-id {:optional true} ::sm/uuid]
|
[:team-id {:optional true} ::sm/uuid]
|
||||||
[:is-shared {:optional true} ::sm/boolean]
|
[:is-shared {:optional true} ::sm/boolean]
|
||||||
@@ -164,7 +163,7 @@
|
|||||||
:or {create-page true with-data true}}]
|
:or {create-page true with-data true}}]
|
||||||
|
|
||||||
(let [id (or id (uuid/next))
|
(let [id (or id (uuid/next))
|
||||||
created-at (or created-at (dt/now))
|
created-at (or created-at (ct/now))
|
||||||
modified-at (or modified-at created-at)
|
modified-at (or modified-at created-at)
|
||||||
features (d/nilv features #{})
|
features (d/nilv features #{})
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
[app.common.files.helpers :as cfh]
|
[app.common.files.helpers :as cfh]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.schema.generators :as sg]
|
[app.common.schema.generators :as sg]
|
||||||
[app.common.time :as dt]
|
[app.common.time :as ct]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.common.types.token :as cto]
|
[app.common.types.token :as cto]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
[:type [::sm/one-of cto/token-types]]
|
[:type [::sm/one-of cto/token-types]]
|
||||||
[:value ::sm/any]
|
[:value ::sm/any]
|
||||||
[:description {:optional true} :string]
|
[:description {:optional true} :string]
|
||||||
[:modified-at {:optional true} ::sm/inst]])
|
[:modified-at {:optional true} ::ct/inst]])
|
||||||
|
|
||||||
(declare make-token)
|
(declare make-token)
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
[& {:as attrs}]
|
[& {:as attrs}]
|
||||||
(-> attrs
|
(-> attrs
|
||||||
(update :id #(or % (uuid/next)))
|
(update :id #(or % (uuid/next)))
|
||||||
(update :modified-at #(or % (dt/now)))
|
(update :modified-at #(or % (ct/now)))
|
||||||
(update :description d/nilv "")
|
(update :description d/nilv "")
|
||||||
(check-token-attrs)
|
(check-token-attrs)
|
||||||
(map->Token)))
|
(map->Token)))
|
||||||
@@ -208,14 +208,14 @@
|
|||||||
(TokenSet. id
|
(TokenSet. id
|
||||||
new-name
|
new-name
|
||||||
description
|
description
|
||||||
(dt/now)
|
(ct/now)
|
||||||
tokens))
|
tokens))
|
||||||
|
|
||||||
(set-description [_ new-description]
|
(set-description [_ new-description]
|
||||||
(TokenSet. id
|
(TokenSet. id
|
||||||
name
|
name
|
||||||
(d/nilv new-description "")
|
(d/nilv new-description "")
|
||||||
(dt/now)
|
(ct/now)
|
||||||
tokens))
|
tokens))
|
||||||
|
|
||||||
ITokenSet
|
ITokenSet
|
||||||
@@ -231,17 +231,17 @@
|
|||||||
(TokenSet. id
|
(TokenSet. id
|
||||||
name
|
name
|
||||||
description
|
description
|
||||||
(dt/now)
|
(ct/now)
|
||||||
(assoc tokens (:name token) token))))
|
(assoc tokens (:name token) token))))
|
||||||
|
|
||||||
(update-token [this id f]
|
(update-token [this id f]
|
||||||
(if-let [token (token-by-id this id)]
|
(if-let [token (token-by-id this id)]
|
||||||
(let [token' (-> (make-token (f token))
|
(let [token' (-> (make-token (f token))
|
||||||
(assoc :modified-at (dt/now)))]
|
(assoc :modified-at (ct/now)))]
|
||||||
(TokenSet. id
|
(TokenSet. id
|
||||||
name
|
name
|
||||||
description
|
description
|
||||||
(dt/now)
|
(ct/now)
|
||||||
(if (= (:name token) (:name token'))
|
(if (= (:name token) (:name token'))
|
||||||
(assoc tokens (:name token') token')
|
(assoc tokens (:name token') token')
|
||||||
(-> tokens
|
(-> tokens
|
||||||
@@ -254,7 +254,7 @@
|
|||||||
(TokenSet. id
|
(TokenSet. id
|
||||||
name
|
name
|
||||||
description
|
description
|
||||||
(dt/now)
|
(ct/now)
|
||||||
(dissoc tokens (:name token)))))
|
(dissoc tokens (:name token)))))
|
||||||
|
|
||||||
(get-token [this id]
|
(get-token [this id]
|
||||||
@@ -279,7 +279,7 @@
|
|||||||
[:id ::sm/uuid]
|
[:id ::sm/uuid]
|
||||||
[:name :string]
|
[:name :string]
|
||||||
[:description {:optional true} :string]
|
[:description {:optional true} :string]
|
||||||
[:modified-at {:optional true} ::sm/inst]
|
[:modified-at {:optional true} ::ct/inst]
|
||||||
[:tokens {:optional true
|
[:tokens {:optional true
|
||||||
:gen/gen (->> (sg/map-of (sg/generator ::sm/text)
|
:gen/gen (->> (sg/map-of (sg/generator ::sm/text)
|
||||||
(sg/generator schema:token))
|
(sg/generator schema:token))
|
||||||
@@ -316,7 +316,7 @@
|
|||||||
[& {:as attrs}]
|
[& {:as attrs}]
|
||||||
(let [attrs (-> attrs
|
(let [attrs (-> attrs
|
||||||
(update :id #(or % (uuid/next)))
|
(update :id #(or % (uuid/next)))
|
||||||
(update :modified-at #(or % (dt/now)))
|
(update :modified-at #(or % (ct/now)))
|
||||||
(update :tokens #(into (d/ordered-map) %))
|
(update :tokens #(into (d/ordered-map) %))
|
||||||
(update :description d/nilv "")
|
(update :description d/nilv "")
|
||||||
(check-token-set-attrs))]
|
(check-token-set-attrs))]
|
||||||
@@ -552,7 +552,7 @@
|
|||||||
description
|
description
|
||||||
is-source
|
is-source
|
||||||
external-id
|
external-id
|
||||||
(dt/now)
|
(ct/now)
|
||||||
set-names))
|
set-names))
|
||||||
|
|
||||||
(enable-set [this set-name]
|
(enable-set [this set-name]
|
||||||
@@ -580,7 +580,7 @@
|
|||||||
description
|
description
|
||||||
is-source
|
is-source
|
||||||
external-id
|
external-id
|
||||||
(dt/now)
|
(ct/now)
|
||||||
(conj (disj sets prev-set-name) set-name))
|
(conj (disj sets prev-set-name) set-name))
|
||||||
this))
|
this))
|
||||||
|
|
||||||
@@ -606,7 +606,7 @@
|
|||||||
[:description {:optional true} :string]
|
[:description {:optional true} :string]
|
||||||
[:is-source {:optional true} :boolean]
|
[:is-source {:optional true} :boolean]
|
||||||
[:external-id {:optional true} :string]
|
[:external-id {:optional true} :string]
|
||||||
[:modified-at {:optional true} ::sm/inst]
|
[:modified-at {:optional true} ::ct/inst]
|
||||||
[:sets {:optional true} [:set {:gen/max 5} :string]]])
|
[:sets {:optional true} [:set {:gen/max 5} :string]]])
|
||||||
|
|
||||||
(def schema:token-theme
|
(def schema:token-theme
|
||||||
@@ -640,7 +640,7 @@
|
|||||||
(update :description d/nilv "")
|
(update :description d/nilv "")
|
||||||
(update :is-source d/nilv false)
|
(update :is-source d/nilv false)
|
||||||
(update :external-id #(or % (str new-id)))
|
(update :external-id #(or % (str new-id)))
|
||||||
(update :modified-at #(or % (dt/now)))
|
(update :modified-at #(or % (ct/now)))
|
||||||
(update :sets set)
|
(update :sets set)
|
||||||
(check-token-theme-attrs)
|
(check-token-theme-attrs)
|
||||||
(map->TokenTheme))))
|
(map->TokenTheme))))
|
||||||
@@ -1070,7 +1070,7 @@ Will return a value that matches this schema:
|
|||||||
(let [theme (dm/get-in themes [group name])]
|
(let [theme (dm/get-in themes [group name])]
|
||||||
(if theme
|
(if theme
|
||||||
(let [theme' (-> (make-token-theme (f theme))
|
(let [theme' (-> (make-token-theme (f theme))
|
||||||
(assoc :modified-at (dt/now)))
|
(assoc :modified-at (ct/now)))
|
||||||
group' (:group theme')
|
group' (:group theme')
|
||||||
name' (:name theme')
|
name' (:name theme')
|
||||||
same-group? (= group group')
|
same-group? (= group group')
|
||||||
@@ -1490,7 +1490,7 @@ Will return a value that matches this schema:
|
|||||||
:is-source (get theme "is-source")
|
:is-source (get theme "is-source")
|
||||||
:external-id (get theme "id")
|
:external-id (get theme "id")
|
||||||
:modified-at (some-> (get theme "modified-at")
|
:modified-at (some-> (get theme "modified-at")
|
||||||
(dt/parse-instant))
|
(ct/inst))
|
||||||
:sets (into #{}
|
:sets (into #{}
|
||||||
(comp (map key)
|
(comp (map key)
|
||||||
xf-normalize-set-name
|
xf-normalize-set-name
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as-alias ct]
|
||||||
[app.common.types.plugins :as ctpg]
|
[app.common.types.plugins :as ctpg]
|
||||||
[app.common.types.text :as txt]
|
[app.common.types.text :as txt]
|
||||||
[app.common.uuid :as uuid]))
|
[app.common.uuid :as uuid]))
|
||||||
@@ -31,7 +32,7 @@
|
|||||||
[:line-height :string]
|
[:line-height :string]
|
||||||
[:letter-spacing :string]
|
[:letter-spacing :string]
|
||||||
[:text-transform :string]
|
[:text-transform :string]
|
||||||
[:modified-at {:optional true} ::sm/inst]
|
[:modified-at {:optional true} ::ct/inst]
|
||||||
[:path {:optional true} [:maybe :string]]
|
[:path {:optional true} [:maybe :string]]
|
||||||
[:plugin-data {:optional true} ::ctpg/plugin-data]]))
|
[:plugin-data {:optional true} ::ctpg/plugin-data]]))
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
[clojure.test :as t]))
|
[clojure.test :as t]))
|
||||||
|
|
||||||
(t/deftest compare-time
|
(t/deftest compare-time
|
||||||
(let [dta (dt/parse-instant 10000)
|
(let [dta (dt/inst 10000)
|
||||||
dtb (dt/parse-instant 20000)]
|
dtb (dt/inst 20000)]
|
||||||
(t/is (false? (dt/is-after? dta dtb)))
|
(t/is (false? (dt/is-after? dta dtb)))
|
||||||
(t/is (true? (dt/is-before? dta dtb)))))
|
(t/is (true? (dt/is-before? dta dtb)))))
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#?(:clj [clojure.datafy :refer [datafy]])
|
#?(:clj [clojure.datafy :refer [datafy]])
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.test-helpers.ids-map :as thi]
|
[app.common.test-helpers.ids-map :as thi]
|
||||||
[app.common.time :as dt]
|
[app.common.time :as ct]
|
||||||
[app.common.transit :as tr]
|
[app.common.transit :as tr]
|
||||||
[app.common.types.tokens-lib :as ctob]
|
[app.common.types.tokens-lib :as ctob]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
@@ -20,14 +20,14 @@
|
|||||||
|
|
||||||
(defn setup-virtual-time
|
(defn setup-virtual-time
|
||||||
[next]
|
[next]
|
||||||
(let [current (volatile! (inst-ms (dt/now)))]
|
(let [current (volatile! (inst-ms (ct/now)))]
|
||||||
(with-redefs [dt/now #(dt/parse-instant (vswap! current inc))]
|
(with-redefs [ct/now #(ct/inst (vswap! current inc))]
|
||||||
(next))))
|
(next))))
|
||||||
|
|
||||||
(t/use-fixtures :once setup-virtual-time)
|
(t/use-fixtures :once setup-virtual-time)
|
||||||
|
|
||||||
(t/deftest make-token
|
(t/deftest make-token
|
||||||
(let [now (dt/now)
|
(let [now (ct/now)
|
||||||
token1 (ctob/make-token :id (thi/new-id! :token1)
|
token1 (ctob/make-token :id (thi/new-id! :token1)
|
||||||
:name "test-token-1"
|
:name "test-token-1"
|
||||||
:type :boolean
|
:type :boolean
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
(t/is (= #{"foo" "bar"} (ctob/find-token-value-references "{foo}} + {bar}")))))
|
(t/is (= #{"foo" "bar"} (ctob/find-token-value-references "{foo}} + {bar}")))))
|
||||||
|
|
||||||
(t/deftest make-token-set
|
(t/deftest make-token-set
|
||||||
(let [now (dt/now)
|
(let [now (ct/now)
|
||||||
token-set1 (ctob/make-token-set :name "test-token-set-1")
|
token-set1 (ctob/make-token-set :name "test-token-set-1")
|
||||||
token-set2 (ctob/make-token-set :name "test-token-set-2"
|
token-set2 (ctob/make-token-set :name "test-token-set-2"
|
||||||
:description "test description"
|
:description "test description"
|
||||||
@@ -196,7 +196,7 @@
|
|||||||
(t/is (= (get-in expected ["baz" "boo" :name]) "baz.boo"))))
|
(t/is (= (get-in expected ["baz" "boo" :name]) "baz.boo"))))
|
||||||
|
|
||||||
(t/deftest make-token-theme
|
(t/deftest make-token-theme
|
||||||
(let [now (dt/now)
|
(let [now (ct/now)
|
||||||
token-theme1 (ctob/make-token-theme :name "test-token-theme-1")
|
token-theme1 (ctob/make-token-theme :name "test-token-theme-1")
|
||||||
token-theme2 (ctob/make-token-theme :name "test-token-theme-2"
|
token-theme2 (ctob/make-token-theme :name "test-token-theme-2"
|
||||||
:group "group-1"
|
:group "group-1"
|
||||||
@@ -266,7 +266,7 @@
|
|||||||
(t/is (= (ctob/set-count tokens-lib') 1))
|
(t/is (= (ctob/set-count tokens-lib') 1))
|
||||||
(t/is (= (ctob/get-name token-set') "test-token-set"))
|
(t/is (= (ctob/get-name token-set') "test-token-set"))
|
||||||
(t/is (= (ctob/get-description token-set') "some description"))
|
(t/is (= (ctob/get-description token-set') "some description"))
|
||||||
(t/is (dt/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
(t/is (ct/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
||||||
|
|
||||||
(t/deftest rename-token-set
|
(t/deftest rename-token-set
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -282,7 +282,7 @@
|
|||||||
|
|
||||||
(t/is (= (ctob/set-count tokens-lib') 1))
|
(t/is (= (ctob/set-count tokens-lib') 1))
|
||||||
(t/is (= (ctob/get-name token-set') "updated-name"))
|
(t/is (= (ctob/get-name token-set') "updated-name"))
|
||||||
(t/is (dt/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
(t/is (ct/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
||||||
|
|
||||||
(t/deftest rename-token-set-group
|
(t/deftest rename-token-set-group
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -403,7 +403,7 @@
|
|||||||
(t/is (= (ctob/set-count tokens-lib') 1))
|
(t/is (= (ctob/set-count tokens-lib') 1))
|
||||||
(t/is (= (count (ctob/get-tokens-map token-set')) 1))
|
(t/is (= (count (ctob/get-tokens-map token-set')) 1))
|
||||||
(t/is (= (:name token') "test-token"))
|
(t/is (= (:name token') "test-token"))
|
||||||
(t/is (dt/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
(t/is (ct/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
||||||
|
|
||||||
(t/deftest update-token
|
(t/deftest update-token
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -445,8 +445,8 @@
|
|||||||
(t/is (= (:name token') "test-token-1"))
|
(t/is (= (:name token') "test-token-1"))
|
||||||
(t/is (= (:description token') "some description"))
|
(t/is (= (:description token') "some description"))
|
||||||
(t/is (= (:value token') false))
|
(t/is (= (:value token') false))
|
||||||
(t/is (dt/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))
|
(t/is (ct/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))
|
||||||
(t/is (dt/is-after? (:modified-at token') (:modified-at token)))))
|
(t/is (ct/is-after? (:modified-at token') (:modified-at token)))))
|
||||||
|
|
||||||
(t/deftest rename-token
|
(t/deftest rename-token
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -479,8 +479,8 @@
|
|||||||
(t/is (= (:name token') "updated-name"))
|
(t/is (= (:name token') "updated-name"))
|
||||||
(t/is (= (:description token') ""))
|
(t/is (= (:description token') ""))
|
||||||
(t/is (= (:value token') true))
|
(t/is (= (:value token') true))
|
||||||
(t/is (dt/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))
|
(t/is (ct/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))
|
||||||
(t/is (dt/is-after? (:modified-at token') (:modified-at token)))))
|
(t/is (ct/is-after? (:modified-at token') (:modified-at token)))))
|
||||||
|
|
||||||
(t/deftest delete-token
|
(t/deftest delete-token
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -502,7 +502,7 @@
|
|||||||
(t/is (= (ctob/set-count tokens-lib') 1))
|
(t/is (= (ctob/set-count tokens-lib') 1))
|
||||||
(t/is (= (count (ctob/get-tokens-map token-set')) 0))
|
(t/is (= (count (ctob/get-tokens-map token-set')) 0))
|
||||||
(t/is (nil? token'))
|
(t/is (nil? token'))
|
||||||
(t/is (dt/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
(t/is (ct/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
||||||
|
|
||||||
(t/deftest get-ordered-sets
|
(t/deftest get-ordered-sets
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -788,7 +788,7 @@
|
|||||||
(t/is (= (ctob/theme-count tokens-lib') 2))
|
(t/is (= (ctob/theme-count tokens-lib') 2))
|
||||||
(t/is (= (:name token-theme') "test-token-theme"))
|
(t/is (= (:name token-theme') "test-token-theme"))
|
||||||
(t/is (= (:description token-theme') "some description"))
|
(t/is (= (:description token-theme') "some description"))
|
||||||
(t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
|
(t/is (ct/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
|
||||||
|
|
||||||
(t/deftest rename-token-theme
|
(t/deftest rename-token-theme
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -805,7 +805,7 @@
|
|||||||
|
|
||||||
(t/is (= (ctob/theme-count tokens-lib') 2))
|
(t/is (= (ctob/theme-count tokens-lib') 2))
|
||||||
(t/is (= (:name token-theme') "updated-name"))
|
(t/is (= (:name token-theme') "updated-name"))
|
||||||
(t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
|
(t/is (ct/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
|
||||||
|
|
||||||
(t/deftest delete-token-theme
|
(t/deftest delete-token-theme
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -834,7 +834,7 @@
|
|||||||
token-theme (ctob/get-theme tokens-lib "" "test-token-theme")
|
token-theme (ctob/get-theme tokens-lib "" "test-token-theme")
|
||||||
token-theme' (ctob/get-theme tokens-lib' "" "test-token-theme")]
|
token-theme' (ctob/get-theme tokens-lib' "" "test-token-theme")]
|
||||||
|
|
||||||
(t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
|
(t/is (ct/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
|
||||||
|
|
||||||
(t/deftest transit-serialization
|
(t/deftest transit-serialization
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -952,8 +952,8 @@
|
|||||||
(t/is (= (:name token') "group1.test-token-2"))
|
(t/is (= (:name token') "group1.test-token-2"))
|
||||||
(t/is (= (:description token') "some description"))
|
(t/is (= (:description token') "some description"))
|
||||||
(t/is (= (:value token') false))
|
(t/is (= (:value token') false))
|
||||||
(t/is (dt/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))
|
(t/is (ct/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))
|
||||||
(t/is (dt/is-after? (:modified-at token') (:modified-at token)))))
|
(t/is (ct/is-after? (:modified-at token') (:modified-at token)))))
|
||||||
|
|
||||||
(t/deftest update-token-in-sets-rename
|
(t/deftest update-token-in-sets-rename
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -989,8 +989,8 @@
|
|||||||
(t/is (= (:name token') "group1.updated-name"))
|
(t/is (= (:name token') "group1.updated-name"))
|
||||||
(t/is (= (:description token') ""))
|
(t/is (= (:description token') ""))
|
||||||
(t/is (= (:value token') true))
|
(t/is (= (:value token') true))
|
||||||
(t/is (dt/is-after? (ctob/get-modified-at token-set') (:ctob/get-modified-at token-set)))
|
(t/is (ct/is-after? (ctob/get-modified-at token-set') (:ctob/get-modified-at token-set)))
|
||||||
(t/is (dt/is-after? (:modified-at token') (:modified-at token)))))
|
(t/is (ct/is-after? (:modified-at token') (:modified-at token)))))
|
||||||
|
|
||||||
(t/deftest move-token-of-group
|
(t/deftest move-token-of-group
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -1027,8 +1027,8 @@
|
|||||||
(t/is (= (:name token') "group2.updated-name"))
|
(t/is (= (:name token') "group2.updated-name"))
|
||||||
(t/is (= (:description token') ""))
|
(t/is (= (:description token') ""))
|
||||||
(t/is (= (:value token') true))
|
(t/is (= (:value token') true))
|
||||||
(t/is (dt/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))
|
(t/is (ct/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))
|
||||||
(t/is (dt/is-after? (:modified-at token') (:modified-at token)))))
|
(t/is (ct/is-after? (:modified-at token') (:modified-at token)))))
|
||||||
|
|
||||||
(t/deftest delete-token-in-group
|
(t/deftest delete-token-in-group
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -1053,7 +1053,7 @@
|
|||||||
(t/is (= (ctob/set-count tokens-lib') 1))
|
(t/is (= (ctob/set-count tokens-lib') 1))
|
||||||
(t/is (= (count (ctob/get-tokens-map token-set')) 1))
|
(t/is (= (count (ctob/get-tokens-map token-set')) 1))
|
||||||
(t/is (nil? token'))
|
(t/is (nil? token'))
|
||||||
(t/is (dt/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
(t/is (ct/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
||||||
|
|
||||||
(t/deftest update-token-set-in-groups
|
(t/deftest update-token-set-in-groups
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -1079,7 +1079,7 @@
|
|||||||
(t/is (= (d/index-of (keys group1') "S-token-set-2") 0))
|
(t/is (= (d/index-of (keys group1') "S-token-set-2") 0))
|
||||||
(t/is (= (ctob/get-name token-set') "group1/token-set-2"))
|
(t/is (= (ctob/get-name token-set') "group1/token-set-2"))
|
||||||
(t/is (= (ctob/get-description token-set') "some description"))
|
(t/is (= (ctob/get-description token-set') "some description"))
|
||||||
(t/is (dt/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
(t/is (ct/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
||||||
|
|
||||||
(t/deftest rename-token-set-in-groups
|
(t/deftest rename-token-set-in-groups
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -1105,7 +1105,7 @@
|
|||||||
(t/is (= (d/index-of (keys group1') "S-updated-name") 0))
|
(t/is (= (d/index-of (keys group1') "S-updated-name") 0))
|
||||||
(t/is (= (ctob/get-name token-set') "group1/updated-name"))
|
(t/is (= (ctob/get-name token-set') "group1/updated-name"))
|
||||||
(t/is (= (ctob/get-description token-set') ""))
|
(t/is (= (ctob/get-description token-set') ""))
|
||||||
(t/is (dt/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
(t/is (ct/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
||||||
|
|
||||||
(t/deftest move-token-set-of-group
|
(t/deftest move-token-set-of-group
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -1133,7 +1133,7 @@
|
|||||||
(t/is (nil? (get group1' "S-updated-name")))
|
(t/is (nil? (get group1' "S-updated-name")))
|
||||||
(t/is (= (ctob/get-name token-set') "group2/updated-name"))
|
(t/is (= (ctob/get-name token-set') "group2/updated-name"))
|
||||||
(t/is (= (ctob/get-description token-set') ""))
|
(t/is (= (ctob/get-description token-set') ""))
|
||||||
(t/is (dt/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
(t/is (ct/is-after? (ctob/get-modified-at token-set') (ctob/get-modified-at token-set)))))
|
||||||
|
|
||||||
(t/deftest delete-token-set-in-group
|
(t/deftest delete-token-set-in-group
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -1174,7 +1174,7 @@
|
|||||||
(t/is (= (:name token-theme') "token-theme-2"))
|
(t/is (= (:name token-theme') "token-theme-2"))
|
||||||
(t/is (= (:group token-theme') "group1"))
|
(t/is (= (:group token-theme') "group1"))
|
||||||
(t/is (= (:description token-theme') "some description"))
|
(t/is (= (:description token-theme') "some description"))
|
||||||
(t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
|
(t/is (ct/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
|
||||||
|
|
||||||
(t/deftest get-token-theme-groups
|
(t/deftest get-token-theme-groups
|
||||||
(let [token-lib (-> (ctob/make-tokens-lib)
|
(let [token-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -1211,7 +1211,7 @@
|
|||||||
(t/is (= (:name token-theme') "updated-name"))
|
(t/is (= (:name token-theme') "updated-name"))
|
||||||
(t/is (= (:group token-theme') "group1"))
|
(t/is (= (:group token-theme') "group1"))
|
||||||
(t/is (= (:description token-theme') ""))
|
(t/is (= (:description token-theme') ""))
|
||||||
(t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
|
(t/is (ct/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
|
||||||
|
|
||||||
(t/deftest move-token-theme-of-group
|
(t/deftest move-token-theme-of-group
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -1241,7 +1241,7 @@
|
|||||||
(t/is (= (:name token-theme') "updated-name"))
|
(t/is (= (:name token-theme') "updated-name"))
|
||||||
(t/is (= (:group token-theme') "group2"))
|
(t/is (= (:group token-theme') "group2"))
|
||||||
(t/is (= (:description token-theme') ""))
|
(t/is (= (:description token-theme') ""))
|
||||||
(t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
|
(t/is (ct/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
|
||||||
|
|
||||||
(t/deftest delete-token-theme-in-group
|
(t/deftest delete-token-theme-in-group
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
@@ -1357,7 +1357,7 @@
|
|||||||
|
|
||||||
#?(:clj
|
#?(:clj
|
||||||
(t/deftest export-dtcg-json
|
(t/deftest export-dtcg-json
|
||||||
(let [now (dt/now)
|
(let [now (ct/now)
|
||||||
tokens-lib (-> (ctob/make-tokens-lib)
|
tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
(ctob/add-set (ctob/make-token-set :name "core"
|
(ctob/add-set (ctob/make-token-set :name "core"
|
||||||
:tokens {"colors.red.600"
|
:tokens {"colors.red.600"
|
||||||
@@ -1408,7 +1408,7 @@
|
|||||||
|
|
||||||
#?(:clj
|
#?(:clj
|
||||||
(t/deftest export-parse-dtcg-json
|
(t/deftest export-parse-dtcg-json
|
||||||
(with-redefs [dt/now (constantly #inst "2024-10-16T12:01:20.257840055-00:00")
|
(with-redefs [ct/now (constantly #inst "2024-10-16T12:01:20.257840055-00:00")
|
||||||
uuid/next (constantly uuid/zero)]
|
uuid/next (constantly uuid/zero)]
|
||||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
(ctob/add-set (ctob/make-token-set :name "core"
|
(ctob/add-set (ctob/make-token-set :name "core"
|
||||||
@@ -1477,7 +1477,7 @@
|
|||||||
|
|
||||||
#?(:clj
|
#?(:clj
|
||||||
(t/deftest export-dtcg-json-with-active-theme-and-set
|
(t/deftest export-dtcg-json-with-active-theme-and-set
|
||||||
(let [now (dt/now)
|
(let [now (ct/now)
|
||||||
tokens-lib (-> (ctob/make-tokens-lib)
|
tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
(ctob/add-set (ctob/make-token-set :name "core"
|
(ctob/add-set (ctob/make-token-set :name "core"
|
||||||
:tokens {"colors.red.600"
|
:tokens {"colors.red.600"
|
||||||
@@ -1530,7 +1530,7 @@
|
|||||||
|
|
||||||
#?(:clj
|
#?(:clj
|
||||||
(t/deftest export-dtcg-multi-file
|
(t/deftest export-dtcg-multi-file
|
||||||
(let [now (dt/now)
|
(let [now (ct/now)
|
||||||
tokens-lib (-> (ctob/make-tokens-lib)
|
tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
(ctob/add-set (ctob/make-token-set :name "some/set"
|
(ctob/add-set (ctob/make-token-set :name "some/set"
|
||||||
:tokens {"colors.red.600"
|
:tokens {"colors.red.600"
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ __metadata:
|
|||||||
resolution: "common@workspace:."
|
resolution: "common@workspace:."
|
||||||
dependencies:
|
dependencies:
|
||||||
concurrently: "npm:^9.1.2"
|
concurrently: "npm:^9.1.2"
|
||||||
luxon: "npm:^3.6.1"
|
date-fns: "npm:^4.1.0"
|
||||||
nodemon: "npm:^3.1.10"
|
nodemon: "npm:^3.1.10"
|
||||||
source-map-support: "npm:^0.5.21"
|
source-map-support: "npm:^0.5.21"
|
||||||
ws: "npm:^8.18.2"
|
ws: "npm:^8.18.2"
|
||||||
@@ -291,6 +291,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"date-fns@npm:^4.1.0":
|
||||||
|
version: 4.1.0
|
||||||
|
resolution: "date-fns@npm:4.1.0"
|
||||||
|
checksum: 10c0/b79ff32830e6b7faa009590af6ae0fb8c3fd9ffad46d930548fbb5acf473773b4712ae887e156ba91a7b3dc30591ce0f517d69fd83bd9c38650fdc03b4e0bac8
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"debug@npm:4, debug@npm:^4, debug@npm:^4.3.4":
|
"debug@npm:4, debug@npm:^4, debug@npm:^4.3.4":
|
||||||
version: 4.4.1
|
version: 4.4.1
|
||||||
resolution: "debug@npm:4.4.1"
|
resolution: "debug@npm:4.4.1"
|
||||||
@@ -620,13 +627,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"luxon@npm:^3.6.1":
|
|
||||||
version: 3.6.1
|
|
||||||
resolution: "luxon@npm:3.6.1"
|
|
||||||
checksum: 10c0/906d57a9dc4d1de9383f2e9223e378c298607c1b4d17b6657b836a3cd120feb1c1de3b5d06d846a3417e1ca764de8476e8c23b3cd4083b5cdb870adcb06a99d5
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"make-fetch-happen@npm:^14.0.3":
|
"make-fetch-happen@npm:^14.0.3":
|
||||||
version: 14.0.3
|
version: 14.0.3
|
||||||
resolution: "make-fetch-happen@npm:14.0.3"
|
resolution: "make-fetch-happen@npm:14.0.3"
|
||||||
|
|||||||
@@ -114,7 +114,6 @@
|
|||||||
"js-beautify": "^1.15.4",
|
"js-beautify": "^1.15.4",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"luxon": "^3.6.1",
|
|
||||||
"opentype.js": "^1.3.4",
|
"opentype.js": "^1.3.4",
|
||||||
"postcss-modules": "^6.0.1",
|
"postcss-modules": "^6.0.1",
|
||||||
"randomcolor": "^0.6.2",
|
"randomcolor": "^0.6.2",
|
||||||
|
|||||||
@@ -10,11 +10,11 @@
|
|||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.files.changes :as cpc]
|
[app.common.files.changes :as cpc]
|
||||||
[app.common.logging :as log]
|
[app.common.logging :as log]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.shape-tree :as ctst]
|
[app.common.types.shape-tree :as ctst]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.helpers :as dsh]
|
[app.main.data.helpers :as dsh]
|
||||||
[app.main.worker :as mw]
|
[app.main.worker :as mw]
|
||||||
[app.util.time :as dt]
|
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
source (d/nilv source :local)
|
source (d/nilv source :local)
|
||||||
local? (= source :local)
|
local? (= source :local)
|
||||||
commit {:id commit-id
|
commit {:id commit-id
|
||||||
:created-at (dt/now)
|
:created-at (ct/now)
|
||||||
:source source
|
:source source
|
||||||
:origin (ptk/type origin)
|
:origin (ptk/type origin)
|
||||||
:features features
|
:features features
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.time :as ct]
|
||||||
[app.common.types.shape-tree :as ctst]
|
[app.common.types.shape-tree :as ctst]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.event :as ev]
|
[app.main.data.event :as ev]
|
||||||
@@ -35,8 +36,8 @@
|
|||||||
[:seqn :int]
|
[:seqn :int]
|
||||||
[:content :string]
|
[:content :string]
|
||||||
[:participants ::sm/set-of-uuid]
|
[:participants ::sm/set-of-uuid]
|
||||||
[:created-at ::sm/inst]
|
[:created-at ::ct/inst]
|
||||||
[:modified-at ::sm/inst]
|
[:modified-at ::ct/inst]
|
||||||
[:position ::gpt/point]
|
[:position ::gpt/point]
|
||||||
[:count-unread-comments {:optional true} :int]
|
[:count-unread-comments {:optional true} :int]
|
||||||
[:count-comments {:optional true} :int]])
|
[:count-comments {:optional true} :int]])
|
||||||
@@ -49,8 +50,8 @@
|
|||||||
[:owner-id ::sm/uuid]
|
[:owner-id ::sm/uuid]
|
||||||
[:owner-fullname {:optional true} ::sm/text]
|
[:owner-fullname {:optional true} ::sm/text]
|
||||||
[:owner-email {:optional true} ::sm/email]
|
[:owner-email {:optional true} ::sm/email]
|
||||||
[:created-at ::sm/inst]
|
[:created-at ::ct/inst]
|
||||||
[:modified-at ::sm/inst]
|
[:modified-at ::ct/inst]
|
||||||
[:content :string]])
|
[:content :string]])
|
||||||
|
|
||||||
(def check-comment-thread!
|
(def check-comment-thread!
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user