mirror of
https://github.com/penpot/penpot.git
synced 2025-03-09 06:11:23 -05:00
🐛 Fix typos in backend
This commit is contained in:
parent
589e646023
commit
cd2d3d5fa3
33 changed files with 65 additions and 61 deletions
|
@ -72,7 +72,7 @@
|
|||
;; Copy run script template
|
||||
(-> ($ cp "./scripts/manage.template.sh" "./target/dist/manage.sh") check)
|
||||
|
||||
;; Add exec permisions to scripts.
|
||||
;; Add exec permissions to scripts.
|
||||
(-> ($ chmod +x "./target/dist/run.sh") check)
|
||||
(-> ($ chmod +x "./target/dist/manage.sh") check)
|
||||
|
||||
|
|
|
@ -173,14 +173,14 @@
|
|||
|
||||
(defn- process-report
|
||||
[cfg {:keys [type profile-id] :as report}]
|
||||
(l/trace :action "procesing report" :report (pr-str report))
|
||||
(l/trace :action "processing report" :report (pr-str report))
|
||||
(cond
|
||||
;; In this case we receive a bounce/complaint notification without
|
||||
;; confirmed identity, we just emit a warning but do nothing about
|
||||
;; it because this is not a normal case. All notifications should
|
||||
;; come with profile identity.
|
||||
(nil? profile-id)
|
||||
(l/warn :msg "a notification without identity recevied from AWS"
|
||||
(l/warn :msg "a notification without identity received from AWS"
|
||||
:report (pr-str report))
|
||||
|
||||
(= "bounce" type)
|
||||
|
|
|
@ -130,7 +130,7 @@
|
|||
(when-not (set/subset? provider-roles profile-roles)
|
||||
(ex/raise :type :internal
|
||||
:code :unable-to-auth
|
||||
:hint "not enought permissions"))))
|
||||
:hint "not enough permissions"))))
|
||||
|
||||
(cond-> info
|
||||
(some? (:invitation-token state))
|
||||
|
|
|
@ -150,7 +150,7 @@
|
|||
(defmethod ig/init-key ::collector
|
||||
[_ cfg]
|
||||
(when (contains? cf/flags :audit-log)
|
||||
(l/info :msg "intializing audit log collector")
|
||||
(l/info :msg "initializing audit log collector")
|
||||
(let [input (a/chan 512 event-xform)
|
||||
buffer (aa/batch input {:max-batch-size 100
|
||||
:max-batch-age (* 10 1000) ; 10s
|
||||
|
@ -159,7 +159,7 @@
|
|||
(when-let [[_type events] (a/<! buffer)]
|
||||
(let [res (a/<! (persist-events cfg events))]
|
||||
(when (ex/exception? res)
|
||||
(l/error :hint "error on persiting events"
|
||||
(l/error :hint "error on persisting events"
|
||||
:cause res)))
|
||||
(recur)))
|
||||
|
||||
|
@ -195,7 +195,7 @@
|
|||
;; Archive Task
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; This is a task responsible to send the accomulated events to an
|
||||
;; This is a task responsible to send the accumulated events to an
|
||||
;; external service for archival.
|
||||
|
||||
(declare archive-events)
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
(defmethod ig/init-key ::reporter
|
||||
[_ {:keys [receiver uri] :as cfg}]
|
||||
(when uri
|
||||
(l/info :msg "intializing loki reporter" :uri uri)
|
||||
(l/info :msg "initializing loki reporter" :uri uri)
|
||||
(let [input (a/chan (a/dropping-buffer 512))]
|
||||
(receiver :sub input)
|
||||
(a/go-loop []
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
(defmethod ig/init-key ::receiver
|
||||
[_ {:keys [endpoint] :as cfg}]
|
||||
(l/info :msg "intializing ZMQ receiver" :bind endpoint)
|
||||
(l/info :msg "initializing ZMQ receiver" :bind endpoint)
|
||||
(let [buffer (a/chan 1)
|
||||
output (a/chan 1 (comp (filter map?)
|
||||
(map prepare)))
|
||||
|
|
|
@ -213,7 +213,7 @@
|
|||
;; --- Fonts Generation
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(def all-fotmats #{"font/woff2", "font/woff", "font/otf", "font/ttf"})
|
||||
(def all-formats #{"font/woff2", "font/woff", "font/otf", "font/ttf"})
|
||||
|
||||
(defmethod process :generate-fonts
|
||||
[{:keys [input] :as params}]
|
||||
|
@ -334,7 +334,7 @@
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn configure-assets-storage
|
||||
"Given storage map, returns a storage configured with the apropriate
|
||||
"Given storage map, returns a storage configured with the appropriate
|
||||
backend for assets."
|
||||
[storage conn]
|
||||
(-> storage
|
||||
|
|
|
@ -22,7 +22,7 @@ CREATE TABLE storage_data (
|
|||
CREATE INDEX storage_data__id__idx ON storage_data(id);
|
||||
|
||||
-- Table used for store inflight upload ids, for later recheck and
|
||||
-- delete possible staled files that exists on the phisical storage
|
||||
-- delete possible staled files that exists on the physical storage
|
||||
-- but does not exists in the 'storage_object' table.
|
||||
|
||||
CREATE TABLE storage_pending (
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- Fix problem with content-type inconherence
|
||||
-- Fix problem with content-type incoherence
|
||||
|
||||
UPDATE storage_object so
|
||||
SET metadata = jsonb_set(metadata, '{~:content-type}', to_jsonb(fmo.mtype))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--- This is a second migration but it should be applied when manual
|
||||
--- migration intervention is alteady executed.
|
||||
--- migration intervention is already executed.
|
||||
|
||||
ALTER TABLE file_media_object ALTER COLUMN media_id SET NOT NULL;
|
||||
DROP TABLE file_media_thumbnail;
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
alter index color_colection__team_id__idx to color_collection__team_id__idx;
|
||||
alter index icon_colection__team_id__idx to icon_collection__team_id__idx;
|
||||
alter index file__modified_at__has_media_trimed__idx to file__modified_at__has_media_trimmed__idx;
|
||||
alter index media_bject__file_id__idx rename to media_object__file_id__idx;
|
|
@ -181,7 +181,7 @@
|
|||
(reify RedisPubSubListener
|
||||
(message [it pattern topic message])
|
||||
(message [it topic message]
|
||||
;; There are no back pressure, so we use a slidding
|
||||
;; There are no back pressure, so we use a sliding
|
||||
;; buffer for cases when the pubsub broker sends
|
||||
;; more messages that we can process.
|
||||
(let [val {:topic topic :message (blob/decode message)}]
|
||||
|
@ -243,7 +243,7 @@
|
|||
(recur))
|
||||
(a/close! rcv-ch)))
|
||||
|
||||
;; Asyncrhonous message processing loop;x
|
||||
;; Asynchronous message processing loop;x
|
||||
(a/go-loop []
|
||||
(if-let [{:keys [topic message]} (a/<! rcv-ch)]
|
||||
;; This means we receive data from redis and we need to
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
(mtx/wrap-summary f (::mobj cfg) [(::sv/name mdata)]))
|
||||
|
||||
;; Wrap the rpc handler with a semaphore if it is specified in the
|
||||
;; metadata asocciated with the handler.
|
||||
;; metadata associated with the handler.
|
||||
(defn- wrap-with-rlimits
|
||||
[cfg f mdata]
|
||||
(if-let [key (:rlimit mdata)]
|
||||
|
|
|
@ -176,7 +176,7 @@
|
|||
:content content})]
|
||||
|
||||
;; NOTE: this is done in SQL instead of using db/update!
|
||||
;; helper bacause currently the helper does not allow pass raw
|
||||
;; helper because currently the helper does not allow pass raw
|
||||
;; function call parameters to the underlying prepared
|
||||
;; statement; in a future when we fix/improve it, this can be
|
||||
;; changed to use the helper.
|
||||
|
|
|
@ -181,7 +181,7 @@
|
|||
:library-file-id library-id}))
|
||||
|
||||
|
||||
;; --- Mutation: Update syncrhonization status of a link
|
||||
;; --- Mutation: Update synchronization status of a link
|
||||
|
||||
(declare update-sync)
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
(= :image (:type form)))
|
||||
(update-in [:metadata :id] #(get index % %))))
|
||||
|
||||
;; A function responsible to analize all file data and
|
||||
;; A function responsible to analyze all file data and
|
||||
;; replace the old :component-file reference with the new
|
||||
;; ones, using the provided file-index
|
||||
(relink-shapes [data]
|
||||
|
@ -294,7 +294,7 @@
|
|||
;; move all files to the project
|
||||
(db/exec-one! conn [sql:move-files project-id fids])
|
||||
|
||||
;; delete posible broken relations on moved files
|
||||
;; delete possible broken relations on moved files
|
||||
(db/exec-one! conn [sql:delete-broken-relations pids])
|
||||
|
||||
nil)))
|
||||
|
@ -329,7 +329,7 @@
|
|||
{:team-id team-id}
|
||||
{:id project-id})
|
||||
|
||||
;; delete posible broken relations on moved files
|
||||
;; delete possible broken relations on moved files
|
||||
(db/exec-one! conn [sql:delete-broken-relations pids])
|
||||
|
||||
nil)))
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
:code :email-domain-is-not-allowed)))
|
||||
|
||||
;; Don't allow proceed in preparing registration if the profile is
|
||||
;; already reported as spamer.
|
||||
;; already reported as spammer.
|
||||
(when (eml/has-bounce-reports? pool (:email params))
|
||||
(ex/raise :type :validation
|
||||
:code :email-has-permanent-bounces
|
||||
|
@ -175,7 +175,7 @@
|
|||
::audit/profile-id (:id profile)}))
|
||||
|
||||
;; If auth backend is different from "penpot" means user is
|
||||
;; registring using third party auth mechanism; in this case
|
||||
;; registering using third party auth mechanism; in this case
|
||||
;; we need to mark this session as logged.
|
||||
(not= "penpot" (:auth-backend profile))
|
||||
(with-meta (profile/strip-private-attrs profile)
|
||||
|
@ -433,7 +433,7 @@
|
|||
;; --- MUTATION: Request Email Change
|
||||
|
||||
(declare request-email-change)
|
||||
(declare change-email-inmediatelly)
|
||||
(declare change-email-immediately)
|
||||
|
||||
(s/def ::request-email-change
|
||||
(s/keys :req-un [::email]))
|
||||
|
@ -449,9 +449,9 @@
|
|||
(if (or (cf/get :smtp-enabled)
|
||||
(contains? cf/flags :smtp))
|
||||
(request-email-change cfg params)
|
||||
(change-email-inmediatelly cfg params)))))
|
||||
(change-email-immediately cfg params)))))
|
||||
|
||||
(defn- change-email-inmediatelly
|
||||
(defn- change-email-immediately
|
||||
[{:keys [conn]} {:keys [profile email] :as params}]
|
||||
(when (not= email (:email profile))
|
||||
(check-profile-existence! conn params))
|
||||
|
@ -633,7 +633,7 @@
|
|||
(let [rows (db/exec! conn [sql:owned-teams profile-id])]
|
||||
;; If we found owned teams with more than one profile we don't
|
||||
;; allow delete profile until the user properly transfer ownership
|
||||
;; or explictly removes all participants from the team.
|
||||
;; or explicitly removes all participants from the team.
|
||||
(when (some #(> (:num-profiles %) 1) rows)
|
||||
(ex/raise :type :validation
|
||||
:code :owner-teams-with-people
|
||||
|
|
|
@ -114,7 +114,7 @@
|
|||
(when (some :is-owner perms)
|
||||
(ex/raise :type :validation
|
||||
:code :owner-cant-leave-team
|
||||
:hint "reasing owner before leave"))
|
||||
:hint "releasing owner before leave"))
|
||||
|
||||
(when-not (> (count members) 1)
|
||||
(ex/raise :type :validation
|
||||
|
@ -134,7 +134,7 @@
|
|||
(s/keys :req-un [::profile-id ::id]))
|
||||
|
||||
;; TODO: right now just don't allow delete default team, in future it
|
||||
;; should raise a speific exception for signal that this acction is
|
||||
;; should raise a specific exception for signal that this action is
|
||||
;; not allowed.
|
||||
|
||||
(sv/defmethod ::delete-team
|
||||
|
@ -173,8 +173,8 @@
|
|||
|
||||
;; We retrieve all team members instead of query the
|
||||
;; database for a single member. This is just for
|
||||
;; convenience, if this bocomes a bottleneck or problematic,
|
||||
;; we will change it to more efficient fetch mechanims.
|
||||
;; convenience, if this becomes a bottleneck or problematic,
|
||||
;; we will change it to more efficient fetch mechanisms.
|
||||
members (teams/retrieve-team-members conn team-id)
|
||||
member (d/seek #(= member-id (:id %)) members)
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@
|
|||
|
||||
;; If the session does not matches the invited member, replace
|
||||
;; the session with a new one matching the invited member.
|
||||
;; This techinique should be considered secure because the
|
||||
;; This technique should be considered secure because the
|
||||
;; user clicking the link he already has access to the email
|
||||
;; account.
|
||||
(with-meta
|
||||
|
@ -179,7 +179,7 @@
|
|||
::audit/profile-id member-id}))
|
||||
|
||||
;; In this case, we wait until frontend app redirect user to
|
||||
;; registeration page, the user is correctly registered and the
|
||||
;; registration page, the user is correctly registered and the
|
||||
;; register mutation call us again with the same token to finally
|
||||
;; create the corresponding team-profile relation from the first
|
||||
;; condition of this if.
|
||||
|
|
|
@ -84,8 +84,8 @@
|
|||
(let [perms (get-permissions conn profile-id file-id)
|
||||
ldata (retrieve-share-link conn file-id share-id)]
|
||||
|
||||
;; NOTE: in a future when share-link becomes more powerfull and
|
||||
;; will allow us specify which parts of the app is availabel, we
|
||||
;; NOTE: in a future when share-link becomes more powerful and
|
||||
;; will allow us specify which parts of the app is available, we
|
||||
;; will probably need to tweak this function in order to expose
|
||||
;; this flags to the frontend.
|
||||
(cond
|
||||
|
@ -227,7 +227,7 @@
|
|||
(= frame-id uuid/zero)
|
||||
(not (some? (get-in objects [frame-id :thumbnail]))))))
|
||||
|
||||
;; We need to remove from the attribute :shapes its childrens because
|
||||
;; We need to remove from the attribute :shapes its children because
|
||||
;; they will not be sent in the data
|
||||
remove-frame-children
|
||||
(fn [[id shape]]
|
||||
|
|
|
@ -106,6 +106,6 @@
|
|||
;; --- Attrs Helpers
|
||||
|
||||
(defn strip-private-attrs
|
||||
"Only selects a publicy visible profile attrs."
|
||||
"Only selects a publicly visible profile attrs."
|
||||
[row]
|
||||
(dissoc row :password :deleted-at))
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
(ex/raise :type :not-found
|
||||
:code :object-not-found))
|
||||
|
||||
;; When we have only profile, we need to check read permissiones
|
||||
;; When we have only profile, we need to check read permissions
|
||||
;; on file.
|
||||
(when (and profile-id (not slink))
|
||||
(files/check-read-permissions! conn profile-id file-id))
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
|
||||
|
||||
(defn duplicate-file
|
||||
"This is a raw version of duplication of file just only for forensic analisys"
|
||||
"This is a raw version of duplication of file just only for forensic analysis"
|
||||
[system file-id email]
|
||||
(db/with-atomic [conn (:app.db/pool system)]
|
||||
(when-let [profile (some->> (prof/retrieve-profile-data-by-email conn (str/lower email))
|
||||
|
|
|
@ -188,7 +188,7 @@
|
|||
object))
|
||||
|
||||
(defn clone-object
|
||||
"Creates a clone of the provided object using backend basded efficient
|
||||
"Creates a clone of the provided object using backend based efficient
|
||||
method. Always clones objects to the configured default."
|
||||
[{:keys [pool conn] :as storage} object]
|
||||
(us/assert ::storage storage)
|
||||
|
@ -323,18 +323,18 @@
|
|||
returning *;")
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Garbage Collection: Analize touched objects
|
||||
;; Garbage Collection: Analyze touched objects
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; This task is part of the garbage collection of storage objects and
|
||||
;; is responsible on analizing the touched objects and mark them for deletion
|
||||
;; is responsible on analyzing the touched objects and mark them for deletion
|
||||
;; if corresponds.
|
||||
;;
|
||||
;; When file_media_object is deleted, the depending storage_object are
|
||||
;; marked as touched. This means that some files that depend on a
|
||||
;; concrete storage_object are no longer exists and maybe this
|
||||
;; storage_object is no longer necessary and can be ellegible for
|
||||
;; elimination. This task peridically analizes touched objects and
|
||||
;; storage_object is no longer necessary and can be eligible for
|
||||
;; elimination. This task periodically analyzes touched objects and
|
||||
;; mark them as freeze (means that has other references and the object
|
||||
;; is still valid) or deleted (no more references to this object so is
|
||||
;; ready to be deleted).
|
||||
|
@ -408,7 +408,7 @@
|
|||
;; For this situations we need to write a "log" of inserted files that
|
||||
;; are checked in some time in future. If physical file exists but the
|
||||
;; database refence does not exists means that leaked file is found
|
||||
;; and is inmediatelly deleted. The responsability of this task is
|
||||
;; and is immediately deleted. The responsibility of this task is
|
||||
;; check that write log for possible leaked files.
|
||||
|
||||
(def recheck-min-age (dt/duration {:hours 1}))
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
(ns app.tasks.file-media-gc
|
||||
"A maintenance task that is responsible to purge the unused media
|
||||
objects from files. A file is ellegible to be garbage collected
|
||||
objects from files. A file is eligible to be garbage collected
|
||||
after some period of inactivity (the default threshold is 72h)."
|
||||
(:require
|
||||
[app.common.logging :as l]
|
||||
|
@ -107,7 +107,7 @@
|
|||
:thumbnail-id (:thumbnail-id mobj))
|
||||
|
||||
;; NOTE: deleting the file-media-object in the database
|
||||
;; automatically marks as toched the referenced storage
|
||||
;; automatically marks as touched the referenced storage
|
||||
;; objects. The touch mechanism is needed because many files can
|
||||
;; point to the same storage objects and we can't just delete
|
||||
;; them.
|
||||
|
|
|
@ -129,7 +129,7 @@
|
|||
(doseq [{:keys [id] :as profile} profiles]
|
||||
(l/trace :action "delete object" :table table :id id)
|
||||
|
||||
;; Mark the owned teams as deleted; this enables them to be procesed
|
||||
;; Mark the owned teams as deleted; this enables them to be processed
|
||||
;; in the same transaction in the "team" table step.
|
||||
(db/exec-one! conn [sql:mark-owned-teams-deleted id max-age])
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
;; Copyright (c) UXBOX Labs SL
|
||||
|
||||
(ns app.tasks.telemetry
|
||||
"A task that is reponsible to collect anonymous statistical
|
||||
"A task that is responsible to collect anonymous statistical
|
||||
information about the current instance and send it to the telemetry
|
||||
server."
|
||||
(:require
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
:content html}]))}))
|
||||
|
||||
(s/def ::priority #{:high :low})
|
||||
(s/def ::to (s/or :sigle ::us/email
|
||||
(s/def ::to (s/or :single ::us/email
|
||||
:multi (s/coll-of ::us/email)))
|
||||
(s/def ::from ::us/email)
|
||||
(s/def ::reply-to ::us/email)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
;; --- Implementation
|
||||
|
||||
(defn- registered?
|
||||
"Check if concrete migration is already registred."
|
||||
"Check if concrete migration is already registered."
|
||||
[pool modname stepname]
|
||||
(let [sql "select * from migrations where module=? and step=?"
|
||||
rows (jdbc/execute! pool [sql modname stepname])]
|
||||
|
|
|
@ -470,7 +470,7 @@
|
|||
:type :summary
|
||||
:quantiles []
|
||||
:name "tasks_checkout_timing"
|
||||
:help "Latency measured between scheduld_at and execution time."
|
||||
:help "Latency measured between scheduled_at and execution time."
|
||||
:wrap (fn [rootf mobj]
|
||||
(let [mdata (meta rootf)
|
||||
origf (::original mdata rootf)]
|
||||
|
|
|
@ -174,12 +174,12 @@
|
|||
:type :image
|
||||
:metadata {:id (:id fmo1)}}}]})]
|
||||
|
||||
;; run the task inmediatelly
|
||||
;; run the task immediately
|
||||
(let [task (:app.tasks.file-media-gc/handler th/*system*)
|
||||
res (task {})]
|
||||
(t/is (= 0 (:processed res))))
|
||||
|
||||
;; make the file ellegible for GC waiting 300ms (configured
|
||||
;; make the file eligible for GC waiting 300ms (configured
|
||||
;; timeout for testing)
|
||||
(th/sleep 300)
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
|
||||
;; (th/print-result! out)
|
||||
|
||||
;; Check tha tresult is correct
|
||||
;; Check that result is correct
|
||||
(t/is (nil? (:error out)))
|
||||
(let [result (:result out)]
|
||||
|
||||
|
@ -127,7 +127,7 @@
|
|||
|
||||
;; (th/print-result! out)
|
||||
|
||||
;; Check tha tresult is correct
|
||||
;; Check that result is correct
|
||||
(t/is (nil? (:error out)))
|
||||
(let [result (:result out)]
|
||||
|
||||
|
@ -183,7 +183,7 @@
|
|||
:name "project 1 (copy)"}
|
||||
out (th/mutation! data)]
|
||||
|
||||
;; Check tha tresult is correct
|
||||
;; Check that result is correct
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
|
@ -254,7 +254,7 @@
|
|||
:name "project 1 (copy)"}
|
||||
out (th/mutation! data)]
|
||||
|
||||
;; Check tha tresult is correct
|
||||
;; Check that result is correct
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
(t/is (true? (sto/del-object storage object)))
|
||||
|
||||
;; retrieving the same object should be not nil because the
|
||||
;; deletion is not inmediate
|
||||
;; deletion is not immediate
|
||||
(t/is (some? (sto/get-object-data storage object)))
|
||||
(t/is (some? (sto/get-object-url storage object)))
|
||||
(t/is (some? (sto/get-object-path storage object)))
|
||||
|
@ -248,7 +248,7 @@
|
|||
(th/sleep 200)
|
||||
|
||||
;; storage_pending table should have the object
|
||||
;; registred independently of the aborted transaction.
|
||||
;; registered independently of the aborted transaction.
|
||||
(let [rows (db/exec! th/*pool* ["select * from storage_pending"])]
|
||||
(t/is (= 1 (count rows))))
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue