diff --git a/backend/src/app/rpc/mutations/management.clj b/backend/src/app/rpc/mutations/management.clj index d742b015e..ee885d0aa 100644 --- a/backend/src/app/rpc/mutations/management.clj +++ b/backend/src/app/rpc/mutations/management.clj @@ -84,10 +84,24 @@ (d/without-nils) (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 [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)}) - fmeds (db/query conn :file-media-object {:file-id (:id file)}) + (let [flibs (db/exec! conn [sql:retrieve-used-libraries (:id file)]) + fmeds (db/exec! conn [sql:retrieve-used-media-objects (:id file)]) ;; memo uniform creation/modification date now (dt/now) @@ -185,7 +199,8 @@ (defn duplicate-project [conn {:keys [profile-id project name] :as params}] (let [files (db/query conn :file - {:project-id (:id project)} + {:project-id (:id project) + :deleted-at nil} {:columns [:id]}) project (cond-> project diff --git a/backend/tests/app/tests/helpers.clj b/backend/tests/app/tests/helpers.clj index d9d6b50c4..2c4584573 100644 --- a/backend/tests/app/tests/helpers.clj +++ b/backend/tests/app/tests/helpers.clj @@ -145,6 +145,10 @@ :name (str "file" i)} 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* ([i params] (create-team* *pool* i params)) @@ -160,7 +164,6 @@ :role :owner}) team))) - (defn create-file-media-object* ([params] (create-file-media-object* *pool* params)) ([conn {:keys [name width height mtype file-id is-local media-id] diff --git a/backend/tests/app/tests/test_services_management.clj b/backend/tests/app/tests/test_services_management.clj index 7afa00d16..fd0d58233 100644 --- a/backend/tests/app/tests/test_services_management.clj +++ b/backend/tests/app/tests/test_services_management.clj @@ -73,7 +73,7 @@ (let [[item :as rows] (db/query th/*pool* :file-media-object {:file-id (:id result)})] (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))) ;; 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 (let [storage (:app.storage/storage th/*system*) 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 (let [profile (th/create-profile* 1 {:is-active true}) team (th/create-team* 1 {:profile-id (:id profile)})