From ed701fd9c58b855feba707f390e69ee5374b815c Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 3 Aug 2022 11:37:29 +0200 Subject: [PATCH] :recycle: Move management mutations to commands --- backend/src/app/rpc.clj | 1 + backend/src/app/rpc/commands/management.clj | 352 ++++++++++++++++++ backend/src/app/rpc/mutations/management.clj | 321 ++-------------- backend/src/app/setup/initial_data.clj | 106 ------ backend/test/app/services_management_test.clj | 2 + frontend/src/app/main/data/dashboard.cljs | 11 +- 6 files changed, 381 insertions(+), 412 deletions(-) create mode 100644 backend/src/app/rpc/commands/management.clj delete mode 100644 backend/src/app/setup/initial_data.clj diff --git a/backend/src/app/rpc.clj b/backend/src/app/rpc.clj index 477b0a633..7c59f964f 100644 --- a/backend/src/app/rpc.clj +++ b/backend/src/app/rpc.clj @@ -242,6 +242,7 @@ (let [cfg (assoc cfg ::type "command" ::metrics-id :rpc-command-timing)] (->> (sv/scan-ns 'app.rpc.commands.binfile 'app.rpc.commands.comments + 'app.rpc.commands.management 'app.rpc.commands.auth 'app.rpc.commands.ldap 'app.rpc.commands.demo) diff --git a/backend/src/app/rpc/commands/management.clj b/backend/src/app/rpc/commands/management.clj new file mode 100644 index 000000000..a78bfe310 --- /dev/null +++ b/backend/src/app/rpc/commands/management.clj @@ -0,0 +1,352 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) UXBOX Labs SL + +(ns app.rpc.commands.management + "A collection of RPC methods for manage the files, projects and team organization." + (:require + [app.common.data :as d] + [app.common.exceptions :as ex] + [app.common.pages.migrations :as pmg] + [app.common.spec :as us] + [app.common.uuid :as uuid] + [app.db :as db] + [app.rpc.doc :as-alias doc] + [app.rpc.mutations.projects :refer [create-project-role create-project]] + [app.rpc.queries.projects :as proj] + [app.rpc.queries.teams :as teams] + [app.util.blob :as blob] + [app.util.services :as sv] + [app.util.time :as dt] + [clojure.spec.alpha :as s] + [clojure.walk :as walk])) + +;; --- COMMAND: Duplicate File + +(declare duplicate-file) + +(s/def ::id ::us/uuid) +(s/def ::profile-id ::us/uuid) +(s/def ::project-id ::us/uuid) +(s/def ::file-id ::us/uuid) +(s/def ::team-id ::us/uuid) +(s/def ::name ::us/string) + +(s/def ::duplicate-file + (s/keys :req-un [::profile-id ::file-id] + :opt-un [::name])) + +(sv/defmethod ::duplicate-file + "Duplicate a single file in the same team." + {::doc/added "1.16"} + [{:keys [pool] :as cfg} params] + (db/with-atomic [conn pool] + (duplicate-file conn params))) + +(defn- remap-id + [item index key] + (cond-> item + (contains? item key) + (assoc key (get index (get item key) (get item key))))) + +(defn- process-file + [file index] + (letfn [(process-form [form] + (cond-> form + ;; Relink library items + (and (map? form) + (uuid? (:component-file form))) + (update :component-file #(get index % %)) + + (and (map? form) + (uuid? (:fill-color-ref-file form))) + (update :fill-color-ref-file #(get index % %)) + + (and (map? form) + (uuid? (:stroke-color-ref-file form))) + (update :stroke-color-ref-file #(get index % %)) + + (and (map? form) + (uuid? (:typography-ref-file form))) + (update :typography-ref-file #(get index % %)) + + ;; Relink Image Shapes + (and (map? form) + (map? (:metadata form)) + (= :image (:type form))) + (update-in [:metadata :id] #(get index % %)))) + + ;; 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] + (walk/postwalk process-form data)) + + ;; A function responsible of process the :media attr of file + ;; data and remap the old ids with the new ones. + (relink-media [media] + (reduce-kv (fn [res k v] + (let [id (get index k)] + (if (uuid? id) + (-> res + (assoc id (assoc v :id id)) + (dissoc k)) + res))) + media + media))] + + (update file :data + (fn [data] + (-> data + (blob/decode) + (assoc :id (:id file)) + (pmg/migrate-data) + (update :pages-index relink-shapes) + (update :components relink-shapes) + (update :media relink-media) + (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 so on (fmo.media_id = so.id) + where fmo.file_id = ? + and so.deleted_at is null") + +(defn duplicate-file* + [conn {:keys [profile-id file index project-id name flibs fmeds]} {:keys [reset-shared-flag] :as opts}] + (let [flibs (or flibs (db/exec! conn [sql:retrieve-used-libraries (:id file)])) + fmeds (or fmeds (db/exec! conn [sql:retrieve-used-media-objects (:id file)])) + + ;; memo uniform creation/modification date + now (dt/now) + ignore (dt/plus now (dt/duration {:seconds 5})) + + ;; add to the index all file media objects. + index (reduce #(assoc %1 (:id %2) (uuid/next)) index fmeds) + + flibs-xf (comp + (map #(remap-id % index :file-id)) + (map #(remap-id % index :library-file-id)) + (map #(assoc % :synced-at now)) + (map #(assoc % :created-at now))) + + ;; remap all file-library-rel row + flibs (sequence flibs-xf flibs) + + fmeds-xf (comp + (map #(assoc % :id (get index (:id %)))) + (map #(assoc % :created-at now)) + (map #(remap-id % index :file-id))) + + ;; remap all file-media-object rows + fmeds (sequence fmeds-xf fmeds) + + file (cond-> file + (some? project-id) + (assoc :project-id project-id) + + (some? name) + (assoc :name name) + + (true? reset-shared-flag) + (assoc :is-shared false)) + + file (-> file + (assoc :created-at now) + (assoc :modified-at now) + (assoc :ignore-sync-until ignore) + (update :id #(get index %)) + (process-file index))] + + (db/insert! conn :file file) + (db/insert! conn :file-profile-rel + {:file-id (:id file) + :profile-id profile-id + :is-owner true + :is-admin true + :can-edit true}) + + (doseq [params flibs] + (db/insert! conn :file-library-rel params)) + + (doseq [params fmeds] + (db/insert! conn :file-media-object params)) + + file)) + +(defn duplicate-file + [conn {:keys [profile-id file-id] :as params}] + (let [file (db/get-by-id conn :file file-id) + index {file-id (uuid/next)} + params (assoc params :index index :file file)] + (proj/check-edition-permissions! conn profile-id (:project-id file)) + (db/exec-one! conn ["SET CONSTRAINTS ALL DEFERRED"]) + (-> (duplicate-file* conn params {:reset-shared-flag true}) + (update :data blob/decode)))) + +;; --- COMMAND: Duplicate Project + +(declare duplicate-project) + +(s/def ::duplicate-project + (s/keys :req-un [::profile-id ::project-id] + :opt-un [::name])) + +(sv/defmethod ::duplicate-project + [{:keys [pool] :as cfg} {:keys [profile-id project-id] :as params}] + (db/with-atomic [conn pool] + (duplicate-project conn params))) + +(defn duplicate-project + [conn {:keys [profile-id project-id name] :as params}] + + ;; Defer all constraints + (db/exec-one! conn ["SET CONSTRAINTS ALL DEFERRED"]) + + (let [project (db/get-by-id conn :project project-id) + + files (db/query conn :file + {:project-id (:id project) + :deleted-at nil} + {:columns [:id]}) + + project (cond-> project + (string? name) + (assoc :name name) + + :always + (assoc :id (uuid/next)))] + + ;; Check if the source team-id allow creating new project for current user + (teams/check-edition-permissions! conn profile-id (:team-id project)) + + ;; create the duplicated project and assign the current profile as + ;; a project owner + (create-project conn project) + (create-project-role conn {:project-id (:id project) + :profile-id profile-id + :role :owner}) + + ;; duplicate all files + (let [index (reduce #(assoc %1 (:id %2) (uuid/next)) {} files) + params (-> params + (dissoc :name) + (assoc :project-id (:id project)) + (assoc :index index))] + (doseq [{:keys [id]} files] + (let [file (db/get-by-id conn :file id) + params (assoc params :file file) + opts {:reset-shared-flag false}] + (duplicate-file* conn params opts)))) + + ;; return the created project + project)) + +;; --- COMMAND: Move file + +(def sql:retrieve-files + "select id, project_id from file where id = ANY(?)") + +(def sql:move-files + "update file set project_id = ? where id = ANY(?)") + +(def sql:delete-broken-relations + "with broken as ( + (select * from file_library_rel as flr + inner join file as f on (flr.file_id = f.id) + inner join project as p on (f.project_id = p.id) + inner join file as lf on (flr.library_file_id = lf.id) + inner join project as lp on (lf.project_id = lp.id) + where p.id = ANY(?) + and lp.team_id != p.team_id) + ) + delete from file_library_rel as rel + using broken as br + where rel.file_id = br.file_id + and rel.library_file_id = br.library_file_id") + +(defn move-files + [conn {:keys [profile-id ids project-id] :as params}] + + (let [fids (db/create-array conn "uuid" ids) + files (db/exec! conn [sql:retrieve-files fids]) + source (into #{} (map :project-id) files) + pids (->> (conj source project-id) + (db/create-array conn "uuid"))] + + ;; Check if we have permissions on the destination project + (proj/check-edition-permissions! conn profile-id project-id) + + ;; Check if we have permissions on all source projects + (doseq [project-id source] + (proj/check-edition-permissions! conn profile-id project-id)) + + (when (contains? source project-id) + (ex/raise :type :validation + :code :cant-move-to-same-project + :hint "Unable to move a file to the same project")) + + ;; move all files to the project + (db/exec-one! conn [sql:move-files project-id fids]) + + ;; delete possible broken relations on moved files + (db/exec-one! conn [sql:delete-broken-relations pids]) + + nil)) + +(s/def ::ids (s/every ::us/uuid :kind set?)) +(s/def ::move-files + (s/keys :req-un [::profile-id ::ids ::project-id])) + +(sv/defmethod ::move-files + [{:keys [pool] :as cfg} params] + (db/with-atomic [conn pool] + (move-files conn params))) + + +;; --- COMMAND: Move project + +(defn move-project + [conn {:keys [profile-id team-id project-id] :as params}] + (let [project (db/get-by-id conn :project project-id {:columns [:id :team-id]}) + pids (->> (db/query conn :project {:team-id (:team-id project)} {:columns [:id]}) + (map :id) + (db/create-array conn "uuid"))] + + (teams/check-edition-permissions! conn profile-id (:team-id project)) + (teams/check-edition-permissions! conn profile-id team-id) + + (when (= team-id (:team-id project)) + (ex/raise :type :validation + :code :cant-move-to-same-team + :hint "Unable to move a project to same team")) + + ;; move project to the destination team + (db/update! conn :project + {:team-id team-id} + {:id project-id}) + + ;; delete possible broken relations on moved files + (db/exec-one! conn [sql:delete-broken-relations pids]) + + nil)) + + +(s/def ::move-project + (s/keys :req-un [::profile-id ::team-id ::project-id])) + +(sv/defmethod ::move-project + [{:keys [pool] :as cfg} params] + (db/with-atomic [conn pool] + (move-project conn params))) diff --git a/backend/src/app/rpc/mutations/management.clj b/backend/src/app/rpc/mutations/management.clj index 322fbdacd..c37d3a645 100644 --- a/backend/src/app/rpc/mutations/management.clj +++ b/backend/src/app/rpc/mutations/management.clj @@ -7,329 +7,52 @@ (ns app.rpc.mutations.management "Move & Duplicate RPC methods for files and projects." (:require - [app.common.data :as d] - [app.common.exceptions :as ex] - [app.common.pages.migrations :as pmg] - [app.common.spec :as us] - [app.common.uuid :as uuid] [app.db :as db] - [app.rpc.mutations.projects :refer [create-project-role create-project]] - [app.rpc.queries.projects :as proj] - [app.rpc.queries.teams :as teams] - [app.util.blob :as blob] + [app.rpc.commands.management :as cmd.mgm] + [app.rpc.doc :as-alias doc] [app.util.services :as sv] - [app.util.time :as dt] - [clojure.spec.alpha :as s] - [clojure.walk :as walk])) - -(s/def ::id ::us/uuid) -(s/def ::profile-id ::us/uuid) -(s/def ::project-id ::us/uuid) -(s/def ::file-id ::us/uuid) -(s/def ::team-id ::us/uuid) -(s/def ::name ::us/string) - -(defn- remap-id - [item index key] - (cond-> item - (contains? item key) - (assoc key (get index (get item key) (get item key))))) - -(defn- process-file - [file index] - (letfn [(process-form [form] - (cond-> form - ;; Relink library items - (and (map? form) - (uuid? (:component-file form))) - (update :component-file #(get index % %)) - - (and (map? form) - (uuid? (:fill-color-ref-file form))) - (update :fill-color-ref-file #(get index % %)) - - (and (map? form) - (uuid? (:stroke-color-ref-file form))) - (update :stroke-color-ref-file #(get index % %)) - - (and (map? form) - (uuid? (:typography-ref-file form))) - (update :typography-ref-file #(get index % %)) - - ;; Relink Image Shapes - (and (map? form) - (map? (:metadata form)) - (= :image (:type form))) - (update-in [:metadata :id] #(get index % %)))) - - ;; 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] - (walk/postwalk process-form data)) - - ;; A function responsible of process the :media attr of file - ;; data and remap the old ids with the new ones. - (relink-media [media] - (reduce-kv (fn [res k v] - (let [id (get index k)] - (if (uuid? id) - (-> res - (assoc id (assoc v :id id)) - (dissoc k)) - res))) - media - media))] - - (update file :data - (fn [data] - (-> data - (blob/decode) - (assoc :id (:id file)) - (pmg/migrate-data) - (update :pages-index relink-shapes) - (update :components relink-shapes) - (update :media relink-media) - (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 so on (fmo.media_id = so.id) - where fmo.file_id = ? - and so.deleted_at is null") - -(defn duplicate-file - [conn {:keys [profile-id file index project-id name flibs fmeds]} {:keys [reset-shared-flag] :as opts}] - (let [flibs (or flibs (db/exec! conn [sql:retrieve-used-libraries (:id file)])) - fmeds (or fmeds (db/exec! conn [sql:retrieve-used-media-objects (:id file)])) - - ;; memo uniform creation/modification date - now (dt/now) - ignore (dt/plus now (dt/duration {:seconds 5})) - - ;; add to the index all file media objects. - index (reduce #(assoc %1 (:id %2) (uuid/next)) index fmeds) - - flibs-xf (comp - (map #(remap-id % index :file-id)) - (map #(remap-id % index :library-file-id)) - (map #(assoc % :synced-at now)) - (map #(assoc % :created-at now))) - - ;; remap all file-library-rel row - flibs (sequence flibs-xf flibs) - - fmeds-xf (comp - (map #(assoc % :id (get index (:id %)))) - (map #(assoc % :created-at now)) - (map #(remap-id % index :file-id))) - - ;; remap all file-media-object rows - fmeds (sequence fmeds-xf fmeds) - - file (cond-> file - (some? project-id) - (assoc :project-id project-id) - - (some? name) - (assoc :name name) - - (true? reset-shared-flag) - (assoc :is-shared false)) - - file (-> file - (assoc :created-at now) - (assoc :modified-at now) - (assoc :ignore-sync-until ignore) - (update :id #(get index %)) - (process-file index))] - - (db/insert! conn :file file) - (db/insert! conn :file-profile-rel - {:file-id (:id file) - :profile-id profile-id - :is-owner true - :is-admin true - :can-edit true}) - - (doseq [params flibs] - (db/insert! conn :file-library-rel params)) - - (doseq [params fmeds] - (db/insert! conn :file-media-object params)) - - file)) - + [clojure.spec.alpha :as s])) ;; --- MUTATION: Duplicate File -(declare duplicate-file) - -(s/def ::duplicate-file - (s/keys :req-un [::profile-id ::file-id] - :opt-un [::name])) +(s/def ::duplicate-file ::cmd.mgm/duplicate-file) (sv/defmethod ::duplicate-file - [{:keys [pool] :as cfg} {:keys [profile-id file-id] :as params}] + {::doc/added "1.2" + ::doc/deprecated "1.16"} + [{:keys [pool] :as cfg} params] (db/with-atomic [conn pool] - (let [file (db/get-by-id conn :file file-id) - index {file-id (uuid/next)} - params (assoc params :index index :file file)] - (proj/check-edition-permissions! conn profile-id (:project-id file)) - (db/exec-one! conn ["SET CONSTRAINTS ALL DEFERRED"]) - (-> (duplicate-file conn params {:reset-shared-flag true}) - (update :data blob/decode))))) - + (cmd.mgm/duplicate-file conn params))) ;; --- MUTATION: Duplicate Project -(declare duplicate-project) - -(s/def ::duplicate-project - (s/keys :req-un [::profile-id ::project-id] - :opt-un [::name])) +(s/def ::duplicate-project ::cmd.mgm/duplicate-project) (sv/defmethod ::duplicate-project + {::doc/added "1.2" + ::doc/deprecated "1.16"} [{:keys [pool] :as cfg} {:keys [profile-id project-id] :as params}] (db/with-atomic [conn pool] - (let [project (db/get-by-id conn :project project-id)] - (teams/check-edition-permissions! conn profile-id (:team-id project)) - (db/exec-one! conn ["SET CONSTRAINTS ALL DEFERRED"]) - (duplicate-project conn (assoc params :project project))))) - -(defn duplicate-project - [conn {:keys [profile-id project name] :as params}] - (let [files (db/query conn :file - {:project-id (:id project) - :deleted-at nil} - {:columns [:id]}) - - project (cond-> project - (string? name) - (assoc :name name) - - :always - (assoc :id (uuid/next)))] - - ;; create the duplicated project and assign the current profile as - ;; a project owner - (create-project conn project) - (create-project-role conn {:project-id (:id project) - :profile-id profile-id - :role :owner}) - - ;; duplicate all files - (let [index (reduce #(assoc %1 (:id %2) (uuid/next)) {} files) - params (-> params - (dissoc :name) - (assoc :project-id (:id project)) - (assoc :index index))] - (doseq [{:keys [id]} files] - (let [file (db/get-by-id conn :file id) - params (assoc params :file file) - opts {:reset-shared-flag false}] - (duplicate-file conn params opts)))) - - ;; return the created project - project)) - + (cmd.mgm/duplicate-project conn params))) ;; --- MUTATION: Move file -(def sql:retrieve-files - "select id, project_id from file where id = ANY(?)") - -(def sql:move-files - "update file set project_id = ? where id = ANY(?)") - -(def sql:delete-broken-relations - "with broken as ( - (select * from file_library_rel as flr - inner join file as f on (flr.file_id = f.id) - inner join project as p on (f.project_id = p.id) - inner join file as lf on (flr.library_file_id = lf.id) - inner join project as lp on (lf.project_id = lp.id) - where p.id = ANY(?) - and lp.team_id != p.team_id) - ) - delete from file_library_rel as rel - using broken as br - where rel.file_id = br.file_id - and rel.library_file_id = br.library_file_id") - -(s/def ::ids (s/every ::us/uuid :kind set?)) -(s/def ::move-files - (s/keys :req-un [::profile-id ::ids ::project-id])) +(s/def ::move-files ::cmd.mgm/move-files) (sv/defmethod ::move-files - [{:keys [pool] :as cfg} {:keys [profile-id ids project-id] :as params}] + {::doc/added "1.2" + ::doc/deprecated "1.16"} + [{:keys [pool] :as cfg} params] (db/with-atomic [conn pool] - (let [fids (db/create-array conn "uuid" ids) - files (db/exec! conn [sql:retrieve-files fids]) - source (into #{} (map :project-id) files) - pids (->> (conj source project-id) - (db/create-array conn "uuid"))] - - ;; Check if we have permissions on the destination project - (proj/check-edition-permissions! conn profile-id project-id) - - ;; Check if we have permissions on all source projects - (doseq [project-id source] - (proj/check-edition-permissions! conn profile-id project-id)) - - (when (contains? source project-id) - (ex/raise :type :validation - :code :cant-move-to-same-project - :hint "Unable to move a file to the same project")) - - ;; move all files to the project - (db/exec-one! conn [sql:move-files project-id fids]) - - ;; delete possible broken relations on moved files - (db/exec-one! conn [sql:delete-broken-relations pids]) - - nil))) - + (cmd.mgm/move-files conn params))) ;; --- MUTATION: Move project -(declare move-project) - -(s/def ::move-project - (s/keys :req-un [::profile-id ::team-id ::project-id])) +(s/def ::move-project ::cmd.mgm/move-project) (sv/defmethod ::move-project - [{:keys [pool] :as cfg} {:keys [profile-id team-id project-id] :as params}] + {::doc/added "1.2" + ::doc/deprecated "1.16"} + [{:keys [pool] :as cfg} params] (db/with-atomic [conn pool] - (let [project (db/get-by-id conn :project project-id {:columns [:id :team-id]}) - - pids (->> (db/query conn :project {:team-id (:team-id project)} {:columns [:id]}) - (map :id) - (db/create-array conn "uuid"))] - - (teams/check-edition-permissions! conn profile-id (:team-id project)) - (teams/check-edition-permissions! conn profile-id team-id) - - (when (= team-id (:team-id project)) - (ex/raise :type :validation - :code :cant-move-to-same-team - :hint "Unable to move a project to same team")) - - ;; move project to the destination team - (db/update! conn :project - {:team-id team-id} - {:id project-id}) - - ;; delete possible broken relations on moved files - (db/exec-one! conn [sql:delete-broken-relations pids]) - - nil))) + (cmd.mgm/move-project conn params))) diff --git a/backend/src/app/setup/initial_data.clj b/backend/src/app/setup/initial_data.clj deleted file mode 100644 index 6532a54e5..000000000 --- a/backend/src/app/setup/initial_data.clj +++ /dev/null @@ -1,106 +0,0 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public -;; License, v. 2.0. If a copy of the MPL was not distributed with this -;; file, You can obtain one at http://mozilla.org/MPL/2.0/. -;; -;; Copyright (c) UXBOX Labs SL - -(ns app.setup.initial-data - (:refer-clojure :exclude [load]) - (:require - [app.common.uuid :as uuid] - [app.config :as cf] - [app.db :as db] - [app.rpc.mutations.management :refer [duplicate-file]] - [app.rpc.mutations.projects :refer [create-project create-project-role]] - [app.rpc.queries.profile :as profile])) - -;; --- DUMP GENERATION - -(def sql:file - "select * from file where project_id = ?") - -(def sql:file-library-rel - "with file_ids as (select id from file where project_id = ?) - select * - from file_library_rel - where file_id in (select id from file_ids)") - -(def sql:file-media-object - "with file_ids as (select id from file where project_id = ?) - select * - from file_media_object - where file_id in (select id from file_ids)") - -(defn dump - ([system project-id] (dump system project-id nil)) - ([system project-id {:keys [skey project-name] - :or {project-name "Penpot Onboarding"}}] - (db/with-atomic [conn (:app.db/pool system)] - (let [skey (or skey (cf/get :initial-project-skey)) - files (db/exec! conn [sql:file project-id]) - flibs (db/exec! conn [sql:file-library-rel project-id]) - fmeds (db/exec! conn [sql:file-media-object project-id]) - data {:project-name project-name - :files files - :flibs flibs - :fmeds fmeds}] - - (db/delete! conn :server-prop {:id skey}) - (db/insert! conn :server-prop - {:id skey - :preload false - :content (db/tjson data)}) - skey)))) - - -;; --- DUMP LOADING - -(defn- retrieve-data - [conn skey] - (when-let [row (db/exec-one! conn ["select content from server_prop where id = ?" skey])] - (when-let [content (:content row)] - (when (db/pgobject? content) - (db/decode-transit-pgobject content))))) - -(defn load-initial-project! - ([conn profile] (load-initial-project! conn profile nil)) - ([conn profile opts] - (let [skey (or (:skey opts) (cf/get :initial-project-skey)) - data (retrieve-data conn skey)] - (when data - (let [index (reduce #(assoc %1 (:id %2) (uuid/next)) {} (:files data)) - project {:id (uuid/next) - :profile-id (:id profile) - :team-id (:default-team-id profile) - :name (:project-name data)}] - - (db/exec-one! conn ["SET CONSTRAINTS ALL DEFERRED"]) - - (create-project conn project) - (create-project-role conn {:project-id (:id project) - :profile-id (:id profile) - :role :owner}) - - (doseq [file (:files data)] - (let [flibs (filterv #(= (:id file) (:file-id %)) (:flibs data)) - fmeds (filterv #(= (:id file) (:file-id %)) (:fmeds data)) - - params {:profile-id (:id profile) - :project-id (:id project) - :file file - :index index - :flibs flibs - :fmeds fmeds} - - opts {:reset-shared-flag false}] - (duplicate-file conn params opts)))))))) - -(defn load - [system {:keys [email] :as opts}] - (db/with-atomic [conn (:app.db/pool system)] - (when-let [profile (some->> email - (profile/retrieve-profile-data-by-email conn) - (profile/populate-additional-data conn))] - (load-initial-project! conn profile opts) - true))) - diff --git a/backend/test/app/services_management_test.clj b/backend/test/app/services_management_test.clj index 2089537ea..bcfa277f9 100644 --- a/backend/test/app/services_management_test.clj +++ b/backend/test/app/services_management_test.clj @@ -19,6 +19,8 @@ (t/use-fixtures :once th/state-init) (t/use-fixtures :each th/database-reset) +;; TODO: migrate to commands + (t/deftest duplicate-file (let [storage (-> (:app.storage/storage th/*system*) (configure-storage-backend)) diff --git a/frontend/src/app/main/data/dashboard.cljs b/frontend/src/app/main/data/dashboard.cljs index 33dce462a..071cb4b3f 100644 --- a/frontend/src/app/main/data/dashboard.cljs +++ b/frontend/src/app/main/data/dashboard.cljs @@ -568,8 +568,7 @@ new-name (str name " " (tr "dashboard.copy-suffix"))] - (->> (rp/mutation! :duplicate-project {:project-id id - :name new-name}) + (->> (rp/command! :duplicate-project {:project-id id :name new-name}) (rx/tap on-success) (rx/map project-duplicated) (rx/catch on-error)))))) @@ -589,8 +588,7 @@ :or {on-success identity on-error rx/throw}} (meta params)] - (->> (rp/mutation! :move-project {:project-id id - :team-id team-id}) + (->> (rp/command! :move-project {:project-id id :team-id team-id}) (rx/tap on-success) (rx/catch on-error)))))) @@ -771,8 +769,7 @@ new-name (str name " " (tr "dashboard.copy-suffix"))] - (->> (rp/mutation! :duplicate-file {:file-id id - :name new-name}) + (->> (rp/command! :duplicate-file {:file-id id :name new-name}) (rx/tap on-success) (rx/map file-created) (rx/catch on-error)))))) @@ -794,7 +791,7 @@ (let [{:keys [on-success on-error] :or {on-success identity on-error rx/throw}} (meta params)] - (->> (rp/mutation! :move-files {:ids ids :project-id project-id}) + (->> (rp/command! :move-files {:ids ids :project-id project-id}) (rx/tap on-success) (rx/catch on-error))))))