mirror of
https://github.com/penpot/penpot.git
synced 2025-03-11 07:11:32 -05:00
🐛 Fix errors duplicating objects with deleted relations
This commit is contained in:
parent
0a3b244f44
commit
47c58df2a4
3 changed files with 155 additions and 5 deletions
|
@ -84,10 +84,24 @@
|
||||||
(d/without-nils)
|
(d/without-nils)
|
||||||
(blob/encode))))))
|
(blob/encode))))))
|
||||||
|
|
||||||
|
(def sql:retrieve-used-libraries
|
||||||
|
"select flr.*
|
||||||
|
from file_library_rel as flr
|
||||||
|
inner join file as l on (flr.library_file_id = l.id)
|
||||||
|
where flr.file_id = ?
|
||||||
|
and l.deleted_at is null")
|
||||||
|
|
||||||
|
(def sql:retrieve-used-media-objects
|
||||||
|
"select fmo.*
|
||||||
|
from file_media_object as fmo
|
||||||
|
inner join storage_object as o on (fmo.media_id = o.id)
|
||||||
|
where fmo.file_id = ?
|
||||||
|
and o.deleted_at is null")
|
||||||
|
|
||||||
(defn duplicate-file
|
(defn duplicate-file
|
||||||
[conn {:keys [profile-id file index project-id name]} {:keys [reset-shared-flag] :as opts}]
|
[conn {:keys [profile-id file index project-id name]} {:keys [reset-shared-flag] :as opts}]
|
||||||
(let [flibs (db/query conn :file-library-rel {:file-id (:id file)})
|
(let [flibs (db/exec! conn [sql:retrieve-used-libraries (:id file)])
|
||||||
fmeds (db/query conn :file-media-object {:file-id (:id file)})
|
fmeds (db/exec! conn [sql:retrieve-used-media-objects (:id file)])
|
||||||
|
|
||||||
;; memo uniform creation/modification date
|
;; memo uniform creation/modification date
|
||||||
now (dt/now)
|
now (dt/now)
|
||||||
|
@ -185,7 +199,8 @@
|
||||||
(defn duplicate-project
|
(defn duplicate-project
|
||||||
[conn {:keys [profile-id project name] :as params}]
|
[conn {:keys [profile-id project name] :as params}]
|
||||||
(let [files (db/query conn :file
|
(let [files (db/query conn :file
|
||||||
{:project-id (:id project)}
|
{:project-id (:id project)
|
||||||
|
:deleted-at nil}
|
||||||
{:columns [:id]})
|
{:columns [:id]})
|
||||||
|
|
||||||
project (cond-> project
|
project (cond-> project
|
||||||
|
|
|
@ -145,6 +145,10 @@
|
||||||
:name (str "file" i)}
|
:name (str "file" i)}
|
||||||
params))))
|
params))))
|
||||||
|
|
||||||
|
(defn mark-file-deleted*
|
||||||
|
([params] (mark-file-deleted* *pool* params))
|
||||||
|
([conn {:keys [id] :as params}]
|
||||||
|
(#'files/mark-file-deleted conn {:id id})))
|
||||||
|
|
||||||
(defn create-team*
|
(defn create-team*
|
||||||
([i params] (create-team* *pool* i params))
|
([i params] (create-team* *pool* i params))
|
||||||
|
@ -160,7 +164,6 @@
|
||||||
:role :owner})
|
:role :owner})
|
||||||
team)))
|
team)))
|
||||||
|
|
||||||
|
|
||||||
(defn create-file-media-object*
|
(defn create-file-media-object*
|
||||||
([params] (create-file-media-object* *pool* params))
|
([params] (create-file-media-object* *pool* params))
|
||||||
([conn {:keys [name width height mtype file-id is-local media-id]
|
([conn {:keys [name width height mtype file-id is-local media-id]
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
(let [[item :as rows] (db/query th/*pool* :file-media-object {:file-id (:id result)})]
|
(let [[item :as rows] (db/query th/*pool* :file-media-object {:file-id (:id result)})]
|
||||||
(t/is (= 1 (count rows)))
|
(t/is (= 1 (count rows)))
|
||||||
|
|
||||||
;; Checj that bot items have different ids
|
;; Check that both items have different ids
|
||||||
(t/is (not= (:id item) (:id mobj)))
|
(t/is (not= (:id item) (:id mobj)))
|
||||||
|
|
||||||
;; check that both file-media-objects points to the same storage object.
|
;; check that both file-media-objects points to the same storage object.
|
||||||
|
@ -92,6 +92,67 @@
|
||||||
|
|
||||||
))))
|
))))
|
||||||
|
|
||||||
|
(t/deftest duplicate-file-with-deleted-rels
|
||||||
|
(let [storage (:app.storage/storage th/*system*)
|
||||||
|
sobject (sto/put-object storage {:content (sto/content "content")
|
||||||
|
:content-type "text/plain"
|
||||||
|
:other "data"})
|
||||||
|
profile (th/create-profile* 1 {:is-active true})
|
||||||
|
project (th/create-project* 1 {:team-id (:default-team-id profile)
|
||||||
|
:profile-id (:id profile)})
|
||||||
|
file1 (th/create-file* 1 {:profile-id (:id profile)
|
||||||
|
:project-id (:id project)})
|
||||||
|
file2 (th/create-file* 2 {:profile-id (:id profile)
|
||||||
|
:project-id (:id project)
|
||||||
|
:is-shared true})
|
||||||
|
|
||||||
|
libl (th/link-file-to-library* {:file-id (:id file1)
|
||||||
|
:library-id (:id file2)})
|
||||||
|
|
||||||
|
mobj (th/create-file-media-object* {:file-id (:id file1)
|
||||||
|
:is-local false
|
||||||
|
:media-id (:id sobject)})
|
||||||
|
|
||||||
|
_ (th/mark-file-deleted* {:id (:id file2)})
|
||||||
|
_ (sto/del-object storage (:id sobject))]
|
||||||
|
|
||||||
|
(th/update-file*
|
||||||
|
{:file-id (:id file1)
|
||||||
|
:profile-id (:id profile)
|
||||||
|
:changes [{:type :add-media
|
||||||
|
:object (select-keys mobj [:id :width :height :mtype :name])}]})
|
||||||
|
|
||||||
|
(let [data {::th/type :duplicate-file
|
||||||
|
:profile-id (:id profile)
|
||||||
|
:file-id (:id file1)
|
||||||
|
:name "file 1 (copy)"}
|
||||||
|
out (th/mutation! data)]
|
||||||
|
|
||||||
|
;; (th/print-result! out)
|
||||||
|
|
||||||
|
;; Check tha tresult is correct
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(let [result (:result out)]
|
||||||
|
|
||||||
|
;; Check that the returned result is a file but has different id
|
||||||
|
;; and different name.
|
||||||
|
(t/is (= "file 1 (copy)" (:name result)))
|
||||||
|
(t/is (not= (:id file1) (:id result)))
|
||||||
|
|
||||||
|
;; Check that the deleted library is not duplicated
|
||||||
|
(let [[item :as rows] (db/query th/*pool* :file-library-rel {:file-id (:id result)})]
|
||||||
|
(t/is (= 0 (count rows))))
|
||||||
|
|
||||||
|
;; Check that the new file has no media objects
|
||||||
|
(let [[item :as rows] (db/query th/*pool* :file-media-object {:file-id (:id result)})]
|
||||||
|
(t/is (= 0 (count rows))))
|
||||||
|
|
||||||
|
;; Check the total number of files
|
||||||
|
(let [rows (db/query th/*pool* :file {:project-id (:id project)})]
|
||||||
|
(t/is (= 3 (count rows))))
|
||||||
|
|
||||||
|
))))
|
||||||
|
|
||||||
(t/deftest duplicate-project
|
(t/deftest duplicate-project
|
||||||
(let [storage (:app.storage/storage th/*system*)
|
(let [storage (:app.storage/storage th/*system*)
|
||||||
sobject (sto/put-object storage {:content (sto/content "content")
|
sobject (sto/put-object storage {:content (sto/content "content")
|
||||||
|
@ -162,6 +223,77 @@
|
||||||
|
|
||||||
)))))
|
)))))
|
||||||
|
|
||||||
|
(t/deftest duplicate-project-with-deleted-files
|
||||||
|
(let [storage (:app.storage/storage th/*system*)
|
||||||
|
sobject (sto/put-object storage {:content (sto/content "content")
|
||||||
|
:content-type "text/plain"
|
||||||
|
:other "data"})
|
||||||
|
profile (th/create-profile* 1 {:is-active true})
|
||||||
|
project (th/create-project* 1 {:team-id (:default-team-id profile)
|
||||||
|
:profile-id (:id profile)})
|
||||||
|
file1 (th/create-file* 1 {:profile-id (:id profile)
|
||||||
|
:project-id (:id project)})
|
||||||
|
file2 (th/create-file* 2 {:profile-id (:id profile)
|
||||||
|
:project-id (:id project)
|
||||||
|
:is-shared true})
|
||||||
|
|
||||||
|
libl (th/link-file-to-library* {:file-id (:id file1)
|
||||||
|
:library-id (:id file2)})
|
||||||
|
mobj (th/create-file-media-object* {:file-id (:id file1)
|
||||||
|
:is-local false
|
||||||
|
:media-id (:id sobject)})]
|
||||||
|
|
||||||
|
(th/update-file*
|
||||||
|
{:file-id (:id file1)
|
||||||
|
:profile-id (:id profile)
|
||||||
|
:changes [{:type :add-media
|
||||||
|
:object (select-keys mobj [:id :width :height :mtype :name])}]})
|
||||||
|
|
||||||
|
(th/mark-file-deleted* {:id (:id file1)})
|
||||||
|
|
||||||
|
(let [data {::th/type :duplicate-project
|
||||||
|
:profile-id (:id profile)
|
||||||
|
:project-id (:id project)
|
||||||
|
:name "project 1 (copy)"}
|
||||||
|
out (th/mutation! data)]
|
||||||
|
|
||||||
|
;; Check tha tresult is correct
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
|
||||||
|
(let [result (:result out)]
|
||||||
|
;; Check that they are the same project but different id and name
|
||||||
|
(t/is (= "project 1 (copy)" (:name result)))
|
||||||
|
(t/is (not= (:id project) (:id result)))
|
||||||
|
|
||||||
|
;; Check the total number of projects (previously is 2, now is 3)
|
||||||
|
(let [rows (db/query th/*pool* :project {:team-id (:default-team-id profile)})]
|
||||||
|
(t/is (= 3 (count rows))))
|
||||||
|
|
||||||
|
;; Check that the new project has only the second file
|
||||||
|
(let [p1-files (db/query th/*pool* :file
|
||||||
|
{:project-id (:id project)}
|
||||||
|
{:order-by [:name]})
|
||||||
|
p2-files (db/query th/*pool* :file
|
||||||
|
{:project-id (:id result)}
|
||||||
|
{:order-by [:name]})]
|
||||||
|
(t/is (= (count (rest p1-files))
|
||||||
|
(count p2-files)))
|
||||||
|
|
||||||
|
;; check that the both files are equivalent
|
||||||
|
(doseq [[fa fb] (map vector (rest p1-files) p2-files)]
|
||||||
|
(t/is (not= (:id fa) (:id fb)))
|
||||||
|
(t/is (= (:name fa) (:name fb)))
|
||||||
|
|
||||||
|
(when (= (:id fa) (:id file1))
|
||||||
|
(t/is (false? (b/equals? (:data fa)
|
||||||
|
(:data fb)))))
|
||||||
|
|
||||||
|
(when (= (:id fa) (:id file2))
|
||||||
|
(t/is (false? (b/equals? (:data fa)
|
||||||
|
(:data fb))))))
|
||||||
|
|
||||||
|
)))))
|
||||||
|
|
||||||
(t/deftest move-file-on-same-team
|
(t/deftest move-file-on-same-team
|
||||||
(let [profile (th/create-profile* 1 {:is-active true})
|
(let [profile (th/create-profile* 1 {:is-active true})
|
||||||
team (th/create-team* 1 {:profile-id (:id profile)})
|
team (th/create-team* 1 {:profile-id (:id profile)})
|
||||||
|
|
Loading…
Add table
Reference in a new issue