mirror of
https://github.com/penpot/penpot.git
synced 2025-01-09 00:10:11 -05:00
🎉 Create add-image-from-url service
This commit is contained in:
parent
c0cbb5877b
commit
85bae6cf26
4 changed files with 86 additions and 18 deletions
|
@ -10,6 +10,7 @@
|
|||
(ns uxbox.services.mutations.images
|
||||
(:require
|
||||
[clojure.spec.alpha :as s]
|
||||
[clojure.java.io :as io]
|
||||
[datoteka.core :as fs]
|
||||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.spec :as us]
|
||||
|
@ -22,7 +23,8 @@
|
|||
[uxbox.services.queries.teams :as teams]
|
||||
[uxbox.tasks :as tasks]
|
||||
[uxbox.util.storage :as ust]
|
||||
[uxbox.util.time :as dt]))
|
||||
[uxbox.util.time :as dt]
|
||||
[uxbox.util.http :as http]))
|
||||
|
||||
(def thumbnail-options
|
||||
{:width 800
|
||||
|
@ -35,7 +37,7 @@
|
|||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::library-id ::us/uuid)
|
||||
(s/def ::team-id ::us/uuid)
|
||||
|
||||
(s/def ::url ::us/url)
|
||||
|
||||
;; --- Create Library
|
||||
|
||||
|
@ -108,6 +110,7 @@
|
|||
|
||||
;; --- Create Image (Upload)
|
||||
|
||||
(declare download-image)
|
||||
(declare create-image)
|
||||
(declare persist-image-on-fs)
|
||||
(declare persist-image-thumbnail-on-fs)
|
||||
|
@ -128,10 +131,43 @@
|
|||
|
||||
(s/def ::content ::upload)
|
||||
|
||||
(s/def ::upload-image
|
||||
(s/keys :req-un [::profile-id ::name ::content ::library-id]
|
||||
(s/def ::add-image-from-url
|
||||
(s/keys :req-un [::profile-id ::library-id ::name ::url]
|
||||
:opt-un [::id]))
|
||||
|
||||
(s/def ::upload-image
|
||||
(s/keys :req-un [::profile-id ::library-id ::name ::content]
|
||||
:opt-un [::id]))
|
||||
|
||||
(sm/defmutation ::add-image-from-url
|
||||
[{:keys [library-id profile-id url] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [lib (select-library-for-update conn library-id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id lib))
|
||||
(let [content (download-image url)
|
||||
params' (merge params {:content content})]
|
||||
(create-image conn params')))))
|
||||
|
||||
(defn download-image
|
||||
[url]
|
||||
(let [result (http/get! url {:as :byte-array})
|
||||
data (:body result)
|
||||
content-type (get (:headers result) "content-type")
|
||||
format (images/mtype->format content-type)]
|
||||
(if (nil? format)
|
||||
(ex/raise :type :validation
|
||||
:code :image-type-not-allowed
|
||||
:hint "Seems like the url points to an invalid image.")
|
||||
(let [tempfile (fs/create-tempfile)
|
||||
base-filename (get (fs/split-ext (fs/name tempfile)) 0)
|
||||
filename (str base-filename (images/format->extension format))]
|
||||
(with-open [ostream (io/output-stream tempfile)]
|
||||
(.write ostream data))
|
||||
{:filename filename
|
||||
:size (count data)
|
||||
:tempfile tempfile
|
||||
:content-type content-type}))))
|
||||
|
||||
(sm/defmutation ::upload-image
|
||||
[{:keys [library-id profile-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
(def default-client
|
||||
(delay (http/build-client {:executor @px/default-executor})))
|
||||
|
||||
(defn get!
|
||||
[url opts]
|
||||
(let [opts' (merge {:client @default-client :as :string} opts)]
|
||||
(http/get url nil opts')))
|
||||
|
||||
(defn send!
|
||||
[req]
|
||||
(http/send req {:client @default-client :as :string}))
|
||||
|
|
|
@ -104,10 +104,36 @@
|
|||
))
|
||||
|
||||
(t/deftest images-crud
|
||||
(let [prof (th/create-profile db/pool 1)
|
||||
team-id (:default-team-id prof)
|
||||
lib (th/create-image-library db/pool team-id 1)
|
||||
image-id (uuid/next)]
|
||||
(let [prof (th/create-profile db/pool 1)
|
||||
team-id (:default-team-id prof)
|
||||
image-id-1 (uuid/next)
|
||||
image-id-2 (uuid/next)
|
||||
lib (th/create-image-library db/pool team-id 1)]
|
||||
|
||||
(t/testing "create image from url to library"
|
||||
(let [url "https://raw.githubusercontent.com/uxbox/uxbox/develop/frontend/resources/images/penpot-login.jpg"
|
||||
data {::sm/type :add-image-from-url
|
||||
:id image-id-1
|
||||
:profile-id (:id prof)
|
||||
:library-id (:id lib)
|
||||
:name "testfile"
|
||||
:url url}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(t/is (= image-id-1 (get-in out [:result :id])))
|
||||
(t/is (= "testfile" (get-in out [:result :name])))
|
||||
(t/is (= "image/jpeg" (get-in out [:result :mtype])))
|
||||
(t/is (= "image/jpeg" (get-in out [:result :thumb-mtype])))
|
||||
(t/is (= 787 (get-in out [:result :width])))
|
||||
(t/is (= 2000 (get-in out [:result :height])))
|
||||
|
||||
(t/is (string? (get-in out [:result :path])))
|
||||
(t/is (string? (get-in out [:result :thumb-path])))
|
||||
(t/is (string? (get-in out [:result :uri])))
|
||||
(t/is (string? (get-in out [:result :thumb-uri])))))
|
||||
|
||||
(t/testing "upload image to library"
|
||||
(let [content {:filename "sample.jpg"
|
||||
|
@ -115,7 +141,7 @@
|
|||
:content-type "image/jpeg"
|
||||
:size 312043}
|
||||
data {::sm/type :upload-image
|
||||
:id image-id
|
||||
:id image-id-2
|
||||
:profile-id (:id prof)
|
||||
:library-id (:id lib)
|
||||
:name "testfile"
|
||||
|
@ -125,7 +151,7 @@
|
|||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(t/is (= image-id (get-in out [:result :id])))
|
||||
(t/is (= image-id-2 (get-in out [:result :id])))
|
||||
(t/is (= "testfile" (get-in out [:result :name])))
|
||||
(t/is (= "image/jpeg" (get-in out [:result :mtype])))
|
||||
(t/is (= "image/jpeg" (get-in out [:result :thumb-mtype])))
|
||||
|
@ -135,8 +161,7 @@
|
|||
(t/is (string? (get-in out [:result :path])))
|
||||
(t/is (string? (get-in out [:result :thumb-path])))
|
||||
(t/is (string? (get-in out [:result :uri])))
|
||||
(t/is (string? (get-in out [:result :thumb-uri])))
|
||||
))
|
||||
(t/is (string? (get-in out [:result :thumb-uri])))))
|
||||
|
||||
(t/testing "list images by library"
|
||||
(let [data {::sq/type :images
|
||||
|
@ -145,7 +170,8 @@
|
|||
out (th/try-on! (sq/handle data))]
|
||||
;; (th/print-result! out)
|
||||
|
||||
(t/is (= image-id (get-in out [:result 0 :id])))
|
||||
;; Result is ordered by creation date descendent
|
||||
(t/is (= image-id-2 (get-in out [:result 0 :id])))
|
||||
(t/is (= "testfile" (get-in out [:result 0 :name])))
|
||||
(t/is (= "image/jpeg" (get-in out [:result 0 :mtype])))
|
||||
(t/is (= "image/jpeg" (get-in out [:result 0 :thumb-mtype])))
|
||||
|
@ -160,11 +186,11 @@
|
|||
(t/testing "single image"
|
||||
(let [data {::sq/type :image
|
||||
:profile-id (:id prof)
|
||||
:id image-id}
|
||||
:id image-id-2}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
;; (th/print-result! out)
|
||||
|
||||
(t/is (= image-id (get-in out [:result :id])))
|
||||
(t/is (= image-id-2 (get-in out [:result :id])))
|
||||
(t/is (= "testfile" (get-in out [:result :name])))
|
||||
(t/is (= "image/jpeg" (get-in out [:result :mtype])))
|
||||
(t/is (= "image/jpeg" (get-in out [:result :thumb-mtype])))
|
||||
|
@ -179,7 +205,7 @@
|
|||
(t/testing "delete images"
|
||||
(let [data {::sm/type :delete-image
|
||||
:profile-id (:id prof)
|
||||
:id image-id}
|
||||
:id image-id-1}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
|
@ -189,7 +215,7 @@
|
|||
(t/testing "query image after delete"
|
||||
(let [data {::sq/type :image
|
||||
:profile-id (:id prof)
|
||||
:id image-id}
|
||||
:id image-id-1}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
|
@ -208,5 +234,5 @@
|
|||
out (th/try-on! (sq/handle data))]
|
||||
;; (th/print-result! out)
|
||||
(let [result (:result out)]
|
||||
(t/is (= 0 (count result))))))
|
||||
(t/is (= 1 (count result))))))
|
||||
))
|
||||
|
|
|
@ -105,6 +105,7 @@
|
|||
(s/def ::number (s/conformer number-conformer str))
|
||||
(s/def ::integer (s/conformer integer-conformer str))
|
||||
(s/def ::not-empty-string (s/and string? #(not (str/empty? %))))
|
||||
(s/def ::url string?)
|
||||
#?(:clj (s/def ::path (s/conformer path-conformer str)))
|
||||
|
||||
;; --- Macros
|
||||
|
|
Loading…
Reference in a new issue