mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
🐛 Fix deleted files are accesible
Some checks failed
_STAGING / build-bundle (push) Has been cancelled
_STAGING / build-docker (push) Has been cancelled
_DEVELOP / build-bundle (push) Has been cancelled
_DEVELOP / build-docker (push) Has been cancelled
Commit Message Check / Check Commit Message (push) Has been cancelled
Some checks failed
_STAGING / build-bundle (push) Has been cancelled
_STAGING / build-docker (push) Has been cancelled
_DEVELOP / build-bundle (push) Has been cancelled
_DEVELOP / build-docker (push) Has been cancelled
Commit Message Check / Check Commit Message (push) Has been cancelled
This commit is contained in:
committed by
Andrey Antukh
parent
5717708b56
commit
2b7bd8fa5c
@@ -379,9 +379,7 @@
|
||||
|
||||
(defn is-row-deleted?
|
||||
[{:keys [deleted-at]}]
|
||||
(and (ct/inst? deleted-at)
|
||||
(< (inst-ms deleted-at)
|
||||
(inst-ms (ct/now)))))
|
||||
(some? deleted-at))
|
||||
|
||||
(defn get*
|
||||
"Retrieve a single row from database that matches a simple filters. Do
|
||||
|
||||
@@ -90,15 +90,16 @@
|
||||
FROM snapshots AS c
|
||||
WHERE c.id = ?
|
||||
AND CASE WHEN c.created_by = 'user'
|
||||
THEN (c.deleted_at IS NULL)
|
||||
THEN c.deleted_at IS NULL
|
||||
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"))
|
||||
|
||||
(defn get-minimal-snapshot
|
||||
[cfg snapshot-id]
|
||||
(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))))
|
||||
|
||||
(def ^:private sql:get-snapshot
|
||||
@@ -115,7 +116,8 @@
|
||||
"Get snapshot with decoded data"
|
||||
[cfg file-id snapshot-id]
|
||||
(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)
|
||||
(fdata/resolve-file-data cfg)
|
||||
(fdata/decode-file-data cfg))))
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
[app.features.logical-deletion :as ldel]
|
||||
[app.loggers.audit :as-alias audit]
|
||||
[app.loggers.webhooks :as-alias webhooks]
|
||||
[app.msgbus :as mbus]
|
||||
[app.rpc :as-alias rpc]
|
||||
[app.rpc.commands.projects :as projects]
|
||||
[app.rpc.commands.teams :as teams]
|
||||
@@ -80,8 +81,10 @@
|
||||
fpr.is_admin,
|
||||
fpr.can_edit
|
||||
from file_profile_rel as fpr
|
||||
inner join file as f on (f.id = fpr.file_id)
|
||||
where fpr.file_id = ?
|
||||
and fpr.profile_id = ?
|
||||
and f.deleted_at is null
|
||||
union all
|
||||
select tpr.is_owner,
|
||||
tpr.is_admin,
|
||||
@@ -91,6 +94,7 @@
|
||||
inner join file as f on (p.id = f.project_id)
|
||||
where f.id = ?
|
||||
and tpr.profile_id = ?
|
||||
and f.deleted_at is null
|
||||
union all
|
||||
select ppr.is_owner,
|
||||
ppr.is_admin,
|
||||
@@ -98,7 +102,8 @@
|
||||
from project_profile_rel as ppr
|
||||
inner join file as f on (f.project_id = ppr.project_id)
|
||||
where f.id = ?
|
||||
and ppr.profile_id = ?")
|
||||
and ppr.profile_id = ?
|
||||
and f.deleted_at is null")
|
||||
|
||||
(defn get-file-permissions
|
||||
[conn profile-id file-id]
|
||||
@@ -730,9 +735,9 @@
|
||||
|
||||
(defn- get-file-info
|
||||
[{:keys [::db/conn] :as cfg} {:keys [id] :as params}]
|
||||
(db/get* conn :file
|
||||
{:id id}
|
||||
{::sql/columns [:id]}))
|
||||
(db/get conn :file
|
||||
{:id id}
|
||||
{::sql/columns [:id :deleted-at]}))
|
||||
|
||||
(sv/defmethod ::get-file-info
|
||||
"Retrieve minimal file info by its ID."
|
||||
@@ -944,7 +949,14 @@
|
||||
(let [team (teams/get-team conn
|
||||
:profile-id profile-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)
|
||||
{::audit/props {:project-id (:project-id file)
|
||||
|
||||
@@ -132,7 +132,6 @@
|
||||
;; this will run pending task triggered by deleting user snapshot
|
||||
(th/run-pending-tasks!)
|
||||
|
||||
;; this will
|
||||
(let [res (th/run-task! :objects-gc {:deletion-threshold (cf/get-deletion-delay)})]
|
||||
;; delete 2 snapshots and 2 file data entries
|
||||
(t/is (= 4 (:processed res))))))))
|
||||
@@ -179,7 +178,7 @@
|
||||
(t/is (nil? (:error 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/testing "delete locked snapshot"
|
||||
|
||||
@@ -117,29 +117,8 @@
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (nil? (:result out)))))
|
||||
|
||||
|
||||
(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
|
||||
::rpc/profile-id (:id prof)
|
||||
:id file-id
|
||||
@@ -959,9 +938,11 @@
|
||||
:file-id (:id file)}
|
||||
out (th/command! data)]
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
(let [result (:result out)]
|
||||
(t/is (= 0 (count result)))))
|
||||
|
||||
(let [error (:error out)
|
||||
error-data (ex-data error)]
|
||||
(t/is (th/ex-info? error))
|
||||
(t/is (= (:type error-data) :not-found))))
|
||||
|
||||
;; run permanent deletion (should be noop)
|
||||
(let [result (th/run-task! :objects-gc {})]
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
[app.main.data.workspace.layout :as dwly]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.router :as rt]
|
||||
[app.util.globals :refer [global]]
|
||||
[app.util.mouse :as mse]
|
||||
[app.util.object :as obj]
|
||||
@@ -38,6 +39,7 @@
|
||||
(declare handle-presence)
|
||||
(declare handle-pointer-update)
|
||||
(declare handle-file-change)
|
||||
(declare handle-file-deleted)
|
||||
(declare handle-file-restore)
|
||||
(declare handle-library-change)
|
||||
(declare handle-pointer-send)
|
||||
@@ -129,6 +131,7 @@
|
||||
:disconnect (handle-presence msg)
|
||||
:pointer-update (handle-pointer-update msg)
|
||||
:file-change (handle-file-change msg)
|
||||
:file-deleted (handle-file-deleted msg)
|
||||
:file-restore (handle-file-restore msg)
|
||||
:library-change (handle-library-change msg)
|
||||
:notification (dc/handle-notification msg)
|
||||
@@ -266,6 +269,18 @@
|
||||
:redo-changes (vec 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
|
||||
schema:handle-file-restore
|
||||
[:map {:title "handle-file-restore"}
|
||||
|
||||
Reference in New Issue
Block a user