0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-20 19:51:23 -05:00

Import images and upload media

This commit is contained in:
alonso.torres 2021-06-03 22:11:25 +02:00
parent 83879fb931
commit 152bcf451a
4 changed files with 97 additions and 35 deletions
common/src/app/common
frontend
deps.edn
src/app
util/import
worker

View file

@ -24,7 +24,7 @@
(when verify-on-commit?
(us/assert ::spec/change change))
(-> file
(update :changes conj change)
(update :changes (fnil conj []) change)
(update :data ch/process-changes [change] verify-on-commit?)))
(defn- lookup-objects

View file

@ -6,7 +6,7 @@
binaryage/devtools {:mvn/version "RELEASE"}
metosin/reitit-core {:mvn/version "0.5.13"}
funcool/beicon {:mvn/version "2021.06.02-0"}
funcool/beicon {:mvn/version "2021.06.03-0"}
funcool/okulary {:mvn/version "2020.04.14-0"}
funcool/potok {:mvn/version "2021.06.07-0"}
funcool/rumext {:mvn/version "2021.05.12-1"}

View file

@ -91,7 +91,7 @@
[type node]
(if (search-data-node? type)
(let [data-tags #{:ellipse :rect :path :text :foreignObject}]
(let [data-tags #{:ellipse :rect :path :text :foreignObject :image}]
(->> node
(node-seq)
(filter #(contains? data-tags (:tag %)))
@ -220,11 +220,19 @@
(= stroke-alignment :inner)
(update :stroke-width / 2))))
(defn add-image-data
[props node data]
(-> props
(assoc-in [:metadata :id] (get-meta node :media-id))
(assoc-in [:metadata :width] (get-meta node :media-width))
(assoc-in [:metadata :height] (get-meta node :media-height))
(assoc-in [:metadata :mtype] (get-meta node :media-mtype))))
(defn add-text-data
[props node]
(-> props
(assoc :grow-type (get-meta node :grow-type keyword))
(assoc :content (get-meta node :content json/decode))))
(assoc :content (get-meta node :content json/decode))))
(defn str->bool
[val]
@ -249,6 +257,9 @@
(assoc :blocked blocked)
(assoc :hidden hidden)
(cond-> (= :image type)
(add-image-data node data))
(cond-> (= :text type)
(add-text-data node))
@ -257,3 +268,12 @@
(cond-> (some? transform-inverse)
(assoc :transform-inverse transform-inverse))))))
(defn get-image-name
[node]
(get-in node [:attrs :penpot:name]))
(defn get-image-data
[node]
(let [data (get-shape-data :image node)]
(:xlink:href data)))

View file

@ -11,6 +11,7 @@
[app.common.pages :as cp]
[app.common.uuid :as uuid]
[app.main.repo :as rp]
[app.util.http :as http]
[app.util.import.parser :as cip]
[app.util.zip :as uz]
[app.worker.impl :as impl]
@ -21,21 +22,21 @@
;; Upload changes batches size
(def change-batch-size 100)
(defn create-empty-file
(defn create-file
"Create a new file on the back-end"
[project-id file]
(rp/mutation
:create-file
{:id (:id file)
:name (:name file)
:project-id project-id
:data (-> cp/empty-file-data
(assoc :id (:id file)))}))
[project-id name]
(let [file-id (uuid/next)]
(rp/mutation
:create-file
{:id file-id
:name name
:project-id project-id
:data (-> cp/empty-file-data (assoc :id file-id))})))
(defn send-changes
"Creates batches of changes to be sent to the backend"
[file init-revn]
(let [revn (atom init-revn)
[file]
(let [revn (atom (:revn file))
file-id (:id file)
session-id (uuid/next)
changes-batches
@ -55,11 +56,21 @@
(rx/tap #(reset! revn (:revn %))))))
(defn persist-file
"Sends to the back-end the imported data"
[project-id file]
(->> (create-empty-file project-id file)
(rx/flat-map #(send-changes file (:revn %)))))
(defn upload-media-files
"Upload a image to the backend and returns its id"
[file-id name data-uri]
(->> (http/send!
{:uri data-uri
:response-type :blob
:method :get})
(rx/map :body)
(rx/map
(fn [blob]
{:name name
:file-id file-id
:content blob
:is-local true}))
(rx/flat-map #(rp/mutation! :upload-file-media-object %))))
(defn parse-file-name
[dir]
@ -102,15 +113,41 @@
;; default
file))))
(defn merge-reduce [f seed ob]
(->> (rx/concat
(rx/of seed)
(rx/merge-scan f seed ob))
(rx/last)))
(defn resolve-images
[file-id node]
(if (and (cip/shape? node) (= (cip/get-type node) :image) (not (cip/close? node)))
(let [name (cip/get-image-name node)
data-uri (cip/get-image-data node)]
(->> (upload-media-files file-id name data-uri)
(rx/map
(fn [media]
(-> node
(assoc-in [:attrs :penpot:media-id] (:id media))
(assoc-in [:attrs :penpot:media-width] (:width media))
(assoc-in [:attrs :penpot:media-height] (:height media))
(assoc-in [:attrs :penpot:media-mtype] (:mtype media)))))))
;; If the node is not an image just return the node
(rx/of node)))
(defn import-page
[file {:keys [path content]}]
(let [page-name (parse-page-name path)]
(when (cip/valid? content)
(let [nodes (->> content cip/node-seq)]
(->> nodes
(filter cip/shape?)
(reduce add-shape-file (fb/add-page file page-name))
(fb/close-page))))))
(if (cip/valid? content)
(let [nodes (->> content cip/node-seq)
file-id (:id file)]
(->> (rx/from nodes)
(rx/filter cip/shape?)
(rx/mapcat (partial resolve-images file-id))
(rx/reduce add-shape-file (fb/add-page file page-name))
(rx/map fb/close-page)))
(rx/empty))))
(defmethod impl/handler :import-file
[{:keys [project-id files]}]
@ -130,14 +167,19 @@
(rx/map #(d/update-when % :content tubax/xml->clj)))]
(->> dir-str
(rx/merge-map #(create-file project-id (parse-file-name %)))
(rx/merge-map
(fn [dir]
(let [file (fb/create-file (parse-file-name dir))]
(rx/concat
(->> file-str
(rx/filter #(str/starts-with? (:path %) dir))
(rx/reduce import-page file)
(rx/flat-map #(persist-file project-id %))
(rx/ignore))
(fn [file]
(rx/concat
(->> file-str
(rx/filter #(str/starts-with? (:path %) (:name file)))
(merge-reduce import-page file)
(rx/flat-map send-changes)
(rx/catch (fn [err]
(.error js/console "ERROR" err (clj->js (.-data err)))
(rx/of (select-keys file [:id :name])))))))))
;; We delete the file when there is an error
(rp/mutation! :delete-file {:id (:id file)})))
(rx/ignore))
(rx/of (select-keys file [:id :name]))))))))