mirror of
https://github.com/penpot/penpot.git
synced 2026-08-01 19:06:18 +00:00
🐛 Fix deleted files are accesible
This commit is contained in:
parent
5717708b56
commit
2b7bd8fa5c
@ -379,9 +379,7 @@
|
|||||||
|
|
||||||
(defn is-row-deleted?
|
(defn is-row-deleted?
|
||||||
[{:keys [deleted-at]}]
|
[{:keys [deleted-at]}]
|
||||||
(and (ct/inst? deleted-at)
|
(some? deleted-at))
|
||||||
(< (inst-ms deleted-at)
|
|
||||||
(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
|
||||||
|
|||||||
@ -90,15 +90,16 @@
|
|||||||
FROM snapshots AS c
|
FROM snapshots AS c
|
||||||
WHERE c.id = ?
|
WHERE c.id = ?
|
||||||
AND CASE WHEN c.created_by = 'user'
|
AND CASE WHEN c.created_by = 'user'
|
||||||
THEN (c.deleted_at IS NULL)
|
THEN c.deleted_at IS NULL
|
||||||
WHEN c.created_by = 'system'
|
WHEN c.created_by = 'system'
|
||||||
THEN (c.deleted_at IS NULL OR c.deleted_at >= ?::timestamptz)
|
THEN c.deleted_at IS NULL OR c.deleted_at >= ?::timestamptz
|
||||||
END"))
|
END"))
|
||||||
|
|
||||||
(defn get-minimal-snapshot
|
(defn get-minimal-snapshot
|
||||||
[cfg snapshot-id]
|
[cfg snapshot-id]
|
||||||
(let [now (ct/now)]
|
(let [now (ct/now)]
|
||||||
(-> (db/get-with-sql cfg [sql:get-snapshot-without-data snapshot-id now])
|
(-> (db/get-with-sql cfg [sql:get-snapshot-without-data snapshot-id now]
|
||||||
|
{::db/remove-deleted false})
|
||||||
(decode-snapshot))))
|
(decode-snapshot))))
|
||||||
|
|
||||||
(def ^:private sql:get-snapshot
|
(def ^:private sql:get-snapshot
|
||||||
@ -115,7 +116,8 @@
|
|||||||
"Get snapshot with decoded data"
|
"Get snapshot with decoded data"
|
||||||
[cfg file-id snapshot-id]
|
[cfg file-id snapshot-id]
|
||||||
(let [now (ct/now)]
|
(let [now (ct/now)]
|
||||||
(->> (db/get-with-sql cfg [sql:get-snapshot file-id snapshot-id now])
|
(->> (db/get-with-sql cfg [sql:get-snapshot file-id snapshot-id now]
|
||||||
|
{::db/remove-deleted false})
|
||||||
(decode-snapshot)
|
(decode-snapshot)
|
||||||
(fdata/resolve-file-data cfg)
|
(fdata/resolve-file-data cfg)
|
||||||
(fdata/decode-file-data cfg))))
|
(fdata/decode-file-data cfg))))
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
[app.features.logical-deletion :as ldel]
|
[app.features.logical-deletion :as ldel]
|
||||||
[app.loggers.audit :as-alias audit]
|
[app.loggers.audit :as-alias audit]
|
||||||
[app.loggers.webhooks :as-alias webhooks]
|
[app.loggers.webhooks :as-alias webhooks]
|
||||||
|
[app.msgbus :as mbus]
|
||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.rpc.commands.projects :as projects]
|
[app.rpc.commands.projects :as projects]
|
||||||
[app.rpc.commands.teams :as teams]
|
[app.rpc.commands.teams :as teams]
|
||||||
@ -80,8 +81,10 @@
|
|||||||
fpr.is_admin,
|
fpr.is_admin,
|
||||||
fpr.can_edit
|
fpr.can_edit
|
||||||
from file_profile_rel as fpr
|
from file_profile_rel as fpr
|
||||||
|
inner join file as f on (f.id = fpr.file_id)
|
||||||
where fpr.file_id = ?
|
where fpr.file_id = ?
|
||||||
and fpr.profile_id = ?
|
and fpr.profile_id = ?
|
||||||
|
and f.deleted_at is null
|
||||||
union all
|
union all
|
||||||
select tpr.is_owner,
|
select tpr.is_owner,
|
||||||
tpr.is_admin,
|
tpr.is_admin,
|
||||||
@ -91,6 +94,7 @@
|
|||||||
inner join file as f on (p.id = f.project_id)
|
inner join file as f on (p.id = f.project_id)
|
||||||
where f.id = ?
|
where f.id = ?
|
||||||
and tpr.profile_id = ?
|
and tpr.profile_id = ?
|
||||||
|
and f.deleted_at is null
|
||||||
union all
|
union all
|
||||||
select ppr.is_owner,
|
select ppr.is_owner,
|
||||||
ppr.is_admin,
|
ppr.is_admin,
|
||||||
@ -98,7 +102,8 @@
|
|||||||
from project_profile_rel as ppr
|
from project_profile_rel as ppr
|
||||||
inner join file as f on (f.project_id = ppr.project_id)
|
inner join file as f on (f.project_id = ppr.project_id)
|
||||||
where f.id = ?
|
where f.id = ?
|
||||||
and ppr.profile_id = ?")
|
and ppr.profile_id = ?
|
||||||
|
and f.deleted_at is null")
|
||||||
|
|
||||||
(defn get-file-permissions
|
(defn get-file-permissions
|
||||||
[conn profile-id file-id]
|
[conn profile-id file-id]
|
||||||
@ -730,9 +735,9 @@
|
|||||||
|
|
||||||
(defn- get-file-info
|
(defn- get-file-info
|
||||||
[{:keys [::db/conn] :as cfg} {:keys [id] :as params}]
|
[{:keys [::db/conn] :as cfg} {:keys [id] :as params}]
|
||||||
(db/get* conn :file
|
(db/get conn :file
|
||||||
{:id id}
|
{:id id}
|
||||||
{::sql/columns [:id]}))
|
{::sql/columns [:id :deleted-at]}))
|
||||||
|
|
||||||
(sv/defmethod ::get-file-info
|
(sv/defmethod ::get-file-info
|
||||||
"Retrieve minimal file info by its ID."
|
"Retrieve minimal file info by its ID."
|
||||||
@ -944,7 +949,14 @@
|
|||||||
(let [team (teams/get-team conn
|
(let [team (teams/get-team conn
|
||||||
:profile-id profile-id
|
:profile-id profile-id
|
||||||
:file-id id)
|
:file-id id)
|
||||||
file (mark-file-deleted conn team id)]
|
file (mark-file-deleted conn team id)
|
||||||
|
msgbus (::mbus/msgbus cfg)]
|
||||||
|
|
||||||
|
(mbus/pub! msgbus
|
||||||
|
:topic id
|
||||||
|
:message {:type :file-deleted
|
||||||
|
:file-id id
|
||||||
|
:profile-id profile-id})
|
||||||
|
|
||||||
(rph/with-meta (rph/wrap)
|
(rph/with-meta (rph/wrap)
|
||||||
{::audit/props {:project-id (:project-id file)
|
{::audit/props {:project-id (:project-id file)
|
||||||
|
|||||||
@ -132,7 +132,6 @@
|
|||||||
;; this will run pending task triggered by deleting user snapshot
|
;; this will run pending task triggered by deleting user snapshot
|
||||||
(th/run-pending-tasks!)
|
(th/run-pending-tasks!)
|
||||||
|
|
||||||
;; this will
|
|
||||||
(let [res (th/run-task! :objects-gc {:deletion-threshold (cf/get-deletion-delay)})]
|
(let [res (th/run-task! :objects-gc {:deletion-threshold (cf/get-deletion-delay)})]
|
||||||
;; delete 2 snapshots and 2 file data entries
|
;; delete 2 snapshots and 2 file data entries
|
||||||
(t/is (= 4 (:processed res))))))))
|
(t/is (= 4 (:processed res))))))))
|
||||||
@ -179,7 +178,7 @@
|
|||||||
(t/is (nil? (:error out)))
|
(t/is (nil? (:error out)))
|
||||||
(t/is (true? (:result out)))
|
(t/is (true? (:result out)))
|
||||||
|
|
||||||
(let [snapshot (th/db-get :file-change {:id (:id snapshot)})]
|
(let [snapshot (th/db-get :file-change {:id (:id snapshot)} {::db/remove-deleted false})]
|
||||||
(t/is (= (:id profile-1) (:locked-by snapshot))))))
|
(t/is (= (:id profile-1) (:locked-by snapshot))))))
|
||||||
|
|
||||||
(t/testing "delete locked snapshot"
|
(t/testing "delete locked snapshot"
|
||||||
|
|||||||
@ -117,29 +117,8 @@
|
|||||||
(t/is (nil? (:error out)))
|
(t/is (nil? (:error out)))
|
||||||
(t/is (nil? (:result out)))))
|
(t/is (nil? (:result out)))))
|
||||||
|
|
||||||
|
|
||||||
(t/testing "query single file after delete"
|
(t/testing "query single file after delete"
|
||||||
(let [data {::th/type :get-file
|
|
||||||
::rpc/profile-id (:id prof)
|
|
||||||
:id file-id
|
|
||||||
:components-v2 true}
|
|
||||||
out (th/command! data)]
|
|
||||||
|
|
||||||
|
|
||||||
;; (th/print-result! out)
|
|
||||||
(t/is (nil? (:error out)))
|
|
||||||
|
|
||||||
(let [result (:result out)]
|
|
||||||
(t/is (some? (:deleted-at result)))
|
|
||||||
(t/is (= file-id (:id result)))
|
|
||||||
(t/is (= "new name" (:name result)))
|
|
||||||
(t/is (= 1 (count (get-in result [:data :pages]))))
|
|
||||||
(t/is (nil? (:users result))))))
|
|
||||||
|
|
||||||
(th/db-update! :file
|
|
||||||
{:deleted-at (ct/now)}
|
|
||||||
{:id file-id})
|
|
||||||
|
|
||||||
(t/testing "query single file after delete and wait"
|
|
||||||
(let [data {::th/type :get-file
|
(let [data {::th/type :get-file
|
||||||
::rpc/profile-id (:id prof)
|
::rpc/profile-id (:id prof)
|
||||||
:id file-id
|
:id file-id
|
||||||
@ -959,9 +938,11 @@
|
|||||||
:file-id (:id file)}
|
:file-id (:id file)}
|
||||||
out (th/command! data)]
|
out (th/command! data)]
|
||||||
;; (th/print-result! out)
|
;; (th/print-result! out)
|
||||||
(t/is (nil? (:error out)))
|
|
||||||
(let [result (:result out)]
|
(let [error (:error out)
|
||||||
(t/is (= 0 (count result)))))
|
error-data (ex-data error)]
|
||||||
|
(t/is (th/ex-info? error))
|
||||||
|
(t/is (= (:type error-data) :not-found))))
|
||||||
|
|
||||||
;; run permanent deletion (should be noop)
|
;; run permanent deletion (should be noop)
|
||||||
(let [result (th/run-task! :objects-gc {})]
|
(let [result (th/run-task! :objects-gc {})]
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
[app.main.data.workspace.layout :as dwly]
|
[app.main.data.workspace.layout :as dwly]
|
||||||
[app.main.data.workspace.libraries :as dwl]
|
[app.main.data.workspace.libraries :as dwl]
|
||||||
[app.main.data.workspace.texts :as dwt]
|
[app.main.data.workspace.texts :as dwt]
|
||||||
|
[app.main.router :as rt]
|
||||||
[app.util.globals :refer [global]]
|
[app.util.globals :refer [global]]
|
||||||
[app.util.mouse :as mse]
|
[app.util.mouse :as mse]
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
@ -38,6 +39,7 @@
|
|||||||
(declare handle-presence)
|
(declare handle-presence)
|
||||||
(declare handle-pointer-update)
|
(declare handle-pointer-update)
|
||||||
(declare handle-file-change)
|
(declare handle-file-change)
|
||||||
|
(declare handle-file-deleted)
|
||||||
(declare handle-file-restore)
|
(declare handle-file-restore)
|
||||||
(declare handle-library-change)
|
(declare handle-library-change)
|
||||||
(declare handle-pointer-send)
|
(declare handle-pointer-send)
|
||||||
@ -129,6 +131,7 @@
|
|||||||
:disconnect (handle-presence msg)
|
:disconnect (handle-presence msg)
|
||||||
:pointer-update (handle-pointer-update msg)
|
:pointer-update (handle-pointer-update msg)
|
||||||
:file-change (handle-file-change msg)
|
:file-change (handle-file-change msg)
|
||||||
|
:file-deleted (handle-file-deleted msg)
|
||||||
:file-restore (handle-file-restore msg)
|
:file-restore (handle-file-restore msg)
|
||||||
:library-change (handle-library-change msg)
|
:library-change (handle-library-change msg)
|
||||||
:notification (dc/handle-notification msg)
|
:notification (dc/handle-notification msg)
|
||||||
@ -266,6 +269,18 @@
|
|||||||
:redo-changes (vec changes)
|
:redo-changes (vec changes)
|
||||||
:undo-changes []})))))
|
:undo-changes []})))))
|
||||||
|
|
||||||
|
(defn handle-file-deleted
|
||||||
|
[{:keys [file-id] :as msg}]
|
||||||
|
(ptk/reify ::handle-file-deleted
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(let [curr-file-id (:current-file-id state)
|
||||||
|
team-id (:current-team-id state)]
|
||||||
|
;; If the deleted file is the currently open one
|
||||||
|
(when (= file-id curr-file-id)
|
||||||
|
(rx/of
|
||||||
|
(rt/nav :dashboard-recent {:team-id team-id})))))))
|
||||||
|
|
||||||
(def ^:private
|
(def ^:private
|
||||||
schema:handle-file-restore
|
schema:handle-file-restore
|
||||||
[:map {:title "handle-file-restore"}
|
[:map {:title "handle-file-restore"}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user