mirror of
https://github.com/penpot/penpot.git
synced 2025-03-13 16:21:57 -05:00
♻️ The big media refactor (backend)
This commit is contained in:
parent
8b1ba8c020
commit
bd7114182f
33 changed files with 2037 additions and 1937 deletions
46
backend/resources/migrations/0014-refactor-media-storage.sql
Normal file
46
backend/resources/migrations/0014-refactor-media-storage.sql
Normal file
|
@ -0,0 +1,46 @@
|
|||
ALTER TABLE image
|
||||
RENAME TO media_object;
|
||||
|
||||
ALTER TABLE media_object
|
||||
ADD COLUMN is_local boolean NOT NULL DEFAULT false;
|
||||
|
||||
INSERT INTO media_object
|
||||
(id, file_id, created_at, modified_at, deleted_at, name, path,
|
||||
width, height, mtype, thumb_path, thumb_width, thumb_height,
|
||||
thumb_quality, thumb_mtype, is_local)
|
||||
(SELECT id, file_id, created_at, modified_at, deleted_at, name, path,
|
||||
width, height, mtype, thumb_path, thumb_width, thumb_height,
|
||||
thumb_quality, thumb_mtype, true
|
||||
FROM file_image);
|
||||
|
||||
CREATE TABLE media_thumbnail (
|
||||
id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
media_object_id uuid NOT NULL REFERENCES media_object(id) ON DELETE CASCADE,
|
||||
mtype text NOT NULL,
|
||||
path text NOT NULL,
|
||||
width int NOT NULL,
|
||||
height int NOT NULL,
|
||||
quality int NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX media_thumbnail__media_object_id__idx
|
||||
ON media_thumbnail(media_object_id);
|
||||
|
||||
INSERT INTO media_thumbnail
|
||||
(media_object_id, mtype, path, width, height, quality)
|
||||
(SELECT id, thumb_mtype, thumb_path, thumb_width, thumb_height, thumb_quality
|
||||
FROM media_object);
|
||||
|
||||
ALTER TABLE media_object
|
||||
DROP COLUMN thumb_mtype,
|
||||
DROP COLUMN thumb_path,
|
||||
DROP COLUMN thumb_width,
|
||||
DROP COLUMN thumb_height,
|
||||
DROP COLUMN thumb_quality;
|
||||
|
||||
DROP TABLE color_library;
|
||||
DROP TABLE icon;
|
||||
DROP TABLE icon_library;
|
||||
DROP TABLE image_library;
|
||||
DROP TABLE file_image;
|
||||
|
|
@ -17,7 +17,6 @@
|
|||
[uxbox.common.spec :as us]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.tasks :as tasks]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.util.emails :as emails]))
|
||||
|
||||
;; --- Defaults
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.config :as cfg]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.migrations]
|
||||
[uxbox.services.mutations.profile :as profile]
|
||||
[uxbox.util.blob :as blob]))
|
||||
|
|
|
@ -1,218 +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/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2020 UXBOX Labs SL
|
||||
|
||||
(ns uxbox.images
|
||||
"Image postprocessing."
|
||||
(:require
|
||||
[clojure.core.async :as a]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.spec.alpha :as s]
|
||||
[datoteka.core :as fs]
|
||||
[mount.core :refer [defstate]]
|
||||
[uxbox.config :as cfg]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.util.storage :as ust]
|
||||
[uxbox.util.http :as http])
|
||||
(:import
|
||||
java.io.ByteArrayInputStream
|
||||
java.io.InputStream
|
||||
java.util.concurrent.Semaphore
|
||||
org.im4java.core.ConvertCmd
|
||||
org.im4java.core.Info
|
||||
org.im4java.core.IMOperation))
|
||||
|
||||
(defstate semaphore
|
||||
:start (Semaphore. (:image-process-max-threads cfg/config 1)))
|
||||
|
||||
;; --- Thumbnails Generation
|
||||
|
||||
(s/def ::cmd keyword?)
|
||||
|
||||
(s/def ::path (s/or :path fs/path?
|
||||
:string string?
|
||||
:file fs/file?))
|
||||
(s/def ::mtype string?)
|
||||
|
||||
(s/def ::input
|
||||
(s/keys :req-un [::path]
|
||||
:opt-un [::mtype]))
|
||||
|
||||
(s/def ::width integer?)
|
||||
(s/def ::height integer?)
|
||||
(s/def ::format #{:jpeg :webp :png :svg})
|
||||
(s/def ::quality #(< 0 % 101))
|
||||
|
||||
(s/def ::thumbnail-params
|
||||
(s/keys :req-un [::cmd ::input ::format ::width ::height]))
|
||||
|
||||
;; Related info on how thumbnails generation
|
||||
;; http://www.imagemagick.org/Usage/thumbnails/
|
||||
|
||||
(defn format->extension
|
||||
[format]
|
||||
(case format
|
||||
:png ".png"
|
||||
:jpeg ".jpg"
|
||||
:webp ".webp"
|
||||
:svg ".svg"))
|
||||
|
||||
(defn format->mtype
|
||||
[format]
|
||||
(case format
|
||||
:png "image/png"
|
||||
:jpeg "image/jpeg"
|
||||
:webp "image/webp"
|
||||
:svg "image/svg+xml"))
|
||||
|
||||
(defn mtype->format
|
||||
[mtype]
|
||||
(case mtype
|
||||
"image/png" :png
|
||||
"image/jpeg" :jpeg
|
||||
"image/webp" :webp
|
||||
"image/svg+xml" :svg
|
||||
nil))
|
||||
|
||||
(defn- generic-process
|
||||
[{:keys [input format quality operation] :as params}]
|
||||
(let [{:keys [path mtype]} input
|
||||
format (or (mtype->format mtype) format)
|
||||
ext (format->extension format)
|
||||
tmp (fs/create-tempfile :suffix ext)]
|
||||
|
||||
(doto (ConvertCmd.)
|
||||
(.run operation (into-array (map str [path tmp]))))
|
||||
|
||||
(let [thumbnail-data (fs/slurp-bytes tmp)]
|
||||
(fs/delete tmp)
|
||||
(assoc params
|
||||
:format format
|
||||
:mtype (format->mtype format)
|
||||
:data (ByteArrayInputStream. thumbnail-data)))))
|
||||
|
||||
(defmulti process :cmd)
|
||||
|
||||
(defmethod process :generic-thumbnail
|
||||
[{:keys [quality width height] :as params}]
|
||||
(us/assert ::thumbnail-params params)
|
||||
(let [op (doto (IMOperation.)
|
||||
(.addImage)
|
||||
(.autoOrient)
|
||||
(.strip)
|
||||
(.thumbnail (int width) (int height) ">")
|
||||
(.quality (double quality))
|
||||
(.addImage))]
|
||||
(generic-process (assoc params :operation op))))
|
||||
|
||||
(defmethod process :profile-thumbnail
|
||||
[{:keys [quality width height] :as params}]
|
||||
(us/assert ::thumbnail-params params)
|
||||
(let [op (doto (IMOperation.)
|
||||
(.addImage)
|
||||
(.autoOrient)
|
||||
(.strip)
|
||||
(.thumbnail (int width) (int height) "^")
|
||||
(.gravity "center")
|
||||
(.extent (int width) (int height))
|
||||
(.quality (double quality))
|
||||
(.addImage))]
|
||||
(generic-process (assoc params :operation op))))
|
||||
|
||||
(defmethod process :info
|
||||
[{:keys [input] :as params}]
|
||||
(us/assert ::input input)
|
||||
(let [{:keys [path mtype]} input]
|
||||
(if (= mtype "image/svg+xml")
|
||||
{:width 100
|
||||
:height 100
|
||||
:mtype mtype}
|
||||
(let [instance (Info. (str path))
|
||||
mtype' (.getProperty instance "Mime type")]
|
||||
(when (and (string? mtype)
|
||||
(not= mtype mtype'))
|
||||
(ex/raise :type :validation
|
||||
:code :image-type-mismatch
|
||||
:hint "Seems like you are uploading a file whose content does not match the extension."))
|
||||
{:width (.getImageWidth instance)
|
||||
:height (.getImageHeight instance)
|
||||
:mtype mtype'}))))
|
||||
|
||||
(defmethod process :default
|
||||
[{:keys [cmd] :as params}]
|
||||
(ex/raise :type :internal
|
||||
:code :not-implemented
|
||||
:hint (str "No impl found for process cmd:" cmd)))
|
||||
|
||||
(defn run
|
||||
[params]
|
||||
(try
|
||||
(.acquire semaphore)
|
||||
(let [res (a/<!! (a/thread
|
||||
(try
|
||||
(process params)
|
||||
(catch Throwable e
|
||||
e))))]
|
||||
(if (instance? Throwable res)
|
||||
(throw res)
|
||||
res))
|
||||
(finally
|
||||
(.release semaphore))))
|
||||
|
||||
(defn resolve-urls
|
||||
[row src dst]
|
||||
(s/assert map? row)
|
||||
(if (and src dst)
|
||||
(let [src (if (vector? src) src [src])
|
||||
dst (if (vector? dst) dst [dst])
|
||||
value (get-in row src)]
|
||||
(if (empty? value)
|
||||
row
|
||||
(let [url (ust/public-uri media/media-storage value)]
|
||||
(assoc-in row dst (str url)))))
|
||||
row))
|
||||
|
||||
(defn- resolve-uri
|
||||
[storage row src dst]
|
||||
(let [src (if (vector? src) src [src])
|
||||
dst (if (vector? dst) dst [dst])
|
||||
value (get-in row src)]
|
||||
(if (empty? value)
|
||||
row
|
||||
(let [url (ust/public-uri media/media-storage value)]
|
||||
(assoc-in row dst (str url))))))
|
||||
|
||||
(defn resolve-media-uris
|
||||
[row & pairs]
|
||||
(us/assert map? row)
|
||||
(us/assert (s/coll-of vector?) pairs)
|
||||
(reduce #(resolve-uri media/media-storage %1 (nth %2 0) (nth %2 1)) row pairs))
|
||||
|
||||
(defn download-image
|
||||
[url]
|
||||
(let [result (http/get! url {:as :byte-array})
|
||||
data (:body result)
|
||||
content-type (get (:headers result) "content-type")
|
||||
format (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 (first (fs/split-ext (fs/name tempfile)))
|
||||
filename (str base-filename (format->extension format))]
|
||||
(with-open [ostream (io/output-stream tempfile)]
|
||||
(.write ostream data))
|
||||
{:filename filename
|
||||
:size (count data)
|
||||
:tempfile tempfile
|
||||
:content-type content-type}))))
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
[& args]
|
||||
(require 'uxbox.config
|
||||
'uxbox.migrations
|
||||
'uxbox.images
|
||||
'uxbox.media
|
||||
'uxbox.http
|
||||
'uxbox.tasks)
|
||||
(mount/start))
|
||||
|
|
|
@ -5,32 +5,214 @@
|
|||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2017-2020 Andrey Antukh <niwi@niwi.nz>
|
||||
;; Copyright (c) 2020 UXBOX Labs SL
|
||||
|
||||
(ns uxbox.media
|
||||
"A media storage impl for uxbox."
|
||||
"Media postprocessing."
|
||||
(:require
|
||||
[mount.core :refer [defstate]]
|
||||
[clojure.core.async :as a]
|
||||
[clojure.java.io :as io]
|
||||
[cuerdas.core :as str]
|
||||
[clojure.spec.alpha :as s]
|
||||
[datoteka.core :as fs]
|
||||
[mount.core :refer [defstate]]
|
||||
[uxbox.config :as cfg]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.media-storage :as mst]
|
||||
[uxbox.util.storage :as ust]
|
||||
[uxbox.config :refer [config]]))
|
||||
[uxbox.util.http :as http])
|
||||
(:import
|
||||
java.io.ByteArrayInputStream
|
||||
java.io.InputStream
|
||||
java.util.concurrent.Semaphore
|
||||
org.im4java.core.ConvertCmd
|
||||
org.im4java.core.Info
|
||||
org.im4java.core.IMOperation))
|
||||
|
||||
;; --- State
|
||||
(defstate semaphore
|
||||
:start (Semaphore. (:image-process-max-threads cfg/config 1)))
|
||||
|
||||
(defstate assets-storage
|
||||
:start (ust/create {:base-path (:assets-directory config)
|
||||
:base-uri (:assets-uri config)}))
|
||||
;; --- Thumbnails Generation
|
||||
|
||||
(defstate media-storage
|
||||
:start (ust/create {:base-path (:media-directory config)
|
||||
:base-uri (:media-uri config)
|
||||
:xf (comp ust/random-path
|
||||
ust/slugify-filename)}))
|
||||
(s/def ::cmd keyword?)
|
||||
|
||||
;; --- Public Api
|
||||
(s/def ::path (s/or :path fs/path?
|
||||
:string string?
|
||||
:file fs/file?))
|
||||
(s/def ::mtype string?)
|
||||
|
||||
(s/def ::input
|
||||
(s/keys :req-un [::path]
|
||||
:opt-un [::mtype]))
|
||||
|
||||
(s/def ::width integer?)
|
||||
(s/def ::height integer?)
|
||||
(s/def ::format #{:jpeg :webp :png :svg})
|
||||
(s/def ::quality #(< 0 % 101))
|
||||
|
||||
(s/def ::thumbnail-params
|
||||
(s/keys :req-un [::cmd ::input ::format ::width ::height]))
|
||||
|
||||
;; Related info on how thumbnails generation
|
||||
;; http://www.imagemagick.org/Usage/thumbnails/
|
||||
|
||||
(defn format->extension
|
||||
[format]
|
||||
(case format
|
||||
:png ".png"
|
||||
:jpeg ".jpg"
|
||||
:webp ".webp"
|
||||
:svg ".svg"))
|
||||
|
||||
(defn format->mtype
|
||||
[format]
|
||||
(case format
|
||||
:png "image/png"
|
||||
:jpeg "image/jpeg"
|
||||
:webp "image/webp"
|
||||
:svg "image/svg+xml"))
|
||||
|
||||
(defn mtype->format
|
||||
[mtype]
|
||||
(case mtype
|
||||
"image/png" :png
|
||||
"image/jpeg" :jpeg
|
||||
"image/webp" :webp
|
||||
"image/svg+xml" :svg
|
||||
nil))
|
||||
|
||||
(defn- generic-process
|
||||
[{:keys [input format quality operation] :as params}]
|
||||
(let [{:keys [path mtype]} input
|
||||
format (or (mtype->format mtype) format)
|
||||
ext (format->extension format)
|
||||
tmp (fs/create-tempfile :suffix ext)]
|
||||
|
||||
(doto (ConvertCmd.)
|
||||
(.run operation (into-array (map str [path tmp]))))
|
||||
|
||||
(let [thumbnail-data (fs/slurp-bytes tmp)]
|
||||
(fs/delete tmp)
|
||||
(assoc params
|
||||
:format format
|
||||
:mtype (format->mtype format)
|
||||
:data (ByteArrayInputStream. thumbnail-data)))))
|
||||
|
||||
(defmulti process :cmd)
|
||||
|
||||
(defmethod process :generic-thumbnail
|
||||
[{:keys [quality width height] :as params}]
|
||||
(us/assert ::thumbnail-params params)
|
||||
(let [op (doto (IMOperation.)
|
||||
(.addImage)
|
||||
(.autoOrient)
|
||||
(.strip)
|
||||
(.thumbnail (int width) (int height) ">")
|
||||
(.quality (double quality))
|
||||
(.addImage))]
|
||||
(generic-process (assoc params :operation op))))
|
||||
|
||||
(defmethod process :profile-thumbnail
|
||||
[{:keys [quality width height] :as params}]
|
||||
(us/assert ::thumbnail-params params)
|
||||
(let [op (doto (IMOperation.)
|
||||
(.addImage)
|
||||
(.autoOrient)
|
||||
(.strip)
|
||||
(.thumbnail (int width) (int height) "^")
|
||||
(.gravity "center")
|
||||
(.extent (int width) (int height))
|
||||
(.quality (double quality))
|
||||
(.addImage))]
|
||||
(generic-process (assoc params :operation op))))
|
||||
|
||||
(defmethod process :info
|
||||
[{:keys [input] :as params}]
|
||||
(us/assert ::input input)
|
||||
(let [{:keys [path mtype]} input]
|
||||
(if (= mtype "image/svg+xml")
|
||||
{:width 100
|
||||
:height 100
|
||||
:mtype mtype}
|
||||
(let [instance (Info. (str path))
|
||||
mtype' (.getProperty instance "Mime type")]
|
||||
(when (and (string? mtype)
|
||||
(not= mtype mtype'))
|
||||
(ex/raise :type :validation
|
||||
:code :image-type-mismatch
|
||||
:hint "Seems like you are uploading a file whose content does not match the extension."))
|
||||
{:width (.getImageWidth instance)
|
||||
:height (.getImageHeight instance)
|
||||
:mtype mtype'}))))
|
||||
|
||||
(defmethod process :default
|
||||
[{:keys [cmd] :as params}]
|
||||
(ex/raise :type :internal
|
||||
:code :not-implemented
|
||||
:hint (str "No impl found for process cmd:" cmd)))
|
||||
|
||||
(defn run
|
||||
[params]
|
||||
(try
|
||||
(.acquire semaphore)
|
||||
(let [res (a/<!! (a/thread
|
||||
(try
|
||||
(process params)
|
||||
(catch Throwable e
|
||||
e))))]
|
||||
(if (instance? Throwable res)
|
||||
(throw res)
|
||||
res))
|
||||
(finally
|
||||
(.release semaphore))))
|
||||
|
||||
(defn resolve-urls
|
||||
[row src dst]
|
||||
(s/assert map? row)
|
||||
(if (and src dst)
|
||||
(let [src (if (vector? src) src [src])
|
||||
dst (if (vector? dst) dst [dst])
|
||||
value (get-in row src)]
|
||||
(if (empty? value)
|
||||
row
|
||||
(let [url (ust/public-uri mst/media-storage value)]
|
||||
(assoc-in row dst (str url)))))
|
||||
row))
|
||||
|
||||
(defn- resolve-uri
|
||||
[storage row src dst]
|
||||
(let [src (if (vector? src) src [src])
|
||||
dst (if (vector? dst) dst [dst])
|
||||
value (get-in row src)]
|
||||
(if (empty? value)
|
||||
row
|
||||
(let [url (ust/public-uri mst/media-storage value)]
|
||||
(assoc-in row dst (str url))))))
|
||||
|
||||
(defn resolve-media-uris
|
||||
[row & pairs]
|
||||
(us/assert map? row)
|
||||
(us/assert (s/coll-of vector?) pairs)
|
||||
(reduce #(resolve-uri mst/media-storage %1 (nth %2 0) (nth %2 1)) row pairs))
|
||||
|
||||
(defn download-media-object
|
||||
[url]
|
||||
(let [result (http/get! url {:as :byte-array})
|
||||
data (:body result)
|
||||
content-type (get (:headers result) "content-type")
|
||||
format (mtype->format content-type)]
|
||||
(if (nil? format)
|
||||
(ex/raise :type :validation
|
||||
:code :media-type-not-allowed
|
||||
:hint "Seems like the url points to an invalid media object.")
|
||||
(let [tempfile (fs/create-tempfile)
|
||||
base-filename (first (fs/split-ext (fs/name tempfile)))
|
||||
filename (str base-filename (format->extension format))]
|
||||
(with-open [ostream (io/output-stream tempfile)]
|
||||
(.write ostream data))
|
||||
{:filename filename
|
||||
:size (count data)
|
||||
:tempfile tempfile
|
||||
:content-type content-type}))))
|
||||
|
||||
(defn resolve-asset
|
||||
[path]
|
||||
(str (ust/public-uri assets-storage path)))
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
[uxbox.db :as db]
|
||||
[uxbox.http]
|
||||
[uxbox.migrations]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.util.svg :as svg]
|
||||
[uxbox.util.transit :as t]
|
||||
[uxbox.util.blob :as blob]
|
||||
|
@ -32,8 +31,7 @@
|
|||
[uxbox.services.mutations.projects :as projects]
|
||||
[uxbox.services.mutations.files :as files]
|
||||
[uxbox.services.mutations.colors :as colors]
|
||||
[uxbox.services.mutations.icons :as icons]
|
||||
[uxbox.services.mutations.images :as images]
|
||||
[uxbox.services.mutations.media :as media]
|
||||
[uxbox.util.storage :as ust])
|
||||
(:import
|
||||
java.io.Reader
|
||||
|
@ -164,7 +162,7 @@
|
|||
;; [conn {:keys [name] :as item}]
|
||||
;; (let [id (uuid/namespaced +images-uuid-ns+ name)]
|
||||
;; (log/info "Creating image library:" name)
|
||||
;; (images/create-library conn {:id id
|
||||
;; (media/create-library conn {:id id
|
||||
;; :team-id uuid/zero
|
||||
;; :name name})))
|
||||
;;
|
||||
|
@ -188,7 +186,7 @@
|
|||
;; ".png" "image/png"
|
||||
;; ".webp" "image/webp")]
|
||||
;; (log/info "Creating image" filename image-id)
|
||||
;; (images/create-image conn {:content {:tempfile localpath
|
||||
;; (media/create-image conn {:content {:tempfile localpath
|
||||
;; :filename filename
|
||||
;; :content-type mtype
|
||||
;; :size (.length file)}
|
||||
|
@ -298,19 +296,19 @@
|
|||
".webp" "image/webp"
|
||||
".svg" "image/svg+xml")]
|
||||
(log/info "Creating image" filename image-id)
|
||||
(images/create-image conn {:content {:tempfile localpath
|
||||
:filename filename
|
||||
:content-type mtype
|
||||
:size (.length file)}
|
||||
:id image-id
|
||||
:file-id file-id
|
||||
:user uuid/zero
|
||||
:name filename})))
|
||||
(media/create-media-object conn {:content {:tempfile localpath
|
||||
:filename filename
|
||||
:content-type mtype
|
||||
:size (.length file)}
|
||||
:id image-id
|
||||
:file-id file-id
|
||||
:name filename
|
||||
:is-local false})))
|
||||
|
||||
(defn- image-exists?
|
||||
[conn id]
|
||||
(s/assert ::us/uuid id)
|
||||
(let [row (db/get-by-id conn :image id)]
|
||||
(let [row (db/get-by-id conn :media-object id)]
|
||||
(if row true false)))
|
||||
|
||||
(defn- import-image-if-not-exists
|
||||
|
@ -355,7 +353,7 @@
|
|||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Libraries Importer
|
||||
;; Library files Importer
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn- library-file-exists?
|
||||
|
|
36
backend/src/uxbox/media_storage.clj
Normal file
36
backend/src/uxbox/media_storage.clj
Normal file
|
@ -0,0 +1,36 @@
|
|||
;; 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/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2017-2020 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.media-storage
|
||||
"A media storage impl for uxbox."
|
||||
(:require
|
||||
[mount.core :refer [defstate]]
|
||||
[clojure.java.io :as io]
|
||||
[cuerdas.core :as str]
|
||||
[datoteka.core :as fs]
|
||||
[uxbox.util.storage :as ust]
|
||||
[uxbox.config :refer [config]]))
|
||||
|
||||
;; --- State
|
||||
|
||||
(defstate assets-storage
|
||||
:start (ust/create {:base-path (:assets-directory config)
|
||||
:base-uri (:assets-uri config)}))
|
||||
|
||||
(defstate media-storage
|
||||
:start (ust/create {:base-path (:media-directory config)
|
||||
:base-uri (:media-uri config)
|
||||
:xf (comp ust/random-path
|
||||
ust/slugify-filename)}))
|
||||
|
||||
;; --- Public Api
|
||||
|
||||
(defn resolve-asset
|
||||
[path]
|
||||
(str (ust/public-uri assets-storage path)))
|
|
@ -67,7 +67,11 @@
|
|||
|
||||
{:desc "Mark files shareable"
|
||||
:name "0013-mark-files-shareable"
|
||||
:fn (mg/resource "migrations/0013-mark-files-shareable.sql")}]})
|
||||
:fn (mg/resource "migrations/0013-mark-files-shareable.sql")}
|
||||
|
||||
{:desc "Refactor media storage"
|
||||
:name "0014-refactor-media-storage.sql"
|
||||
:fn (mg/resource "migrations/0014-refactor-media-storage.sql")}]})
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Entry point
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
(defn- load-query-services
|
||||
[]
|
||||
(require 'uxbox.services.queries.icons)
|
||||
(require 'uxbox.services.queries.images)
|
||||
;; (require 'uxbox.services.queries.icons)
|
||||
(require 'uxbox.services.queries.media)
|
||||
(require 'uxbox.services.queries.colors)
|
||||
(require 'uxbox.services.queries.projects)
|
||||
(require 'uxbox.services.queries.files)
|
||||
|
@ -28,8 +28,8 @@
|
|||
(defn- load-mutation-services
|
||||
[]
|
||||
(require 'uxbox.services.mutations.demo)
|
||||
(require 'uxbox.services.mutations.icons)
|
||||
(require 'uxbox.services.mutations.images)
|
||||
;; (require 'uxbox.services.mutations.icons)
|
||||
(require 'uxbox.services.mutations.media)
|
||||
(require 'uxbox.services.mutations.colors)
|
||||
(require 'uxbox.services.mutations.projects)
|
||||
(require 'uxbox.services.mutations.files)
|
||||
|
|
|
@ -30,92 +30,93 @@
|
|||
(s/def ::content ::us/string)
|
||||
|
||||
|
||||
;; --- Mutation: Create Library
|
||||
;; ;; --- Mutation: Create Library
|
||||
;;
|
||||
;; (declare create-library)
|
||||
;;
|
||||
;; (s/def ::create-color-library
|
||||
;; (s/keys :req-un [::profile-id ::team-id ::name]
|
||||
;; :opt-un [::id]))
|
||||
;;
|
||||
;; (sm/defmutation ::create-color-library
|
||||
;; [{:keys [profile-id team-id] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (teams/check-edition-permissions! conn profile-id team-id)
|
||||
;; (create-library conn params)))
|
||||
;;
|
||||
;; (defn create-library
|
||||
;; [conn {:keys [id team-id name]}]
|
||||
;; (let [id (or id (uuid/next))]
|
||||
;; (db/insert! conn :color-library
|
||||
;; {:id id
|
||||
;; :team-id team-id
|
||||
;; :name name})))
|
||||
;;
|
||||
|
||||
(declare create-library)
|
||||
|
||||
(s/def ::create-color-library
|
||||
(s/keys :req-un [::profile-id ::team-id ::name]
|
||||
:opt-un [::id]))
|
||||
|
||||
(sm/defmutation ::create-color-library
|
||||
[{:keys [profile-id team-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(teams/check-edition-permissions! conn profile-id team-id)
|
||||
(create-library conn params)))
|
||||
|
||||
(defn create-library
|
||||
[conn {:keys [id team-id name]}]
|
||||
(let [id (or id (uuid/next))]
|
||||
(db/insert! conn :color-library
|
||||
{:id id
|
||||
:team-id team-id
|
||||
:name name})))
|
||||
;; ;; --- Mutation: Rename Library
|
||||
;;
|
||||
;; (declare select-library-for-update)
|
||||
;; (declare rename-library)
|
||||
;;
|
||||
;; (s/def ::rename-color-library
|
||||
;; (s/keys :req-un [::profile-id ::name ::id]))
|
||||
;;
|
||||
;; (sm/defmutation ::rename-color-library
|
||||
;; [{:keys [id profile-id name] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (let [lib (select-library-for-update conn id)]
|
||||
;; (teams/check-edition-permissions! conn profile-id (:team-id lib))
|
||||
;; (rename-library conn id name))))
|
||||
;;
|
||||
;; (def ^:private sql:select-library-for-update
|
||||
;; "select l.*
|
||||
;; from color_library as l
|
||||
;; where l.id = $1
|
||||
;; for update")
|
||||
;;
|
||||
;; (def ^:private sql:rename-library
|
||||
;; "update color_library
|
||||
;; set name = $2
|
||||
;; where id = $1")
|
||||
;;
|
||||
;; (defn- select-library-for-update
|
||||
;; [conn id]
|
||||
;; (db/get-by-id conn :color-library id {:for-update true}))
|
||||
;;
|
||||
;; (defn- rename-library
|
||||
;; [conn id name]
|
||||
;; (db/update! conn :color-library
|
||||
;; {:name name}
|
||||
;; {:id id}))
|
||||
|
||||
|
||||
;; --- Mutation: Rename Library
|
||||
|
||||
(declare select-library-for-update)
|
||||
(declare rename-library)
|
||||
|
||||
(s/def ::rename-color-library
|
||||
(s/keys :req-un [::profile-id ::name ::id]))
|
||||
|
||||
(sm/defmutation ::rename-color-library
|
||||
[{:keys [id profile-id name] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [lib (select-library-for-update conn id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id lib))
|
||||
(rename-library conn id name))))
|
||||
|
||||
(def ^:private sql:select-library-for-update
|
||||
"select l.*
|
||||
from color_library as l
|
||||
where l.id = $1
|
||||
for update")
|
||||
|
||||
(def ^:private sql:rename-library
|
||||
"update color_library
|
||||
set name = $2
|
||||
where id = $1")
|
||||
|
||||
(defn- select-library-for-update
|
||||
[conn id]
|
||||
(db/get-by-id conn :color-library id {:for-update true}))
|
||||
|
||||
(defn- rename-library
|
||||
[conn id name]
|
||||
(db/update! conn :color-library
|
||||
{:name name}
|
||||
{:id id}))
|
||||
;; ;; --- Delete Library
|
||||
;;
|
||||
;; (declare delete-library)
|
||||
;;
|
||||
;; (s/def ::delete-color-library
|
||||
;; (s/keys :req-un [::profile-id ::id]))
|
||||
;;
|
||||
;; (sm/defmutation ::delete-color-library
|
||||
;; [{:keys [id profile-id] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (let [lib (select-library-for-update conn id)]
|
||||
;; (teams/check-edition-permissions! conn profile-id (:team-id lib))
|
||||
;;
|
||||
;; ;; Schedule object deletion
|
||||
;; (tasks/submit! conn {:name "delete-object"
|
||||
;; :delay cfg/default-deletion-delay
|
||||
;; :props {:id id :type :color-library}})
|
||||
;;
|
||||
;; (db/update! conn :color-library
|
||||
;; {:deleted-at (dt/now)}
|
||||
;; {:id id})
|
||||
;; nil)))
|
||||
|
||||
|
||||
;; --- Delete Library
|
||||
|
||||
(declare delete-library)
|
||||
|
||||
(s/def ::delete-color-library
|
||||
(s/keys :req-un [::profile-id ::id]))
|
||||
|
||||
(sm/defmutation ::delete-color-library
|
||||
[{:keys [id profile-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [lib (select-library-for-update conn id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id lib))
|
||||
|
||||
;; Schedule object deletion
|
||||
(tasks/submit! conn {:name "delete-object"
|
||||
:delay cfg/default-deletion-delay
|
||||
:props {:id id :type :color-library}})
|
||||
|
||||
(db/update! conn :color-library
|
||||
{:deleted-at (dt/now)}
|
||||
{:id id})
|
||||
nil)))
|
||||
|
||||
|
||||
;; --- Mutation: Create Color (Upload)
|
||||
;; --- Mutation: Create Color
|
||||
|
||||
(declare select-file-for-update)
|
||||
(declare create-color)
|
||||
|
||||
(s/def ::create-color
|
||||
|
@ -125,10 +126,9 @@
|
|||
(sm/defmutation ::create-color
|
||||
[{:keys [profile-id file-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(create-color conn params)))
|
||||
;; (let [lib (select-library-for-update conn library-id)]
|
||||
;; (teams/check-edition-permissions! conn profile-id (:team-id lib))
|
||||
;; (create-color conn params))))
|
||||
(let [file (select-file-for-update conn file-id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id file))
|
||||
(create-color conn params))))
|
||||
|
||||
(def ^:private sql:create-color
|
||||
"insert into color (id, name, file_id, content)
|
||||
|
@ -142,6 +142,21 @@
|
|||
:file-id file-id
|
||||
:content content})))
|
||||
|
||||
(def ^:private sql:select-file-for-update
|
||||
"select file.*,
|
||||
project.team_id as team_id
|
||||
from file
|
||||
inner join project on (project.id = file.project_id)
|
||||
where file.id = ?
|
||||
for update of file")
|
||||
|
||||
(defn- select-file-for-update
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:select-file-for-update id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
|
||||
;; --- Mutation: Rename Color
|
||||
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.config :as cfg]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.images :as images]
|
||||
[uxbox.media :as media]
|
||||
;; [uxbox.images :as images]
|
||||
;; [uxbox.media :as media]
|
||||
[uxbox.services.mutations :as sm]
|
||||
[uxbox.services.mutations.images :as imgs]
|
||||
;; [uxbox.services.mutations.images :as imgs]
|
||||
[uxbox.services.mutations.projects :as proj]
|
||||
[uxbox.services.queries.files :as files]
|
||||
[uxbox.tasks :as tasks]
|
||||
|
@ -37,13 +37,14 @@
|
|||
(s/def ::project-id ::us/uuid)
|
||||
(s/def ::url ::us/url)
|
||||
|
||||
;; --- Mutation: Create Project File
|
||||
;; --- Mutation: Create File
|
||||
|
||||
(declare create-file)
|
||||
(declare create-page)
|
||||
|
||||
(s/def ::is-shared boolean?)
|
||||
(s/def ::create-file
|
||||
(s/keys :req-un [::profile-id ::name ::project-id]
|
||||
(s/keys :req-un [::profile-id ::name ::project-id ::is-shared]
|
||||
:opt-un [::id]))
|
||||
|
||||
(sm/defmutation ::create-file
|
||||
|
@ -63,14 +64,13 @@
|
|||
:can-edit true}))
|
||||
|
||||
(defn create-file
|
||||
[conn {:keys [id profile-id name project-id shared?] :as params}]
|
||||
[conn {:keys [id profile-id name project-id is-shared] :as params}]
|
||||
(let [id (or id (uuid/next))
|
||||
shared? (or shared? false)
|
||||
file (db/insert! conn :file
|
||||
{:id id
|
||||
:project-id project-id
|
||||
:name name
|
||||
:is-shared shared?})]
|
||||
:is-shared is-shared})]
|
||||
(->> (assoc params :file-id id)
|
||||
(create-file-profile conn))
|
||||
file))
|
||||
|
@ -153,135 +153,135 @@
|
|||
nil)
|
||||
|
||||
|
||||
;; --- Mutations: Create File Image (Upload and create from url)
|
||||
|
||||
(declare create-file-image)
|
||||
|
||||
(s/def ::file-id ::us/uuid)
|
||||
(s/def ::image-id ::us/uuid)
|
||||
(s/def ::content ::imgs/upload)
|
||||
|
||||
(s/def ::add-file-image-from-url
|
||||
(s/keys :req-un [::profile-id ::file-id ::url]
|
||||
:opt-un [::id]))
|
||||
|
||||
(s/def ::upload-file-image
|
||||
(s/keys :req-un [::profile-id ::file-id ::name ::content]
|
||||
:opt-un [::id]))
|
||||
|
||||
(sm/defmutation ::add-file-image-from-url
|
||||
[{:keys [profile-id file-id url] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(files/check-edition-permissions! conn profile-id file-id)
|
||||
(let [content (images/download-image url)
|
||||
params' (merge params {:content content
|
||||
:name (:filename content)})]
|
||||
(create-file-image conn params'))))
|
||||
|
||||
(sm/defmutation ::upload-file-image
|
||||
[{:keys [profile-id file-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(files/check-edition-permissions! conn profile-id file-id)
|
||||
(create-file-image conn params)))
|
||||
|
||||
(defn- create-file-image
|
||||
[conn {:keys [content file-id name] :as params}]
|
||||
(when-not (imgs/valid-image-types? (:content-type content))
|
||||
(ex/raise :type :validation
|
||||
:code :image-type-not-allowed
|
||||
:hint "Seems like you are uploading an invalid image."))
|
||||
|
||||
(let [info (images/run {:cmd :info :input {:path (:tempfile content)
|
||||
:mtype (:content-type content)}})
|
||||
path (imgs/persist-image-on-fs content)
|
||||
opts (assoc imgs/thumbnail-options
|
||||
:input {:mtype (:mtype info)
|
||||
:path path})
|
||||
thumb (if-not (= (:mtype info) "image/svg+xml")
|
||||
(imgs/persist-image-thumbnail-on-fs opts)
|
||||
(assoc info
|
||||
:path path
|
||||
:quality 0))]
|
||||
|
||||
(-> (db/insert! conn :file-image
|
||||
{:file-id file-id
|
||||
:name name
|
||||
:path (str path)
|
||||
:width (:width info)
|
||||
:height (:height info)
|
||||
:mtype (:mtype info)
|
||||
:thumb-path (str (:path thumb))
|
||||
:thumb-width (:width thumb)
|
||||
:thumb-height (:height thumb)
|
||||
:thumb-quality (:quality thumb)
|
||||
:thumb-mtype (:mtype thumb)})
|
||||
(images/resolve-urls :path :uri)
|
||||
(images/resolve-urls :thumb-path :thumb-uri))))
|
||||
|
||||
|
||||
;; --- Mutation: Delete File Image
|
||||
|
||||
(declare mark-file-image-deleted)
|
||||
|
||||
(s/def ::delete-file-image
|
||||
(s/keys :req-un [::file-id ::image-id ::profile-id]))
|
||||
|
||||
(sm/defmutation ::delete-file-image
|
||||
[{:keys [file-id image-id profile-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(files/check-edition-permissions! conn profile-id file-id)
|
||||
|
||||
;; Schedule object deletion
|
||||
(tasks/submit! conn {:name "delete-object"
|
||||
:delay cfg/default-deletion-delay
|
||||
:props {:id image-id :type :file-image}})
|
||||
|
||||
(mark-file-image-deleted conn params)))
|
||||
|
||||
(defn mark-file-image-deleted
|
||||
[conn {:keys [image-id] :as params}]
|
||||
(db/update! conn :file-image
|
||||
{:deleted-at (dt/now)}
|
||||
{:id image-id})
|
||||
nil)
|
||||
|
||||
|
||||
;; --- Mutation: Import from collection
|
||||
|
||||
(declare copy-image)
|
||||
(declare import-image-to-file)
|
||||
|
||||
(s/def ::import-image-to-file
|
||||
(s/keys :req-un [::image-id ::file-id ::profile-id]))
|
||||
|
||||
(sm/defmutation ::import-image-to-file
|
||||
[{:keys [image-id file-id profile-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(files/check-edition-permissions! conn profile-id file-id)
|
||||
(import-image-to-file conn params)))
|
||||
|
||||
(defn- import-image-to-file
|
||||
[conn {:keys [image-id file-id] :as params}]
|
||||
(let [image (db/get-by-id conn :image image-id)
|
||||
image-path (copy-image (:path image))
|
||||
thumb-path (copy-image (:thumb-path image))]
|
||||
|
||||
(-> (db/insert! conn :file-image
|
||||
{:file-id file-id
|
||||
:name (:name image)
|
||||
:path (str image-path)
|
||||
:width (:width image)
|
||||
:height (:height image)
|
||||
:mtype (:mtype image)
|
||||
:thumb-path (str thumb-path)
|
||||
:thumb-width (:thumb-width image)
|
||||
:thumb-height (:thumb-height image)
|
||||
:thumb-quality (:thumb-quality image)
|
||||
:thumb-mtype (:thumb-mtype image)})
|
||||
(images/resolve-urls :path :uri)
|
||||
(images/resolve-urls :thumb-path :thumb-uri))))
|
||||
|
||||
(defn- copy-image
|
||||
[path]
|
||||
(let [image-path (ust/lookup media/media-storage path)]
|
||||
(ust/save! media/media-storage (fs/name image-path) image-path)))
|
||||
;; ;; --- Mutations: Create File Image (Upload and create from url)
|
||||
;;
|
||||
;; (declare create-file-image)
|
||||
;;
|
||||
;; (s/def ::file-id ::us/uuid)
|
||||
;; (s/def ::image-id ::us/uuid)
|
||||
;; (s/def ::content ::imgs/upload)
|
||||
;;
|
||||
;; (s/def ::add-file-image-from-url
|
||||
;; (s/keys :req-un [::profile-id ::file-id ::url]
|
||||
;; :opt-un [::id]))
|
||||
;;
|
||||
;; (s/def ::upload-file-image
|
||||
;; (s/keys :req-un [::profile-id ::file-id ::name ::content]
|
||||
;; :opt-un [::id]))
|
||||
;;
|
||||
;; (sm/defmutation ::add-file-image-from-url
|
||||
;; [{:keys [profile-id file-id url] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (files/check-edition-permissions! conn profile-id file-id)
|
||||
;; (let [content (images/download-image url)
|
||||
;; params' (merge params {:content content
|
||||
;; :name (:filename content)})]
|
||||
;; (create-file-image conn params'))))
|
||||
;;
|
||||
;; (sm/defmutation ::upload-file-image
|
||||
;; [{:keys [profile-id file-id] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (files/check-edition-permissions! conn profile-id file-id)
|
||||
;; (create-file-image conn params)))
|
||||
;;
|
||||
;; (defn- create-file-image
|
||||
;; [conn {:keys [content file-id name] :as params}]
|
||||
;; (when-not (imgs/valid-image-types? (:content-type content))
|
||||
;; (ex/raise :type :validation
|
||||
;; :code :image-type-not-allowed
|
||||
;; :hint "Seems like you are uploading an invalid image."))
|
||||
;;
|
||||
;; (let [info (images/run {:cmd :info :input {:path (:tempfile content)
|
||||
;; :mtype (:content-type content)}})
|
||||
;; path (imgs/persist-image-on-fs content)
|
||||
;; opts (assoc imgs/thumbnail-options
|
||||
;; :input {:mtype (:mtype info)
|
||||
;; :path path})
|
||||
;; thumb (if-not (= (:mtype info) "image/svg+xml")
|
||||
;; (imgs/persist-image-thumbnail-on-fs opts)
|
||||
;; (assoc info
|
||||
;; :path path
|
||||
;; :quality 0))]
|
||||
;;
|
||||
;; (-> (db/insert! conn :file-image
|
||||
;; {:file-id file-id
|
||||
;; :name name
|
||||
;; :path (str path)
|
||||
;; :width (:width info)
|
||||
;; :height (:height info)
|
||||
;; :mtype (:mtype info)
|
||||
;; :thumb-path (str (:path thumb))
|
||||
;; :thumb-width (:width thumb)
|
||||
;; :thumb-height (:height thumb)
|
||||
;; :thumb-quality (:quality thumb)
|
||||
;; :thumb-mtype (:mtype thumb)})
|
||||
;; (images/resolve-urls :path :uri)
|
||||
;; (images/resolve-urls :thumb-path :thumb-uri))))
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Mutation: Delete File Image
|
||||
;;
|
||||
;; (declare mark-file-image-deleted)
|
||||
;;
|
||||
;; (s/def ::delete-file-image
|
||||
;; (s/keys :req-un [::file-id ::image-id ::profile-id]))
|
||||
;;
|
||||
;; (sm/defmutation ::delete-file-image
|
||||
;; [{:keys [file-id image-id profile-id] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (files/check-edition-permissions! conn profile-id file-id)
|
||||
;;
|
||||
;; ;; Schedule object deletion
|
||||
;; (tasks/submit! conn {:name "delete-object"
|
||||
;; :delay cfg/default-deletion-delay
|
||||
;; :props {:id image-id :type :file-image}})
|
||||
;;
|
||||
;; (mark-file-image-deleted conn params)))
|
||||
;;
|
||||
;; (defn mark-file-image-deleted
|
||||
;; [conn {:keys [image-id] :as params}]
|
||||
;; (db/update! conn :file-image
|
||||
;; {:deleted-at (dt/now)}
|
||||
;; {:id image-id})
|
||||
;; nil)
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Mutation: Import from collection
|
||||
;;
|
||||
;; (declare copy-image)
|
||||
;; (declare import-image-to-file)
|
||||
;;
|
||||
;; (s/def ::import-image-to-file
|
||||
;; (s/keys :req-un [::image-id ::file-id ::profile-id]))
|
||||
;;
|
||||
;; (sm/defmutation ::import-image-to-file
|
||||
;; [{:keys [image-id file-id profile-id] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (files/check-edition-permissions! conn profile-id file-id)
|
||||
;; (import-image-to-file conn params)))
|
||||
;;
|
||||
;; (defn- import-image-to-file
|
||||
;; [conn {:keys [image-id file-id] :as params}]
|
||||
;; (let [image (db/get-by-id conn :image image-id)
|
||||
;; image-path (copy-image (:path image))
|
||||
;; thumb-path (copy-image (:thumb-path image))]
|
||||
;;
|
||||
;; (-> (db/insert! conn :file-image
|
||||
;; {:file-id file-id
|
||||
;; :name (:name image)
|
||||
;; :path (str image-path)
|
||||
;; :width (:width image)
|
||||
;; :height (:height image)
|
||||
;; :mtype (:mtype image)
|
||||
;; :thumb-path (str thumb-path)
|
||||
;; :thumb-width (:thumb-width image)
|
||||
;; :thumb-height (:thumb-height image)
|
||||
;; :thumb-quality (:thumb-quality image)
|
||||
;; :thumb-mtype (:thumb-mtype image)})
|
||||
;; (images/resolve-urls :path :uri)
|
||||
;; (images/resolve-urls :thumb-path :thumb-uri))))
|
||||
;;
|
||||
;; (defn- copy-image
|
||||
;; [path]
|
||||
;; (let [image-path (ust/lookup media/media-storage path)]
|
||||
;; (ust/save! media/media-storage (fs/name image-path) image-path)))
|
||||
|
|
|
@ -7,200 +7,200 @@
|
|||
;;
|
||||
;; Copyright (c) 2019-2020 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.services.mutations.icons
|
||||
(:require
|
||||
[clojure.spec.alpha :as s]
|
||||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.config :as cfg]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.services.mutations :as sm]
|
||||
[uxbox.services.queries.icons :refer [decode-row]]
|
||||
[uxbox.services.queries.teams :as teams]
|
||||
[uxbox.tasks :as tasks]
|
||||
[uxbox.util.blob :as blob]
|
||||
[uxbox.util.time :as dt]))
|
||||
|
||||
;; --- Helpers & Specs
|
||||
|
||||
(s/def ::height ::us/integer)
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::library-id ::us/uuid)
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::team-id ::us/uuid)
|
||||
(s/def ::width ::us/integer)
|
||||
|
||||
(s/def ::view-box
|
||||
(s/and (s/coll-of number?)
|
||||
#(= 4 (count %))
|
||||
vector?))
|
||||
|
||||
(s/def ::content ::us/string)
|
||||
(s/def ::mimetype ::us/string)
|
||||
|
||||
(s/def ::metadata
|
||||
(s/keys :opt-un [::width ::height ::view-box ::mimetype]))
|
||||
|
||||
|
||||
;; --- Mutation: Create Library
|
||||
|
||||
(declare create-library)
|
||||
|
||||
(s/def ::create-icon-library
|
||||
(s/keys :req-un [::profile-id ::team-id ::name]
|
||||
:opt-un [::id]))
|
||||
|
||||
(sm/defmutation ::create-icon-library
|
||||
[{:keys [profile-id team-id id name] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(teams/check-edition-permissions! conn profile-id team-id)
|
||||
(create-library conn params)))
|
||||
|
||||
(def ^:private sql:create-library
|
||||
"insert into icon_library (id, team_id, name)
|
||||
values ($1, $2, $3)
|
||||
returning *;")
|
||||
|
||||
(defn create-library
|
||||
[conn {:keys [team-id id name] :as params}]
|
||||
(let [id (or id (uuid/next))]
|
||||
(db/insert! conn :icon-library
|
||||
{:id id
|
||||
:team-id team-id
|
||||
:name name})))
|
||||
|
||||
|
||||
;; --- Mutation: Rename Library
|
||||
|
||||
(declare select-library-for-update)
|
||||
(declare rename-library)
|
||||
|
||||
(s/def ::rename-icon-library
|
||||
(s/keys :req-un [::profile-id ::name ::id]))
|
||||
|
||||
(sm/defmutation ::rename-icon-library
|
||||
[{:keys [id profile-id name] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [lib (select-library-for-update conn id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id lib))
|
||||
(rename-library conn id name))))
|
||||
|
||||
(defn- select-library-for-update
|
||||
[conn id]
|
||||
(db/get-by-id conn :icon-library id {:for-update true}))
|
||||
|
||||
(defn- rename-library
|
||||
[conn id name]
|
||||
(db/update! conn :icon-library
|
||||
{:name name}
|
||||
{:id id}))
|
||||
|
||||
;; --- Mutation: Delete Library
|
||||
|
||||
(declare delete-library)
|
||||
|
||||
(s/def ::delete-icon-library
|
||||
(s/keys :req-un [::profile-id ::id]))
|
||||
|
||||
(sm/defmutation ::delete-icon-library
|
||||
[{:keys [profile-id id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [lib (select-library-for-update conn id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id lib))
|
||||
|
||||
;; Schedule object deletion
|
||||
(tasks/submit! conn {:name "delete-object"
|
||||
:delay cfg/default-deletion-delay
|
||||
:props {:id id :type :icon-library}})
|
||||
|
||||
(db/update! conn :icon-library
|
||||
{:deleted-at (dt/now)}
|
||||
{:id id})
|
||||
nil)))
|
||||
|
||||
|
||||
;; --- Mutation: Create Icon (Upload)
|
||||
|
||||
(declare create-icon)
|
||||
|
||||
(s/def ::create-icon
|
||||
(s/keys :req-un [::profile-id ::name ::metadata ::content ::library-id]
|
||||
:opt-un [::id]))
|
||||
|
||||
(sm/defmutation ::create-icon
|
||||
[{:keys [profile-id library-id] :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))
|
||||
(create-icon conn params))))
|
||||
|
||||
(defn create-icon
|
||||
[conn {:keys [id name library-id metadata content]}]
|
||||
(let [id (or id (uuid/next))]
|
||||
(-> (db/insert! conn :icon
|
||||
{:id id
|
||||
:name name
|
||||
:library-id library-id
|
||||
:content content
|
||||
:metadata (blob/encode metadata)})
|
||||
(decode-row))))
|
||||
|
||||
|
||||
;; --- Mutation: Rename Icon
|
||||
|
||||
(declare select-icon-for-update)
|
||||
(declare rename-icon)
|
||||
|
||||
(s/def ::rename-icon
|
||||
(s/keys :req-un [::id ::profile-id ::name]))
|
||||
|
||||
(sm/defmutation ::rename-icon
|
||||
[{:keys [id profile-id name] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [icon (select-icon-for-update conn id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id icon))
|
||||
(db/update! conn :icon
|
||||
{:name name}
|
||||
{:id id}))))
|
||||
|
||||
(def ^:private
|
||||
sql:select-icon-for-update
|
||||
"select i.*,
|
||||
lib.team_id as team_id
|
||||
from icon as i
|
||||
inner join icon_library as lib on (lib.id = i.library_id)
|
||||
where i.id = ?
|
||||
for update")
|
||||
|
||||
(defn- select-icon-for-update
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:select-icon-for-update id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
|
||||
;; --- Mutation: Delete Icon
|
||||
|
||||
(declare delete-icon)
|
||||
|
||||
(s/def ::delete-icon
|
||||
(s/keys :req-un [::profile-id ::id]))
|
||||
|
||||
(sm/defmutation ::delete-icon
|
||||
[{:keys [id profile-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [icn (select-icon-for-update conn id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id icn))
|
||||
|
||||
;; Schedule object deletion
|
||||
(tasks/submit! conn {:name "delete-object"
|
||||
:delay cfg/default-deletion-delay
|
||||
:props {:id id :type :icon}})
|
||||
|
||||
(db/update! conn :icon
|
||||
{:deleted-at (dt/now)}
|
||||
{:id id})
|
||||
nil)))
|
||||
;; (ns uxbox.services.mutations.icons
|
||||
;; (:require
|
||||
;; [clojure.spec.alpha :as s]
|
||||
;; [uxbox.common.exceptions :as ex]
|
||||
;; [uxbox.common.spec :as us]
|
||||
;; [uxbox.common.uuid :as uuid]
|
||||
;; [uxbox.config :as cfg]
|
||||
;; [uxbox.db :as db]
|
||||
;; [uxbox.services.mutations :as sm]
|
||||
;; [uxbox.services.queries.icons :refer [decode-row]]
|
||||
;; [uxbox.services.queries.teams :as teams]
|
||||
;; [uxbox.tasks :as tasks]
|
||||
;; [uxbox.util.blob :as blob]
|
||||
;; [uxbox.util.time :as dt]))
|
||||
;;
|
||||
;; ;; --- Helpers & Specs
|
||||
;;
|
||||
;; (s/def ::height ::us/integer)
|
||||
;; (s/def ::id ::us/uuid)
|
||||
;; (s/def ::library-id ::us/uuid)
|
||||
;; (s/def ::name ::us/string)
|
||||
;; (s/def ::profile-id ::us/uuid)
|
||||
;; (s/def ::team-id ::us/uuid)
|
||||
;; (s/def ::width ::us/integer)
|
||||
;;
|
||||
;; (s/def ::view-box
|
||||
;; (s/and (s/coll-of number?)
|
||||
;; #(= 4 (count %))
|
||||
;; vector?))
|
||||
;;
|
||||
;; (s/def ::content ::us/string)
|
||||
;; (s/def ::mimetype ::us/string)
|
||||
;;
|
||||
;; (s/def ::metadata
|
||||
;; (s/keys :opt-un [::width ::height ::view-box ::mimetype]))
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Mutation: Create Library
|
||||
;;
|
||||
;; (declare create-library)
|
||||
;;
|
||||
;; (s/def ::create-icon-library
|
||||
;; (s/keys :req-un [::profile-id ::team-id ::name]
|
||||
;; :opt-un [::id]))
|
||||
;;
|
||||
;; (sm/defmutation ::create-icon-library
|
||||
;; [{:keys [profile-id team-id id name] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (teams/check-edition-permissions! conn profile-id team-id)
|
||||
;; (create-library conn params)))
|
||||
;;
|
||||
;; (def ^:private sql:create-library
|
||||
;; "insert into icon_library (id, team_id, name)
|
||||
;; values ($1, $2, $3)
|
||||
;; returning *;")
|
||||
;;
|
||||
;; (defn create-library
|
||||
;; [conn {:keys [team-id id name] :as params}]
|
||||
;; (let [id (or id (uuid/next))]
|
||||
;; (db/insert! conn :icon-library
|
||||
;; {:id id
|
||||
;; :team-id team-id
|
||||
;; :name name})))
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Mutation: Rename Library
|
||||
;;
|
||||
;; (declare select-library-for-update)
|
||||
;; (declare rename-library)
|
||||
;;
|
||||
;; (s/def ::rename-icon-library
|
||||
;; (s/keys :req-un [::profile-id ::name ::id]))
|
||||
;;
|
||||
;; (sm/defmutation ::rename-icon-library
|
||||
;; [{:keys [id profile-id name] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (let [lib (select-library-for-update conn id)]
|
||||
;; (teams/check-edition-permissions! conn profile-id (:team-id lib))
|
||||
;; (rename-library conn id name))))
|
||||
;;
|
||||
;; (defn- select-library-for-update
|
||||
;; [conn id]
|
||||
;; (db/get-by-id conn :icon-library id {:for-update true}))
|
||||
;;
|
||||
;; (defn- rename-library
|
||||
;; [conn id name]
|
||||
;; (db/update! conn :icon-library
|
||||
;; {:name name}
|
||||
;; {:id id}))
|
||||
;;
|
||||
;; ;; --- Mutation: Delete Library
|
||||
;;
|
||||
;; (declare delete-library)
|
||||
;;
|
||||
;; (s/def ::delete-icon-library
|
||||
;; (s/keys :req-un [::profile-id ::id]))
|
||||
;;
|
||||
;; (sm/defmutation ::delete-icon-library
|
||||
;; [{:keys [profile-id id] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (let [lib (select-library-for-update conn id)]
|
||||
;; (teams/check-edition-permissions! conn profile-id (:team-id lib))
|
||||
;;
|
||||
;; ;; Schedule object deletion
|
||||
;; (tasks/submit! conn {:name "delete-object"
|
||||
;; :delay cfg/default-deletion-delay
|
||||
;; :props {:id id :type :icon-library}})
|
||||
;;
|
||||
;; (db/update! conn :icon-library
|
||||
;; {:deleted-at (dt/now)}
|
||||
;; {:id id})
|
||||
;; nil)))
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Mutation: Create Icon (Upload)
|
||||
;;
|
||||
;; (declare create-icon)
|
||||
;;
|
||||
;; (s/def ::create-icon
|
||||
;; (s/keys :req-un [::profile-id ::name ::metadata ::content ::library-id]
|
||||
;; :opt-un [::id]))
|
||||
;;
|
||||
;; (sm/defmutation ::create-icon
|
||||
;; [{:keys [profile-id library-id] :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))
|
||||
;; (create-icon conn params))))
|
||||
;;
|
||||
;; (defn create-icon
|
||||
;; [conn {:keys [id name library-id metadata content]}]
|
||||
;; (let [id (or id (uuid/next))]
|
||||
;; (-> (db/insert! conn :icon
|
||||
;; {:id id
|
||||
;; :name name
|
||||
;; :library-id library-id
|
||||
;; :content content
|
||||
;; :metadata (blob/encode metadata)})
|
||||
;; (decode-row))))
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Mutation: Rename Icon
|
||||
;;
|
||||
;; (declare select-icon-for-update)
|
||||
;; (declare rename-icon)
|
||||
;;
|
||||
;; (s/def ::rename-icon
|
||||
;; (s/keys :req-un [::id ::profile-id ::name]))
|
||||
;;
|
||||
;; (sm/defmutation ::rename-icon
|
||||
;; [{:keys [id profile-id name] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (let [icon (select-icon-for-update conn id)]
|
||||
;; (teams/check-edition-permissions! conn profile-id (:team-id icon))
|
||||
;; (db/update! conn :icon
|
||||
;; {:name name}
|
||||
;; {:id id}))))
|
||||
;;
|
||||
;; (def ^:private
|
||||
;; sql:select-icon-for-update
|
||||
;; "select i.*,
|
||||
;; lib.team_id as team_id
|
||||
;; from icon as i
|
||||
;; inner join icon_library as lib on (lib.id = i.library_id)
|
||||
;; where i.id = ?
|
||||
;; for update")
|
||||
;;
|
||||
;; (defn- select-icon-for-update
|
||||
;; [conn id]
|
||||
;; (let [row (db/exec-one! conn [sql:select-icon-for-update id])]
|
||||
;; (when-not row
|
||||
;; (ex/raise :type :not-found))
|
||||
;; row))
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Mutation: Delete Icon
|
||||
;;
|
||||
;; (declare delete-icon)
|
||||
;;
|
||||
;; (s/def ::delete-icon
|
||||
;; (s/keys :req-un [::profile-id ::id]))
|
||||
;;
|
||||
;; (sm/defmutation ::delete-icon
|
||||
;; [{:keys [id profile-id] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (let [icn (select-icon-for-update conn id)]
|
||||
;; (teams/check-edition-permissions! conn profile-id (:team-id icn))
|
||||
;;
|
||||
;; ;; Schedule object deletion
|
||||
;; (tasks/submit! conn {:name "delete-object"
|
||||
;; :delay cfg/default-deletion-delay
|
||||
;; :props {:id id :type :icon}})
|
||||
;;
|
||||
;; (db/update! conn :icon
|
||||
;; {:deleted-at (dt/now)}
|
||||
;; {:id id})
|
||||
;; nil)))
|
||||
|
|
|
@ -1,273 +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/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2020 UXBOX Labs SL
|
||||
|
||||
(ns uxbox.services.mutations.images
|
||||
(:require
|
||||
[clojure.spec.alpha :as s]
|
||||
[datoteka.core :as fs]
|
||||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.config :as cfg]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.images :as images]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.services.mutations :as sm]
|
||||
[uxbox.services.queries.teams :as teams]
|
||||
[uxbox.tasks :as tasks]
|
||||
[uxbox.util.storage :as ust]
|
||||
[uxbox.util.time :as dt]))
|
||||
|
||||
(def thumbnail-options
|
||||
{:width 800
|
||||
:height 800
|
||||
:quality 85
|
||||
:format :jpeg})
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::file-id ::us/uuid)
|
||||
(s/def ::team-id ::us/uuid)
|
||||
(s/def ::url ::us/url)
|
||||
|
||||
;; --- Create Library
|
||||
|
||||
(declare create-library)
|
||||
|
||||
(s/def ::create-image-library
|
||||
(s/keys :req-un [::profile-id ::team-id ::name]
|
||||
:opt-un [::id]))
|
||||
|
||||
(sm/defmutation ::create-image-library
|
||||
[{:keys [profile-id team-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(teams/check-edition-permissions! conn profile-id team-id)
|
||||
(create-library conn params)))
|
||||
|
||||
(defn create-library
|
||||
[conn {:keys [id team-id name]}]
|
||||
(let [id (or id (uuid/next))]
|
||||
(db/insert! conn :image-library
|
||||
{:id id
|
||||
:team-id team-id
|
||||
:name name})))
|
||||
|
||||
|
||||
;; --- Rename Library
|
||||
|
||||
(declare select-file-for-update)
|
||||
|
||||
(s/def ::rename-image-library
|
||||
(s/keys :req-un [::id ::profile-id ::name]))
|
||||
|
||||
(sm/defmutation ::rename-image-library
|
||||
[{:keys [profile-id id name] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [lib (select-file-for-update conn id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id lib))
|
||||
(db/update! conn :image-library
|
||||
{:name name}
|
||||
{:id id}))))
|
||||
|
||||
(def ^:private sql:select-file-for-update
|
||||
"select file.*,
|
||||
project.team_id as team_id
|
||||
from file
|
||||
inner join project on (project.id = file.project_id)
|
||||
where file.id = ?
|
||||
for update of file")
|
||||
|
||||
(defn- select-file-for-update
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:select-file-for-update id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
|
||||
;; --- Delete Library
|
||||
|
||||
(declare delete-library)
|
||||
|
||||
(s/def ::delete-image-library
|
||||
(s/keys :req-un [::profile-id ::id]))
|
||||
|
||||
(sm/defmutation ::delete-image-library
|
||||
[{:keys [id profile-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [lib (select-file-for-update conn id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id lib))
|
||||
|
||||
;; Schedule object deletion
|
||||
(tasks/submit! conn {:name "delete-object"
|
||||
:delay cfg/default-deletion-delay
|
||||
:props {:id id :type :image-library}})
|
||||
|
||||
(db/update! conn :image-library
|
||||
{:deleted-at (dt/now)}
|
||||
{:id id})
|
||||
nil)))
|
||||
|
||||
|
||||
;; --- Create Image (Upload and create from url)
|
||||
|
||||
(declare create-image)
|
||||
(declare persist-image-on-fs)
|
||||
(declare persist-image-thumbnail-on-fs)
|
||||
|
||||
(def valid-image-types?
|
||||
#{"image/jpeg", "image/png", "image/webp", "image/svg+xml"})
|
||||
|
||||
(s/def :uxbox$upload/filename ::us/string)
|
||||
(s/def :uxbox$upload/size ::us/integer)
|
||||
(s/def :uxbox$upload/content-type valid-image-types?)
|
||||
(s/def :uxbox$upload/tempfile any?)
|
||||
|
||||
(s/def ::upload
|
||||
(s/keys :req-un [:uxbox$upload/filename
|
||||
:uxbox$upload/size
|
||||
:uxbox$upload/tempfile
|
||||
:uxbox$upload/content-type]))
|
||||
|
||||
(s/def ::content ::upload)
|
||||
|
||||
(s/def ::add-image-from-url
|
||||
(s/keys :req-un [::profile-id ::file-id ::url]
|
||||
:opt-un [::id]))
|
||||
|
||||
(s/def ::upload-image
|
||||
(s/keys :req-un [::profile-id ::file-id ::name ::content]
|
||||
:opt-un [::id]))
|
||||
|
||||
(sm/defmutation ::add-image-from-url
|
||||
[{:keys [profile-id file-id url] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [file (select-file-for-update conn file-id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id file))
|
||||
(let [content (images/download-image url)
|
||||
params' (merge params {:content content
|
||||
:name (:filename content)})]
|
||||
(create-image conn params')))))
|
||||
|
||||
(sm/defmutation ::upload-image
|
||||
[{:keys [profile-id file-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [file (select-file-for-update conn file-id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id file))
|
||||
(create-image conn params))))
|
||||
|
||||
(defn create-image
|
||||
[conn {:keys [id content file-id name]}]
|
||||
(when-not (valid-image-types? (:content-type content))
|
||||
(ex/raise :type :validation
|
||||
:code :image-type-not-allowed
|
||||
:hint "Seems like you are uploading an invalid image."))
|
||||
|
||||
(let [info (images/run {:cmd :info :input {:path (:tempfile content)
|
||||
:mtype (:content-type content)}})
|
||||
path (persist-image-on-fs content)
|
||||
opts (assoc thumbnail-options
|
||||
:input {:mtype (:mtype info)
|
||||
:path path})
|
||||
thumb (if-not (= (:mtype info) "image/svg+xml")
|
||||
(persist-image-thumbnail-on-fs opts)
|
||||
(assoc info
|
||||
:path path
|
||||
:quality 0))]
|
||||
|
||||
(-> (db/insert! conn :image
|
||||
{:id (or id (uuid/next))
|
||||
:file-id file-id
|
||||
:name name
|
||||
:path (str path)
|
||||
:width (:width info)
|
||||
:height (:height info)
|
||||
:mtype (:mtype info)
|
||||
:thumb-path (str (:path thumb))
|
||||
:thumb-width (:width thumb)
|
||||
:thumb-height (:height thumb)
|
||||
:thumb-quality (:quality thumb)
|
||||
:thumb-mtype (:mtype thumb)})
|
||||
(images/resolve-urls :path :uri)
|
||||
(images/resolve-urls :thumb-path :thumb-uri))))
|
||||
|
||||
(defn persist-image-on-fs
|
||||
[{:keys [filename tempfile]}]
|
||||
(let [filename (fs/name filename)]
|
||||
(ust/save! media/media-storage filename tempfile)))
|
||||
|
||||
(defn persist-image-thumbnail-on-fs
|
||||
[{:keys [input] :as params}]
|
||||
(let [path (ust/lookup media/media-storage (:path input))
|
||||
thumb (images/run
|
||||
(-> params
|
||||
(assoc :cmd :generic-thumbnail)
|
||||
(update :input assoc :path path)))
|
||||
|
||||
name (str "thumbnail-"
|
||||
(first (fs/split-ext (fs/name (:path input))))
|
||||
(images/format->extension (:format thumb)))
|
||||
path (ust/save! media/media-storage name (:data thumb))]
|
||||
|
||||
(-> thumb
|
||||
(dissoc :data :input)
|
||||
(assoc :path path))))
|
||||
|
||||
;; --- Mutation: Rename Image
|
||||
|
||||
(declare select-image-for-update)
|
||||
|
||||
(s/def ::rename-image
|
||||
(s/keys :req-un [::id ::profile-id ::name]))
|
||||
|
||||
(sm/defmutation ::rename-image
|
||||
[{:keys [id profile-id name] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [img (select-image-for-update conn id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id img))
|
||||
(db/update! conn :image
|
||||
{:name name}
|
||||
{:id id}))))
|
||||
|
||||
(def ^:private sql:select-image-for-update
|
||||
"select img.*,
|
||||
lib.team_id as team_id
|
||||
from image as img
|
||||
inner join image_library as lib on (lib.id = img.library_id)
|
||||
where img.id = ?
|
||||
for update of img")
|
||||
|
||||
(defn- select-image-for-update
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:select-image-for-update id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
;; --- Delete Image
|
||||
|
||||
(s/def ::delete-image
|
||||
(s/keys :req-un [::id ::profile-id]))
|
||||
|
||||
(sm/defmutation ::delete-image
|
||||
[{:keys [profile-id id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [img (select-image-for-update conn id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id img))
|
||||
|
||||
;; Schedule object deletion
|
||||
(tasks/submit! conn {:name "delete-object"
|
||||
:delay cfg/default-deletion-delay
|
||||
:props {:id id :type :image}})
|
||||
|
||||
(db/update! conn :image
|
||||
{:deleted-at (dt/now)}
|
||||
{:id id})
|
||||
nil)))
|
283
backend/src/uxbox/services/mutations/media.clj
Normal file
283
backend/src/uxbox/services/mutations/media.clj
Normal file
|
@ -0,0 +1,283 @@
|
|||
;; 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/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2020 UXBOX Labs SL
|
||||
|
||||
(ns uxbox.services.mutations.media
|
||||
(:require
|
||||
[clojure.spec.alpha :as s]
|
||||
[datoteka.core :as fs]
|
||||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.config :as cfg]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.services.mutations :as sm]
|
||||
[uxbox.services.queries.teams :as teams]
|
||||
[uxbox.tasks :as tasks]
|
||||
[uxbox.media-storage :as mst]
|
||||
[uxbox.util.storage :as ust]
|
||||
[uxbox.util.time :as dt]))
|
||||
|
||||
(def thumbnail-options
|
||||
{:width 800
|
||||
:height 800
|
||||
:quality 85
|
||||
:format :jpeg})
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::file-id ::us/uuid)
|
||||
(s/def ::team-id ::us/uuid)
|
||||
(s/def ::url ::us/url)
|
||||
|
||||
;; ;; --- Create Library
|
||||
;;
|
||||
;; (declare create-library)
|
||||
;;
|
||||
;; (s/def ::create-media-object-library
|
||||
;; (s/keys :req-un [::profile-id ::team-id ::name]
|
||||
;; :opt-un [::id]))
|
||||
;;
|
||||
;; (sm/defmutation ::create-media-object-library
|
||||
;; [{:keys [profile-id team-id] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (teams/check-edition-permissions! conn profile-id team-id)
|
||||
;; (create-library conn params)))
|
||||
;;
|
||||
;; (defn create-library
|
||||
;; [conn {:keys [id team-id name]}]
|
||||
;; (let [id (or id (uuid/next))]
|
||||
;; (db/insert! conn :media-object-library
|
||||
;; {:id id
|
||||
;; :team-id team-id
|
||||
;; :name name})))
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Rename Library
|
||||
;;
|
||||
;; (s/def ::rename-media-object-library
|
||||
;; (s/keys :req-un [::id ::profile-id ::name]))
|
||||
;;
|
||||
;; (sm/defmutation ::rename-media-object-library
|
||||
;; [{:keys [profile-id id name] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (let [lib (select-file-for-update conn id)]
|
||||
;; (teams/check-edition-permissions! conn profile-id (:team-id lib))
|
||||
;; (db/update! conn :media-object-library
|
||||
;; {:name name}
|
||||
;; {:id id}))))
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Delete Library
|
||||
;;
|
||||
;; (declare delete-library)
|
||||
;;
|
||||
;; (s/def ::delete-media-object-library
|
||||
;; (s/keys :req-un [::profile-id ::id]))
|
||||
;;
|
||||
;; (sm/defmutation ::delete-media-object-library
|
||||
;; [{:keys [id profile-id] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (let [lib (select-file-for-update conn id)]
|
||||
;; (teams/check-edition-permissions! conn profile-id (:team-id lib))
|
||||
;;
|
||||
;; ;; Schedule object deletion
|
||||
;; (tasks/submit! conn {:name "delete-object"
|
||||
;; :delay cfg/default-deletion-delay
|
||||
;; :props {:id id :type :media-object-library}})
|
||||
;;
|
||||
;; (db/update! conn :media-object-library
|
||||
;; {:deleted-at (dt/now)}
|
||||
;; {:id id})
|
||||
;; nil)))
|
||||
|
||||
|
||||
;; --- Create Media object (Upload and create from url)
|
||||
|
||||
(declare create-media-object)
|
||||
(declare select-file-for-update)
|
||||
(declare persist-media-object-on-fs)
|
||||
(declare persist-media-thumbnail-on-fs)
|
||||
|
||||
(def valid-media-object-types?
|
||||
#{"image/jpeg", "image/png", "image/webp", "image/svg+xml"})
|
||||
|
||||
(s/def :uxbox$upload/filename ::us/string)
|
||||
(s/def :uxbox$upload/size ::us/integer)
|
||||
(s/def :uxbox$upload/content-type valid-media-object-types?)
|
||||
(s/def :uxbox$upload/tempfile any?)
|
||||
|
||||
(s/def ::upload
|
||||
(s/keys :req-un [:uxbox$upload/filename
|
||||
:uxbox$upload/size
|
||||
:uxbox$upload/tempfile
|
||||
:uxbox$upload/content-type]))
|
||||
|
||||
(s/def ::content ::upload)
|
||||
|
||||
(s/def ::is-local boolean?)
|
||||
|
||||
(s/def ::add-media-object-from-url
|
||||
(s/keys :req-un [::profile-id ::file-id ::url ::is-local]
|
||||
:opt-un [::id]))
|
||||
|
||||
(s/def ::upload-media-object
|
||||
(s/keys :req-un [::profile-id ::file-id ::name ::content ::is-local]
|
||||
:opt-un [::id]))
|
||||
|
||||
(sm/defmutation ::add-media-object-from-url
|
||||
[{:keys [profile-id file-id url] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [file (select-file-for-update conn file-id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id file))
|
||||
(let [content (media/download-media-object url)
|
||||
params' (merge params {:content content
|
||||
:name (:filename content)})]
|
||||
(create-media-object conn params')))))
|
||||
|
||||
(sm/defmutation ::upload-media-object
|
||||
[{:keys [profile-id file-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [file (select-file-for-update conn file-id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id file))
|
||||
(create-media-object conn params))))
|
||||
|
||||
(defn create-media-object
|
||||
[conn {:keys [id content file-id name is-local]}]
|
||||
(when-not (valid-media-object-types? (:content-type content))
|
||||
(ex/raise :type :validation
|
||||
:code :media-type-not-allowed
|
||||
:hint "Seems like you are uploading an invalid media object."))
|
||||
|
||||
(let [info (media/run {:cmd :info :input {:path (:tempfile content)
|
||||
:mtype (:content-type content)}})
|
||||
path (persist-media-object-on-fs content)
|
||||
opts (assoc thumbnail-options
|
||||
:input {:mtype (:mtype info)
|
||||
:path path})
|
||||
thumb (if-not (= (:mtype info) "image/svg+xml")
|
||||
(persist-media-thumbnail-on-fs opts)
|
||||
(assoc info
|
||||
:path path
|
||||
:quality 0))
|
||||
|
||||
media-object-id (or id (uuid/next))
|
||||
|
||||
media-object (-> (db/insert! conn :media-object
|
||||
{:id media-object-id
|
||||
:file-id file-id
|
||||
:is-local is-local
|
||||
:name name
|
||||
:path (str path)
|
||||
:width (:width info)
|
||||
:height (:height info)
|
||||
:mtype (:mtype info)})
|
||||
(media/resolve-urls :path :uri)
|
||||
(media/resolve-urls :thumb-path :thumb-uri))
|
||||
|
||||
media-thumbnail (db/insert! conn :media-thumbnail
|
||||
{:id (uuid/next)
|
||||
:media-object-id media-object-id
|
||||
:path (str (:path thumb))
|
||||
:width (:width thumb)
|
||||
:height (:height thumb)
|
||||
:quality (:quality thumb)
|
||||
:mtype (:mtype thumb)})]
|
||||
media-object))
|
||||
|
||||
(def ^:private sql:select-file-for-update
|
||||
"select file.*,
|
||||
project.team_id as team_id
|
||||
from file
|
||||
inner join project on (project.id = file.project_id)
|
||||
where file.id = ?
|
||||
for update of file")
|
||||
|
||||
(defn- select-file-for-update
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:select-file-for-update id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
(defn persist-media-object-on-fs
|
||||
[{:keys [filename tempfile]}]
|
||||
(let [filename (fs/name filename)]
|
||||
(ust/save! mst/media-storage filename tempfile)))
|
||||
|
||||
(defn persist-media-thumbnail-on-fs
|
||||
[{:keys [input] :as params}]
|
||||
(let [path (ust/lookup mst/media-storage (:path input))
|
||||
thumb (media/run
|
||||
(-> params
|
||||
(assoc :cmd :generic-thumbnail)
|
||||
(update :input assoc :path path)))
|
||||
|
||||
name (str "thumbnail-"
|
||||
(first (fs/split-ext (fs/name (:path input))))
|
||||
(media/format->extension (:format thumb)))
|
||||
path (ust/save! mst/media-storage name (:data thumb))]
|
||||
|
||||
(-> thumb
|
||||
(dissoc :data :input)
|
||||
(assoc :path path))))
|
||||
|
||||
;; --- Mutation: Rename Media object
|
||||
|
||||
(declare select-media-object-for-update)
|
||||
|
||||
(s/def ::rename-media-object
|
||||
(s/keys :req-un [::id ::profile-id ::name]))
|
||||
|
||||
(sm/defmutation ::rename-media-object
|
||||
[{:keys [id profile-id name] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [obj (select-media-object-for-update conn id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id obj))
|
||||
(db/update! conn :media-object
|
||||
{:name name}
|
||||
{:id id}))))
|
||||
|
||||
(def ^:private sql:select-media-object-for-update
|
||||
"select obj.*,
|
||||
p.team_id as team_id
|
||||
from media_object as obj
|
||||
inner join file as f on (f.id = obj.file_id)
|
||||
inner join project as p on (p.id = f.project_id)
|
||||
where obj.id = ?
|
||||
for update of obj")
|
||||
|
||||
(defn- select-media-object-for-update
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:select-media-object-for-update id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
;; --- Delete Media object
|
||||
|
||||
(s/def ::delete-media-object
|
||||
(s/keys :req-un [::id ::profile-id]))
|
||||
|
||||
(sm/defmutation ::delete-media-object
|
||||
[{:keys [profile-id id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [obj (select-media-object-for-update conn id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id obj))
|
||||
|
||||
;; Schedule object deletion
|
||||
(tasks/submit! conn {:name "delete-object"
|
||||
:delay cfg/default-deletion-delay
|
||||
:props {:id id :type :media-object}})
|
||||
|
||||
(db/update! conn :media-object
|
||||
{:deleted-at (dt/now)}
|
||||
{:id id})
|
||||
nil)))
|
|
@ -23,11 +23,11 @@
|
|||
[uxbox.config :as cfg]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.emails :as emails]
|
||||
[uxbox.images :as images]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.media-storage :as mst]
|
||||
[uxbox.services.tokens :as tokens]
|
||||
[uxbox.services.mutations :as sm]
|
||||
[uxbox.services.mutations.images :as imgs]
|
||||
[uxbox.services.mutations.media :as media-mutations]
|
||||
[uxbox.services.mutations.projects :as projects]
|
||||
[uxbox.services.mutations.teams :as teams]
|
||||
[uxbox.services.queries.profile :as profile]
|
||||
|
@ -266,20 +266,20 @@
|
|||
(declare upload-photo)
|
||||
(declare update-profile-photo)
|
||||
|
||||
(s/def ::file ::imgs/upload)
|
||||
(s/def ::file ::media-mutations/upload)
|
||||
(s/def ::update-profile-photo
|
||||
(s/keys :req-un [::profile-id ::file]))
|
||||
|
||||
(sm/defmutation ::update-profile-photo
|
||||
[{:keys [profile-id file] :as params}]
|
||||
(when-not (imgs/valid-image-types? (:content-type file))
|
||||
(when-not (media-mutations/valid-media-object-types? (:content-type file))
|
||||
(ex/raise :type :validation
|
||||
:code :image-type-not-allowed
|
||||
:hint "Seems like you are uploading an invalid image."))
|
||||
:code :media-type-not-allowed
|
||||
:hint "Seems like you are uploading an invalid media object"))
|
||||
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [profile (profile/retrieve-profile conn profile-id)
|
||||
_ (images/run {:cmd :info :input {:path (:tempfile file)
|
||||
_ (media/run {:cmd :info :input {:path (:tempfile file)
|
||||
:mtype (:content-type file)}})
|
||||
photo (upload-photo conn params)]
|
||||
|
||||
|
@ -295,7 +295,7 @@
|
|||
[conn {:keys [file profile-id]}]
|
||||
(let [prefix (-> (sodi.prng/random-bytes 8)
|
||||
(sodi.util/bytes->b64s))
|
||||
thumb (images/run
|
||||
thumb (media/run
|
||||
{:cmd :profile-thumbnail
|
||||
:format :jpeg
|
||||
:quality 85
|
||||
|
@ -303,8 +303,8 @@
|
|||
:height 256
|
||||
:input {:path (fs/path (:tempfile file))
|
||||
:mtype (:content-type file)}})
|
||||
name (str prefix (images/format->extension (:format thumb)))]
|
||||
(ust/save! media/media-storage name (:data thumb))))
|
||||
name (str prefix (media/format->extension (:format thumb)))]
|
||||
(ust/save! mst/media-storage name (:data thumb))))
|
||||
|
||||
(defn- update-profile-photo
|
||||
[conn profile-id path]
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
[uxbox.common.spec :as us]
|
||||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.images :as images]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.services.queries :as sq]
|
||||
[uxbox.services.queries.teams :as teams]
|
||||
[uxbox.util.blob :as blob]
|
||||
|
@ -29,59 +27,60 @@
|
|||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::team-id ::us/uuid)
|
||||
(s/def ::file-id ::us/uuid)
|
||||
(s/def ::library-id (s/nilable ::us/uuid))
|
||||
;; (s/def ::library-id (s/nilable ::us/uuid))
|
||||
|
||||
;; --- Query: Colors Libraries
|
||||
|
||||
(def ^:private sql:libraries
|
||||
"select lib.*,
|
||||
(select count(*) from color where library_id = lib.id) as num_colors
|
||||
from color_library as lib
|
||||
where lib.team_id = ?
|
||||
and lib.deleted_at is null
|
||||
order by lib.created_at desc")
|
||||
|
||||
(s/def ::color-libraries
|
||||
(s/keys :req-un [::profile-id ::team-id]))
|
||||
|
||||
(sq/defquery ::color-libraries
|
||||
[{:keys [profile-id team-id]}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(teams/check-read-permissions! conn profile-id team-id)
|
||||
(db/exec! conn [sql:libraries team-id])))
|
||||
|
||||
|
||||
;; --- Query: Color Library
|
||||
|
||||
(declare retrieve-library)
|
||||
|
||||
(s/def ::color-library
|
||||
(s/keys :req-un [::profile-id ::id]))
|
||||
|
||||
(sq/defquery ::color-library
|
||||
[{:keys [profile-id id]}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [lib (retrieve-library conn id)]
|
||||
(teams/check-read-permissions! conn profile-id (:team-id lib))
|
||||
lib)))
|
||||
|
||||
(def ^:private sql:single-library
|
||||
"select lib.*,
|
||||
(select count(*) from color where library_id = lib.id) as num_colors
|
||||
from color_library as lib
|
||||
where lib.deleted_at is null
|
||||
and lib.id = ?")
|
||||
|
||||
(defn- retrieve-library
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:single-library id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
;; ;; --- Query: Colors Libraries
|
||||
;;
|
||||
;; (def ^:private sql:libraries
|
||||
;; "select lib.*,
|
||||
;; (select count(*) from color where library_id = lib.id) as num_colors
|
||||
;; from color_library as lib
|
||||
;; where lib.team_id = ?
|
||||
;; and lib.deleted_at is null
|
||||
;; order by lib.created_at desc")
|
||||
;;
|
||||
;; (s/def ::color-libraries
|
||||
;; (s/keys :req-un [::profile-id ::team-id]))
|
||||
;;
|
||||
;; (sq/defquery ::color-libraries
|
||||
;; [{:keys [profile-id team-id]}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (teams/check-read-permissions! conn profile-id team-id)
|
||||
;; (db/exec! conn [sql:libraries team-id])))
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Query: Color Library
|
||||
;;
|
||||
;; (declare retrieve-library)
|
||||
;;
|
||||
;; (s/def ::color-library
|
||||
;; (s/keys :req-un [::profile-id ::id]))
|
||||
;;
|
||||
;; (sq/defquery ::color-library
|
||||
;; [{:keys [profile-id id]}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (let [lib (retrieve-library conn id)]
|
||||
;; (teams/check-read-permissions! conn profile-id (:team-id lib))
|
||||
;; lib)))
|
||||
;;
|
||||
;; (def ^:private sql:single-library
|
||||
;; "select lib.*,
|
||||
;; (select count(*) from color where library_id = lib.id) as num_colors
|
||||
;; from color_library as lib
|
||||
;; where lib.deleted_at is null
|
||||
;; and lib.id = ?")
|
||||
;;
|
||||
;; (defn- retrieve-library
|
||||
;; [conn id]
|
||||
;; (let [row (db/exec-one! conn [sql:single-library id])]
|
||||
;; (when-not row
|
||||
;; (ex/raise :type :not-found))
|
||||
;; row))
|
||||
|
||||
;; --- Query: Colors (by file)
|
||||
|
||||
(declare retrieve-colors)
|
||||
(declare retrieve-file)
|
||||
|
||||
(s/def ::colors
|
||||
(s/keys :req-un [::profile-id ::file-id]))
|
||||
|
@ -89,10 +88,9 @@
|
|||
(sq/defquery ::colors
|
||||
[{:keys [profile-id file-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(retrieve-colors conn file-id)))
|
||||
;; (let [lib (retrieve-library conn library-id)]
|
||||
;; (teams/check-read-permissions! conn profile-id (:team-id lib))
|
||||
;; (retrieve-colors conn library-id))))
|
||||
(let [file (retrieve-file conn file-id)]
|
||||
(teams/check-read-permissions! conn profile-id (:team-id file))
|
||||
(retrieve-colors conn file-id))))
|
||||
|
||||
(def ^:private sql:colors
|
||||
"select *
|
||||
|
@ -105,6 +103,20 @@
|
|||
[conn file-id]
|
||||
(db/exec! conn [sql:colors file-id]))
|
||||
|
||||
(def ^:private sql:retrieve-file
|
||||
"select file.*,
|
||||
project.team_id as team_id
|
||||
from file
|
||||
inner join project on (project.id = file.project_id)
|
||||
where file.id = ?")
|
||||
|
||||
(defn- retrieve-file
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:retrieve-file id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
|
||||
;; --- Query: Color (by ID)
|
||||
|
||||
|
@ -123,9 +135,10 @@
|
|||
|
||||
(def ^:private sql:single-color
|
||||
"select color.*,
|
||||
lib.team_id as team_id
|
||||
p.team_id as team_id
|
||||
from color as color
|
||||
inner join color_library as lib on (lib.id = color.library_id)
|
||||
inner join file as f on (color.file_id = f.id)
|
||||
inner join project as p on (p.id = f.project_id)
|
||||
where color.deleted_at is null
|
||||
and color.id = ?
|
||||
order by created_at desc")
|
||||
|
@ -136,3 +149,4 @@
|
|||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.images :as images]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.services.queries :as sq]
|
||||
[uxbox.util.blob :as blob]))
|
||||
|
||||
|
@ -220,32 +220,32 @@
|
|||
(ex/raise :type :validation
|
||||
:code :not-authorized))))
|
||||
|
||||
;; --- Query: Images of the File
|
||||
|
||||
(declare retrieve-file-images)
|
||||
|
||||
(s/def ::file-images
|
||||
(s/keys :req-un [::profile-id ::file-id]))
|
||||
|
||||
(sq/defquery ::file-images
|
||||
[{:keys [profile-id file-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(check-edition-permissions! conn profile-id file-id)
|
||||
(retrieve-file-images conn params)))
|
||||
|
||||
(def ^:private sql:file-images
|
||||
"select fi.*
|
||||
from file_image as fi
|
||||
where fi.file_id = ?
|
||||
and fi.deleted_at is null")
|
||||
|
||||
(defn retrieve-file-images
|
||||
[conn {:keys [file-id] :as params}]
|
||||
(let [sqlv [sql:file-images file-id]
|
||||
xf (comp (map #(images/resolve-urls % :path :uri))
|
||||
(map #(images/resolve-urls % :thumb-path :thumb-uri)))]
|
||||
(->> (db/exec! conn sqlv)
|
||||
(into [] xf))))
|
||||
;; ;; --- Query: Images of the File
|
||||
;;
|
||||
;; (declare retrieve-file-images)
|
||||
;;
|
||||
;; (s/def ::file-images
|
||||
;; (s/keys :req-un [::profile-id ::file-id]))
|
||||
;;
|
||||
;; (sq/defquery ::file-images
|
||||
;; [{:keys [profile-id file-id] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (check-edition-permissions! conn profile-id file-id)
|
||||
;; (retrieve-file-images conn params)))
|
||||
;;
|
||||
;; (def ^:private sql:file-images
|
||||
;; "select fi.*
|
||||
;; from file_image as fi
|
||||
;; where fi.file_id = ?
|
||||
;; and fi.deleted_at is null")
|
||||
;;
|
||||
;; (defn retrieve-file-images
|
||||
;; [conn {:keys [file-id] :as params}]
|
||||
;; (let [sqlv [sql:file-images file-id]
|
||||
;; xf (comp (map #(media/resolve-urls % :path :uri))
|
||||
;; (map #(media/resolve-urls % :thumb-path :thumb-uri)))]
|
||||
;; (->> (db/exec! conn sqlv)
|
||||
;; (into [] xf))))
|
||||
|
||||
;; --- Query: File (By ID)
|
||||
|
||||
|
@ -284,7 +284,7 @@
|
|||
(defn retrieve-file-users
|
||||
[conn id]
|
||||
(->> (db/exec! conn [sql:file-users id id])
|
||||
(mapv #(images/resolve-media-uris % [:photo :photo-uri]))))
|
||||
(mapv #(media/resolve-media-uris % [:photo :photo-uri]))))
|
||||
|
||||
(s/def ::file-users
|
||||
(s/keys :req-un [::profile-id ::id]))
|
||||
|
|
|
@ -1,148 +1,148 @@
|
|||
;; 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/.
|
||||
;; ;; 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/.
|
||||
;; ;;
|
||||
;; ;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; ;; defined by the Mozilla Public License, v. 2.0.
|
||||
;; ;;
|
||||
;; ;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;; (ns uxbox.services.queries.icons
|
||||
;; (:require
|
||||
;; [clojure.spec.alpha :as s]
|
||||
;; [uxbox.common.exceptions :as ex]
|
||||
;; [uxbox.common.spec :as us]
|
||||
;; [uxbox.common.uuid :as uuid]
|
||||
;; [uxbox.db :as db]
|
||||
;; [uxbox.images :as images]
|
||||
;; [uxbox.media :as media]
|
||||
;; [uxbox.services.queries :as sq]
|
||||
;; [uxbox.services.queries.teams :as teams]
|
||||
;; [uxbox.util.blob :as blob]
|
||||
;; [uxbox.util.data :as data]))
|
||||
;;
|
||||
;; ;; --- Helpers & Specs
|
||||
;;
|
||||
;; (s/def ::id ::us/uuid)
|
||||
;; (s/def ::name ::us/string)
|
||||
;; (s/def ::profile-id ::us/uuid)
|
||||
;; (s/def ::library-id ::us/uuid)
|
||||
;; (s/def ::team-id ::us/uuid)
|
||||
;;
|
||||
;; (defn decode-row
|
||||
;; [{:keys [metadata] :as row}]
|
||||
;; (when row
|
||||
;; (cond-> row
|
||||
;; metadata (assoc :metadata (blob/decode metadata)))))
|
||||
;;
|
||||
;; ;; --- Query: Icons Librarys
|
||||
;;
|
||||
;; (def ^:private sql:libraries
|
||||
;; "select lib.*,
|
||||
;; (select count(*) from icon where library_id = lib.id) as num_icons
|
||||
;; from icon_library as lib
|
||||
;; where lib.team_id = ?
|
||||
;; and lib.deleted_at is null
|
||||
;; order by lib.created_at desc")
|
||||
;;
|
||||
;; (s/def ::icon-libraries
|
||||
;; (s/keys :req-un [::profile-id ::team-id]))
|
||||
;;
|
||||
;; (sq/defquery ::icon-libraries
|
||||
;; [{:keys [profile-id team-id]}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (teams/check-read-permissions! conn profile-id team-id)
|
||||
;; (db/exec! conn [sql:libraries team-id])))
|
||||
;;
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Query: Icon Library
|
||||
;;
|
||||
;; (declare retrieve-library)
|
||||
;;
|
||||
;; (s/def ::icon-library
|
||||
;; (s/keys :req-un [::profile-id ::id]))
|
||||
;;
|
||||
;; (sq/defquery ::icon-library
|
||||
;; [{:keys [profile-id id]}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (let [lib (retrieve-library conn id)]
|
||||
;; (teams/check-read-permissions! conn profile-id (:team-id lib))
|
||||
;; lib)))
|
||||
;;
|
||||
;; (def ^:private sql:single-library
|
||||
;; "select lib.*,
|
||||
;; (select count(*) from icon where library_id = lib.id) as num_icons
|
||||
;; from icon_library as lib
|
||||
;; where lib.deleted_at is null
|
||||
;; and lib.id = ?")
|
||||
;;
|
||||
;; (defn- retrieve-library
|
||||
;; [conn id]
|
||||
;; (let [row (db/exec-one! conn [sql:single-library id])]
|
||||
;; (when-not row
|
||||
;; (ex/raise :type :not-found))
|
||||
;; row))
|
||||
;;
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Query: Icons (by library)
|
||||
;;
|
||||
;; (declare retrieve-icons)
|
||||
;;
|
||||
;; (s/def ::icons
|
||||
;; (s/keys :req-un [::profile-id ::library-id]))
|
||||
;;
|
||||
;; (sq/defquery ::icons
|
||||
;; [{:keys [profile-id library-id] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (let [lib (retrieve-library conn library-id)]
|
||||
;; (teams/check-read-permissions! conn profile-id (:team-id lib))
|
||||
;; (->> (retrieve-icons conn library-id)
|
||||
;; (mapv decode-row)))))
|
||||
;;
|
||||
;; (def ^:private sql:icons
|
||||
;; "select icon.*
|
||||
;; from icon as icon
|
||||
;; inner join icon_library as lib on (lib.id = icon.library_id)
|
||||
;; where icon.deleted_at is null
|
||||
;; and icon.library_id = ?
|
||||
;; order by created_at desc")
|
||||
;;
|
||||
;; (defn- retrieve-icons
|
||||
;; [conn library-id]
|
||||
;; (db/exec! conn [sql:icons library-id]))
|
||||
;;
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Query: Icon (by ID)
|
||||
;;
|
||||
;; (declare retrieve-icon)
|
||||
;;
|
||||
;; (s/def ::id ::us/uuid)
|
||||
;; (s/def ::icon
|
||||
;; (s/keys :req-un [::profile-id ::id]))
|
||||
;;
|
||||
;; (sq/defquery ::icon
|
||||
;; [{:keys [profile-id id] :as params}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (let [icon (retrieve-icon conn id)]
|
||||
;; (teams/check-read-permissions! conn profile-id (:team-id icon))
|
||||
;; (decode-row icon))))
|
||||
;;
|
||||
;; (def ^:private sql:single-icon
|
||||
;; "select icon.*,
|
||||
;; lib.team_id as team_id
|
||||
;; from icon as icon
|
||||
;; inner join icon_library as lib on (lib.id = icon.library_id)
|
||||
;; where icon.deleted_at is null
|
||||
;; and icon.id = ?
|
||||
;; order by created_at desc")
|
||||
;;
|
||||
;; (defn retrieve-icon
|
||||
;; [conn id]
|
||||
;; (let [row (db/exec-one! conn [sql:single-icon id])]
|
||||
;; (when-not row
|
||||
;; (ex/raise :type :not-found))
|
||||
;; row))
|
||||
;;
|
||||
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.services.queries.icons
|
||||
(:require
|
||||
[clojure.spec.alpha :as s]
|
||||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.images :as images]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.services.queries :as sq]
|
||||
[uxbox.services.queries.teams :as teams]
|
||||
[uxbox.util.blob :as blob]
|
||||
[uxbox.util.data :as data]))
|
||||
|
||||
;; --- Helpers & Specs
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::library-id ::us/uuid)
|
||||
(s/def ::team-id ::us/uuid)
|
||||
|
||||
(defn decode-row
|
||||
[{:keys [metadata] :as row}]
|
||||
(when row
|
||||
(cond-> row
|
||||
metadata (assoc :metadata (blob/decode metadata)))))
|
||||
|
||||
;; --- Query: Icons Librarys
|
||||
|
||||
(def ^:private sql:libraries
|
||||
"select lib.*,
|
||||
(select count(*) from icon where library_id = lib.id) as num_icons
|
||||
from icon_library as lib
|
||||
where lib.team_id = ?
|
||||
and lib.deleted_at is null
|
||||
order by lib.created_at desc")
|
||||
|
||||
(s/def ::icon-libraries
|
||||
(s/keys :req-un [::profile-id ::team-id]))
|
||||
|
||||
(sq/defquery ::icon-libraries
|
||||
[{:keys [profile-id team-id]}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(teams/check-read-permissions! conn profile-id team-id)
|
||||
(db/exec! conn [sql:libraries team-id])))
|
||||
|
||||
|
||||
|
||||
;; --- Query: Icon Library
|
||||
|
||||
(declare retrieve-library)
|
||||
|
||||
(s/def ::icon-library
|
||||
(s/keys :req-un [::profile-id ::id]))
|
||||
|
||||
(sq/defquery ::icon-library
|
||||
[{:keys [profile-id id]}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [lib (retrieve-library conn id)]
|
||||
(teams/check-read-permissions! conn profile-id (:team-id lib))
|
||||
lib)))
|
||||
|
||||
(def ^:private sql:single-library
|
||||
"select lib.*,
|
||||
(select count(*) from icon where library_id = lib.id) as num_icons
|
||||
from icon_library as lib
|
||||
where lib.deleted_at is null
|
||||
and lib.id = ?")
|
||||
|
||||
(defn- retrieve-library
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:single-library id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
|
||||
|
||||
;; --- Query: Icons (by library)
|
||||
|
||||
(declare retrieve-icons)
|
||||
|
||||
(s/def ::icons
|
||||
(s/keys :req-un [::profile-id ::library-id]))
|
||||
|
||||
(sq/defquery ::icons
|
||||
[{:keys [profile-id library-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [lib (retrieve-library conn library-id)]
|
||||
(teams/check-read-permissions! conn profile-id (:team-id lib))
|
||||
(->> (retrieve-icons conn library-id)
|
||||
(mapv decode-row)))))
|
||||
|
||||
(def ^:private sql:icons
|
||||
"select icon.*
|
||||
from icon as icon
|
||||
inner join icon_library as lib on (lib.id = icon.library_id)
|
||||
where icon.deleted_at is null
|
||||
and icon.library_id = ?
|
||||
order by created_at desc")
|
||||
|
||||
(defn- retrieve-icons
|
||||
[conn library-id]
|
||||
(db/exec! conn [sql:icons library-id]))
|
||||
|
||||
|
||||
|
||||
;; --- Query: Icon (by ID)
|
||||
|
||||
(declare retrieve-icon)
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::icon
|
||||
(s/keys :req-un [::profile-id ::id]))
|
||||
|
||||
(sq/defquery ::icon
|
||||
[{:keys [profile-id id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [icon (retrieve-icon conn id)]
|
||||
(teams/check-read-permissions! conn profile-id (:team-id icon))
|
||||
(decode-row icon))))
|
||||
|
||||
(def ^:private sql:single-icon
|
||||
"select icon.*,
|
||||
lib.team_id as team_id
|
||||
from icon as icon
|
||||
inner join icon_library as lib on (lib.id = icon.library_id)
|
||||
where icon.deleted_at is null
|
||||
and icon.id = ?
|
||||
order by created_at desc")
|
||||
|
||||
(defn retrieve-icon
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:single-icon id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
|
|
|
@ -1,144 +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/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2019-2020 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.services.queries.images
|
||||
(:require
|
||||
[clojure.spec.alpha :as s]
|
||||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.images :as images]
|
||||
[uxbox.services.queries :as sq]
|
||||
[uxbox.services.queries.teams :as teams]))
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::team-id ::us/uuid)
|
||||
(s/def ::file-id ::us/uuid)
|
||||
|
||||
;; --- Query: Image Librarys
|
||||
|
||||
(def ^:private sql:libraries
|
||||
"select lib.*,
|
||||
(select count(*) from image where library_id = lib.id) as num_images
|
||||
from image_library as lib
|
||||
where lib.team_id = ?
|
||||
and lib.deleted_at is null
|
||||
order by lib.created_at desc")
|
||||
|
||||
(s/def ::image-libraries
|
||||
(s/keys :req-un [::profile-id ::team-id]))
|
||||
|
||||
(sq/defquery ::image-libraries
|
||||
[{:keys [profile-id team-id]}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(teams/check-read-permissions! conn profile-id team-id)
|
||||
(db/exec! conn [sql:libraries team-id])))
|
||||
|
||||
|
||||
;; --- Query: Image Library
|
||||
|
||||
(declare retrieve-library)
|
||||
|
||||
(s/def ::image-library
|
||||
(s/keys :req-un [::profile-id ::id]))
|
||||
|
||||
(sq/defquery ::image-library
|
||||
[{:keys [profile-id id]}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [lib (retrieve-library conn id)]
|
||||
(teams/check-read-permissions! conn profile-id (:team-id lib))
|
||||
lib)))
|
||||
|
||||
(def ^:private sql:single-library
|
||||
"select lib.*,
|
||||
(select count(*) from image where library_id = lib.id) as num_images
|
||||
from image_library as lib
|
||||
where lib.deleted_at is null
|
||||
and lib.id = ?")
|
||||
|
||||
(defn- retrieve-library
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:single-library id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
|
||||
;; --- Query: Images (by library)
|
||||
|
||||
(declare retrieve-images)
|
||||
|
||||
(s/def ::images
|
||||
(s/keys :req-un [::profile-id ::file-id]))
|
||||
|
||||
;; TODO: check if we can resolve url with transducer for reduce
|
||||
;; garbage generation for each request
|
||||
|
||||
(sq/defquery ::images
|
||||
[{:keys [profile-id file-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(->> (retrieve-images conn file-id)
|
||||
(mapv #(images/resolve-urls % :path :uri))
|
||||
(mapv #(images/resolve-urls % :thumb-path :thumb-uri)))))
|
||||
;; (let [lib (retrieve-library conn file-id)]
|
||||
;; (teams/check-read-permissions! conn profile-id (:team-id lib))
|
||||
;; (->> (retrieve-images conn file-id)
|
||||
;; (mapv #(images/resolve-urls % :path :uri))
|
||||
;; (mapv #(images/resolve-urls % :thumb-path :thumb-uri))))))
|
||||
|
||||
|
||||
(def ^:private sql:images
|
||||
"select *
|
||||
from image as img
|
||||
where img.deleted_at is null
|
||||
and img.file_id = ?
|
||||
order by created_at desc")
|
||||
|
||||
(defn- retrieve-images
|
||||
[conn file-id]
|
||||
(db/exec! conn [sql:images file-id]))
|
||||
|
||||
|
||||
|
||||
;; --- Query: Image (by ID)
|
||||
|
||||
(declare retrieve-image)
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::image
|
||||
(s/keys :req-un [::profile-id ::id]))
|
||||
|
||||
(sq/defquery ::image
|
||||
[{:keys [profile-id id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [img (retrieve-image conn id)]
|
||||
(teams/check-read-permissions! conn profile-id (:team-id img))
|
||||
(-> img
|
||||
(images/resolve-urls :path :uri)
|
||||
(images/resolve-urls :thumb-path :thumb-uri)))))
|
||||
|
||||
(def ^:private sql:single-image
|
||||
"select img.*,
|
||||
file.team_id as team_id
|
||||
from image as img
|
||||
inner join file on (file.id = img.file_id)
|
||||
where img.deleted_at is null
|
||||
and img.id = ?
|
||||
order by created_at desc")
|
||||
|
||||
(defn retrieve-image
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:single-image id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
|
154
backend/src/uxbox/services/queries/media.clj
Normal file
154
backend/src/uxbox/services/queries/media.clj
Normal file
|
@ -0,0 +1,154 @@
|
|||
;; 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/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2019-2020 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.services.queries.media
|
||||
(:require
|
||||
[clojure.spec.alpha :as s]
|
||||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.services.queries :as sq]
|
||||
[uxbox.services.queries.teams :as teams]))
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::team-id ::us/uuid)
|
||||
(s/def ::file-id ::us/uuid)
|
||||
|
||||
;; ;; --- Query: Media Libraries
|
||||
;;
|
||||
;; (def ^:private sql:libraries
|
||||
;; "select lib.*,
|
||||
;; (select count(*) from media where library_id = lib.id) as num_media
|
||||
;; from media_library as lib
|
||||
;; where lib.team_id = ?
|
||||
;; and lib.deleted_at is null
|
||||
;; order by lib.created_at desc")
|
||||
;;
|
||||
;; (s/def ::media-libraries
|
||||
;; (s/keys :req-un [::profile-id ::team-id]))
|
||||
;;
|
||||
;; (sq/defquery ::media-libraries
|
||||
;; [{:keys [profile-id team-id]}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (teams/check-read-permissions! conn profile-id team-id)
|
||||
;; (db/exec! conn [sql:libraries team-id])))
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Query: Media Library
|
||||
;;
|
||||
;; (declare retrieve-library)
|
||||
;;
|
||||
;; (s/def ::media-library
|
||||
;; (s/keys :req-un [::profile-id ::id]))
|
||||
;;
|
||||
;; (sq/defquery ::media-library
|
||||
;; [{:keys [profile-id id]}]
|
||||
;; (db/with-atomic [conn db/pool]
|
||||
;; (let [lib (retrieve-library conn id)]
|
||||
;; (teams/check-read-permissions! conn profile-id (:team-id lib))
|
||||
;; lib)))
|
||||
;;
|
||||
;; (def ^:private sql:single-library
|
||||
;; "select lib.*,
|
||||
;; (select count(*) from media where library_id = lib.id) as num_media
|
||||
;; from media_library as lib
|
||||
;; where lib.deleted_at is null
|
||||
;; and lib.id = ?")
|
||||
;;
|
||||
;; (defn- retrieve-library
|
||||
;; [conn id]
|
||||
;; (let [row (db/exec-one! conn [sql:single-library id])]
|
||||
;; (when-not row
|
||||
;; (ex/raise :type :not-found))
|
||||
;; row))
|
||||
|
||||
|
||||
;; --- Query: Media objects (by file)
|
||||
|
||||
(declare retrieve-media-objects)
|
||||
(declare retrieve-file)
|
||||
|
||||
(s/def ::is-local boolean?)
|
||||
(s/def ::media-objects
|
||||
(s/keys :req-un [::profile-id ::file-id ::is-local]))
|
||||
|
||||
;; TODO: check if we can resolve url with transducer for reduce
|
||||
;; garbage generation for each request
|
||||
|
||||
(sq/defquery ::media-objects
|
||||
[{:keys [profile-id file-id is-local] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [file (retrieve-file conn file-id)]
|
||||
(teams/check-read-permissions! conn profile-id (:team-id file))
|
||||
(->> (retrieve-media-objects conn file-id is-local)
|
||||
(mapv #(media/resolve-urls % :path :uri))))))
|
||||
|
||||
(def ^:private sql:media-objects
|
||||
"select *
|
||||
from media_object
|
||||
where deleted_at is null
|
||||
and file_id = ?
|
||||
and is_local = ?
|
||||
order by created_at desc")
|
||||
|
||||
(defn retrieve-media-objects
|
||||
[conn file-id is-local]
|
||||
(db/exec! conn [sql:media-objects file-id is-local]))
|
||||
|
||||
(def ^:private sql:retrieve-file
|
||||
"select file.*,
|
||||
project.team_id as team_id
|
||||
from file
|
||||
inner join project on (project.id = file.project_id)
|
||||
where file.id = ?")
|
||||
|
||||
(defn- retrieve-file
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:retrieve-file id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
|
||||
;; --- Query: Media object (by ID)
|
||||
|
||||
(declare retrieve-media-object)
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::media-object
|
||||
(s/keys :req-un [::profile-id ::id]))
|
||||
|
||||
(sq/defquery ::media-object
|
||||
[{:keys [profile-id id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [media-object (retrieve-media-object conn id)]
|
||||
(teams/check-read-permissions! conn profile-id (:team-id media-object))
|
||||
(-> media-object
|
||||
(media/resolve-urls :path :uri)))))
|
||||
|
||||
(def ^:private sql:media-object
|
||||
"select obj.*,
|
||||
p.team_id as team_id
|
||||
from media_object as obj
|
||||
inner join file as f on (f.id = obj.file_id)
|
||||
inner join project as p on (p.id = f.project_id)
|
||||
where obj.deleted_at is null
|
||||
and obj.id = ?
|
||||
order by created_at desc")
|
||||
|
||||
(defn retrieve-media-object
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:media-object id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.images :as images]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.services.queries :as sq]
|
||||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.util.blob :as blob]))
|
||||
|
@ -78,7 +78,7 @@
|
|||
(defn retrieve-profile
|
||||
[conn id]
|
||||
(let [profile (some-> (retrieve-profile-data conn id)
|
||||
(images/resolve-urls :photo :photo-uri)
|
||||
(media/resolve-urls :photo :photo-uri)
|
||||
(strip-private-attrs)
|
||||
(merge (retrieve-additional-data conn id)))]
|
||||
(when (nil? profile)
|
||||
|
|
|
@ -16,10 +16,9 @@
|
|||
[uxbox.common.spec :as us]
|
||||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.images :as images]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.services.queries :as sq]
|
||||
[uxbox.services.queries.files :as files]
|
||||
[uxbox.services.queries.media :as media-queries]
|
||||
[uxbox.services.queries.pages :as pages]
|
||||
[uxbox.util.blob :as blob]
|
||||
[uxbox.util.data :as data]))
|
||||
|
@ -52,7 +51,7 @@
|
|||
(db/with-atomic [conn db/pool]
|
||||
(let [page (pages/retrieve-page conn page-id)
|
||||
file (files/retrieve-file conn (:file-id page))
|
||||
images (files/retrieve-file-images conn page)
|
||||
images (media-queries/retrieve-media-objects conn (:file-id page) true)
|
||||
project (retrieve-project conn (:project-id file))]
|
||||
(if (string? share-token)
|
||||
(when (not= share-token (:share-token page))
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
[uxbox.common.spec :as us]
|
||||
[uxbox.config :as cfg]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.media-storage :as mst]
|
||||
[uxbox.util.blob :as blob]
|
||||
[uxbox.util.storage :as ust]))
|
||||
|
||||
|
@ -39,8 +39,8 @@
|
|||
(run! (fn [item]
|
||||
(let [path1 (get item "path")
|
||||
path2 (get item "thumb_path")]
|
||||
(ust/delete! media/media-storage path1)
|
||||
(ust/delete! media/media-storage path2)))
|
||||
(ust/delete! mst/media-storage path1)
|
||||
(ust/delete! mst/media-storage path2)))
|
||||
result))
|
||||
|
||||
(defn- decode-row
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
[clojure.tools.logging :as log]
|
||||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.media-storage :as mst]
|
||||
[uxbox.metrics :as mtx]
|
||||
[uxbox.util.storage :as ust]))
|
||||
|
||||
|
@ -25,8 +25,8 @@
|
|||
(defn handler
|
||||
[{:keys [props] :as task}]
|
||||
(us/verify ::props props)
|
||||
(when (ust/exists? media/media-storage (:path props))
|
||||
(ust/delete! media/media-storage (:path props))
|
||||
(when (ust/exists? mst/media-storage (:path props))
|
||||
(ust/delete! mst/media-storage (:path props))
|
||||
(log/debug "Media " (:path props) " removed.")))
|
||||
|
||||
(mtx/instrument-with-summary!
|
||||
|
|
|
@ -14,13 +14,12 @@
|
|||
[uxbox.services.mutations.teams :as teams]
|
||||
[uxbox.services.mutations.files :as files]
|
||||
[uxbox.services.mutations.pages :as pages]
|
||||
[uxbox.services.mutations.images :as images]
|
||||
[uxbox.services.mutations.icons :as icons]
|
||||
;; [uxbox.services.mutations.icons :as icons]
|
||||
[uxbox.services.mutations.colors :as colors]
|
||||
[uxbox.fixtures :as fixtures]
|
||||
[uxbox.migrations]
|
||||
[uxbox.images]
|
||||
[uxbox.media]
|
||||
[uxbox.media-storage]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.util.blob :as blob]
|
||||
[uxbox.common.uuid :as uuid]
|
||||
|
@ -45,12 +44,12 @@
|
|||
#'uxbox.db/pool
|
||||
#'uxbox.redis/client
|
||||
#'uxbox.redis/conn
|
||||
#'uxbox.images/semaphore
|
||||
#'uxbox.media/semaphore
|
||||
#'uxbox.services.init/query-services
|
||||
#'uxbox.services.init/mutation-services
|
||||
#'uxbox.migrations/migrations
|
||||
#'uxbox.media/assets-storage
|
||||
#'uxbox.media/media-storage})
|
||||
#'uxbox.media-storage/assets-storage
|
||||
#'uxbox.media-storage/media-storage})
|
||||
(mount/swap {#'uxbox.config/config config
|
||||
#'uxbox.db/pool pool})
|
||||
(mount/start)))
|
||||
|
@ -73,8 +72,8 @@
|
|||
(try
|
||||
(next)
|
||||
(finally
|
||||
(ust/clear! uxbox.media/media-storage)
|
||||
(ust/clear! uxbox.media/assets-storage))))
|
||||
(ust/clear! uxbox.media-storage/media-storage)
|
||||
(ust/clear! uxbox.media-storage/assets-storage))))
|
||||
|
||||
(defn mk-uuid
|
||||
[prefix & args]
|
||||
|
@ -105,10 +104,11 @@
|
|||
:name (str "project" i)}))
|
||||
|
||||
(defn create-file
|
||||
[conn profile-id project-id i]
|
||||
[conn profile-id project-id is-shared i]
|
||||
(#'files/create-file conn {:id (mk-uuid "file" i)
|
||||
:profile-id profile-id
|
||||
:project-id project-id
|
||||
:is-shared is-shared
|
||||
:name (str "file" i)}))
|
||||
|
||||
(defn create-page
|
||||
|
@ -120,23 +120,22 @@
|
|||
:ordering i
|
||||
:data cp/default-page-data}))
|
||||
|
||||
|
||||
(defn create-image-library
|
||||
[conn team-id i]
|
||||
(#'images/create-library conn {:id (mk-uuid "imgcoll" i)
|
||||
:team-id team-id
|
||||
:name (str "image library " i)}))
|
||||
|
||||
(defn create-icon-library
|
||||
[conn team-id i]
|
||||
(#'icons/create-library conn {:id (mk-uuid "imgcoll" i)
|
||||
:team-id team-id
|
||||
:name (str "icon library " i)}))
|
||||
(defn create-color-library
|
||||
[conn team-id i]
|
||||
(#'colors/create-library conn {:id (mk-uuid "imgcoll" i)
|
||||
:team-id team-id
|
||||
:name (str "color library " i)}))
|
||||
;; (defn create-image-library
|
||||
;; [conn team-id i]
|
||||
;; (#'images/create-library conn {:id (mk-uuid "imgcoll" i)
|
||||
;; :team-id team-id
|
||||
;; :name (str "image library " i)}))
|
||||
;;
|
||||
;; (defn create-icon-library
|
||||
;; [conn team-id i]
|
||||
;; (#'icons/create-library conn {:id (mk-uuid "imgcoll" i)
|
||||
;; :team-id team-id
|
||||
;; :name (str "icon library " i)}))
|
||||
;; (defn create-color-library
|
||||
;; [conn team-id i]
|
||||
;; (#'colors/create-library conn {:id (mk-uuid "imgcoll" i)
|
||||
;; :team-id team-id
|
||||
;; :name (str "color library " i)}))
|
||||
|
||||
(defn handle-error
|
||||
[^Throwable err]
|
||||
|
|
|
@ -22,74 +22,77 @@
|
|||
(t/use-fixtures :once th/state-init)
|
||||
(t/use-fixtures :each th/database-reset)
|
||||
|
||||
(t/deftest color-libraries-crud
|
||||
(let [id (uuid/next)
|
||||
prof (th/create-profile db/pool 2)
|
||||
team-id (:default-team-id prof)]
|
||||
|
||||
(t/testing "create library"
|
||||
(let [data {::sm/type :create-color-library
|
||||
:name "sample library"
|
||||
:profile-id (:id prof)
|
||||
:team-id team-id
|
||||
:id id}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
(t/is (= id (:id result)))
|
||||
(t/is (= team-id (:team-id result)))
|
||||
(t/is (= (:name data) (:name result))))))
|
||||
|
||||
(t/testing "update library"
|
||||
(let [data {::sm/type :rename-color-library
|
||||
:name "renamed"
|
||||
:profile-id (:id prof)
|
||||
:id id}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
(t/is (= "renamed" (get-in result [:name]))))))
|
||||
|
||||
(t/testing "delete library"
|
||||
(let [data {::sm/type :delete-color-library
|
||||
:profile-id (:id prof)
|
||||
:id id}
|
||||
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (nil? (:result out)))))
|
||||
|
||||
(t/testing "query libraries after delete"
|
||||
(let [data {::sq/type :color-libraries
|
||||
:profile-id (:id prof)
|
||||
:team-id team-id}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
(let [result (:result out)]
|
||||
(t/is (= 0 (count result))))))
|
||||
))
|
||||
;; (t/deftest color-libraries-crud
|
||||
;; (let [id (uuid/next)
|
||||
;; prof (th/create-profile db/pool 2)
|
||||
;; team-id (:default-team-id prof)
|
||||
;; proj (th/create-project db/pool (:id prof) team-id 2)]
|
||||
;;
|
||||
;; (t/testing "create library file"
|
||||
;; (let [data {::sm/type :create-file
|
||||
;; :profile-id (:id prof)
|
||||
;; :name "sample library"
|
||||
;; :project-id (:id proj)
|
||||
;; :id id
|
||||
;; :is-shared true}
|
||||
;; out (th/try-on! (sm/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;;
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= id (:id result)))
|
||||
;; (t/is (= (:id proj) (:project-id result)))
|
||||
;; (t/is (= (:name data) (:name result))))))
|
||||
;;
|
||||
;; (t/testing "update library file"
|
||||
;; (let [data {::sm/type :rename-color-library
|
||||
;; :name "renamed"
|
||||
;; :profile-id (:id prof)
|
||||
;; :id id}
|
||||
;; out (th/try-on! (sm/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;;
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= "renamed" (get-in result [:name]))))))
|
||||
;;
|
||||
;; (t/testing "delete library"
|
||||
;; (let [data {::sm/type :delete-color-library
|
||||
;; :profile-id (:id prof)
|
||||
;; :id id}
|
||||
;;
|
||||
;; out (th/try-on! (sm/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;; (t/is (nil? (:result out)))))
|
||||
;;
|
||||
;; (t/testing "query libraries after delete"
|
||||
;; (let [data {::sq/type :color-libraries
|
||||
;; :profile-id (:id prof)
|
||||
;; :team-id team-id}
|
||||
;; out (th/try-on! (sq/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= 0 (count result))))))
|
||||
;; ))
|
||||
|
||||
(t/deftest colors-crud
|
||||
(let [prof (th/create-profile db/pool 1)
|
||||
team-id (:default-team-id prof)
|
||||
coll (th/create-color-library db/pool team-id 1)
|
||||
proj (th/create-project db/pool (:id prof) team-id 1)
|
||||
file (th/create-file db/pool (:id prof) (:id proj) true 1)
|
||||
color-id (uuid/next)]
|
||||
|
||||
(t/testing "upload color to library"
|
||||
(let [data {::sm/type :create-color
|
||||
:id color-id
|
||||
:profile-id (:id prof)
|
||||
:library-id (:id coll)
|
||||
:file-id (:id file)
|
||||
:name "testfile"
|
||||
:content "#222222"}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
@ -102,17 +105,17 @@
|
|||
(t/is (= (:name data) (:name result)))
|
||||
(t/is (= (:content data) (:content result))))))
|
||||
|
||||
(t/testing "list colors by library"
|
||||
(t/testing "list colors by library file"
|
||||
(let [data {::sq/type :colors
|
||||
:profile-id (:id prof)
|
||||
:library-id (:id coll)}
|
||||
:file-id (:id file)}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
;; (th/print-result! out)
|
||||
|
||||
(t/is (= color-id (get-in out [:result 0 :id])))
|
||||
(t/is (= "testfile" (get-in out [:result 0 :name])))))
|
||||
|
||||
(t/testing "single color"
|
||||
(t/testing "get single color"
|
||||
(let [data {::sq/type :color
|
||||
:profile-id (:id prof)
|
||||
:id color-id}
|
||||
|
@ -150,7 +153,7 @@
|
|||
(t/testing "query colors after delete"
|
||||
(let [data {::sq/type :colors
|
||||
:profile-id (:id prof)
|
||||
:library-id (:id coll)}
|
||||
:file-id (:id file)}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
;; (th/print-result! out)
|
||||
(let [result (:result out)]
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.http :as http]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.services.mutations :as sm]
|
||||
[uxbox.services.queries :as sq]
|
||||
[uxbox.tests.helpers :as th]
|
||||
|
@ -35,6 +34,7 @@
|
|||
:profile-id (:id prof)
|
||||
:project-id proj-id
|
||||
:id file-id
|
||||
:is-shared false
|
||||
:name "test file"}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
|
@ -129,105 +129,105 @@
|
|||
(t/is (= 0 (count result))))))
|
||||
))
|
||||
|
||||
(t/deftest file-images-crud
|
||||
(let [prof (th/create-profile db/pool 1)
|
||||
team-id (:default-team-id prof)
|
||||
proj-id (:default-project-id prof)
|
||||
file (th/create-file db/pool (:id prof) proj-id 1)]
|
||||
|
||||
(t/testing "create file image from url"
|
||||
(let [url "https://raw.githubusercontent.com/uxbox/uxbox/develop/frontend/resources/images/penpot-login.jpg"
|
||||
data {::sm/type :add-file-image-from-url
|
||||
:profile-id (:id prof)
|
||||
:file-id (:id file)
|
||||
:url url}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
(t/is (= (:id file) (:file-id result)))
|
||||
(t/is (not (nil? (:name result))))
|
||||
(t/is (= 787 (:width result)))
|
||||
(t/is (= 2000 (:height result)))
|
||||
(t/is (= "image/jpeg" (:mtype result)))
|
||||
|
||||
(t/is (string? (:path result)))
|
||||
(t/is (string? (:uri result)))
|
||||
(t/is (string? (:thumb-path result)))
|
||||
(t/is (string? (:thumb-uri result))))))
|
||||
|
||||
(t/testing "upload file image"
|
||||
(let [content {:filename "sample.jpg"
|
||||
:tempfile (th/tempfile "uxbox/tests/_files/sample.jpg")
|
||||
:content-type "image/jpeg"
|
||||
:size 312043}
|
||||
data {::sm/type :upload-file-image
|
||||
:profile-id (:id prof)
|
||||
:file-id (:id file)
|
||||
:name "testfile"
|
||||
:content content}
|
||||
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
(t/is (= (:id file) (:file-id result)))
|
||||
(t/is (= (:name data) (:name result)))
|
||||
(t/is (= 800 (:width result)))
|
||||
(t/is (= 800 (:height result)))
|
||||
(t/is (= (:content-type content) (:mtype result)))
|
||||
|
||||
(t/is (string? (:path result)))
|
||||
(t/is (string? (:uri result)))
|
||||
(t/is (string? (:thumb-path result)))
|
||||
(t/is (string? (:thumb-uri result))))))
|
||||
|
||||
(t/testing "import from library"
|
||||
(let [lib (th/create-image-library db/pool team-id 1)
|
||||
image-id (uuid/next)
|
||||
|
||||
content {:filename "sample.jpg"
|
||||
:tempfile (th/tempfile "uxbox/tests/_files/sample.jpg")
|
||||
:content-type "image/jpeg"
|
||||
:size 312043}
|
||||
|
||||
data {::sm/type :upload-image
|
||||
:id image-id
|
||||
:profile-id (:id prof)
|
||||
:library-id (:id lib)
|
||||
:name "testfile"
|
||||
:content content}
|
||||
out1 (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out1)
|
||||
(t/is (nil? (:error out1)))
|
||||
|
||||
(let [result (:result out1)]
|
||||
(t/is (= image-id (:id result)))
|
||||
(t/is (= "testfile" (:name result)))
|
||||
(t/is (= "image/jpeg" (:mtype result)))
|
||||
(t/is (= "image/jpeg" (:thumb-mtype result))))
|
||||
|
||||
(let [data2 {::sm/type :import-image-to-file
|
||||
:image-id image-id
|
||||
:file-id (:id file)
|
||||
:profile-id (:id prof)}
|
||||
out2 (th/try-on! (sm/handle data2))]
|
||||
|
||||
;; (th/print-result! out2)
|
||||
(t/is (nil? (:error out2)))
|
||||
|
||||
(let [result1 (:result out1)
|
||||
result2 (:result out2)]
|
||||
(t/is (not= (:path result2)
|
||||
(:path result1)))
|
||||
(t/is (not= (:thumb-path result2)
|
||||
(:thumb-path result1)))))))
|
||||
))
|
||||
;; (t/deftest file-images-crud
|
||||
;; (let [prof (th/create-profile db/pool 1)
|
||||
;; team-id (:default-team-id prof)
|
||||
;; proj-id (:default-project-id prof)
|
||||
;; file (th/create-file db/pool (:id prof) proj-id 1)]
|
||||
;;
|
||||
;; (t/testing "create file image from url"
|
||||
;; (let [url "https://raw.githubusercontent.com/uxbox/uxbox/develop/frontend/resources/images/penpot-login.jpg"
|
||||
;; data {::sm/type :add-file-image-from-url
|
||||
;; :profile-id (:id prof)
|
||||
;; :file-id (:id file)
|
||||
;; :url url}
|
||||
;; out (th/try-on! (sm/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;;
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= (:id file) (:file-id result)))
|
||||
;; (t/is (not (nil? (:name result))))
|
||||
;; (t/is (= 787 (:width result)))
|
||||
;; (t/is (= 2000 (:height result)))
|
||||
;; (t/is (= "image/jpeg" (:mtype result)))
|
||||
;;
|
||||
;; (t/is (string? (:path result)))
|
||||
;; (t/is (string? (:uri result)))
|
||||
;; (t/is (string? (:thumb-path result)))
|
||||
;; (t/is (string? (:thumb-uri result))))))
|
||||
;;
|
||||
;; (t/testing "upload file image"
|
||||
;; (let [content {:filename "sample.jpg"
|
||||
;; :tempfile (th/tempfile "uxbox/tests/_files/sample.jpg")
|
||||
;; :content-type "image/jpeg"
|
||||
;; :size 312043}
|
||||
;; data {::sm/type :upload-file-image
|
||||
;; :profile-id (:id prof)
|
||||
;; :file-id (:id file)
|
||||
;; :name "testfile"
|
||||
;; :content content}
|
||||
;;
|
||||
;; out (th/try-on! (sm/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;;
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= (:id file) (:file-id result)))
|
||||
;; (t/is (= (:name data) (:name result)))
|
||||
;; (t/is (= 800 (:width result)))
|
||||
;; (t/is (= 800 (:height result)))
|
||||
;; (t/is (= (:content-type content) (:mtype result)))
|
||||
;;
|
||||
;; (t/is (string? (:path result)))
|
||||
;; (t/is (string? (:uri result)))
|
||||
;; (t/is (string? (:thumb-path result)))
|
||||
;; (t/is (string? (:thumb-uri result))))))
|
||||
;;
|
||||
;; ;; (t/testing "import from library"
|
||||
;; ;; (let [lib (th/create-image-library db/pool team-id 1)
|
||||
;; ;; image-id (uuid/next)
|
||||
;; ;;
|
||||
;; ;; content {:filename "sample.jpg"
|
||||
;; ;; :tempfile (th/tempfile "uxbox/tests/_files/sample.jpg")
|
||||
;; ;; :content-type "image/jpeg"
|
||||
;; ;; :size 312043}
|
||||
;; ;;
|
||||
;; ;; data {::sm/type :upload-image
|
||||
;; ;; :id image-id
|
||||
;; ;; :profile-id (:id prof)
|
||||
;; ;; :library-id (:id lib)
|
||||
;; ;; :name "testfile"
|
||||
;; ;; :content content}
|
||||
;; ;; out1 (th/try-on! (sm/handle data))]
|
||||
;; ;;
|
||||
;; ;; ;; (th/print-result! out1)
|
||||
;; ;; (t/is (nil? (:error out1)))
|
||||
;; ;;
|
||||
;; ;; (let [result (:result out1)]
|
||||
;; ;; (t/is (= image-id (:id result)))
|
||||
;; ;; (t/is (= "testfile" (:name result)))
|
||||
;; ;; (t/is (= "image/jpeg" (:mtype result)))
|
||||
;; ;; (t/is (= "image/jpeg" (:thumb-mtype result))))
|
||||
;; ;;
|
||||
;; ;; (let [data2 {::sm/type :import-image-to-file
|
||||
;; ;; :image-id image-id
|
||||
;; ;; :file-id (:id file)
|
||||
;; ;; :profile-id (:id prof)}
|
||||
;; ;; out2 (th/try-on! (sm/handle data2))]
|
||||
;; ;;
|
||||
;; ;; ;; (th/print-result! out2)
|
||||
;; ;; (t/is (nil? (:error out2)))
|
||||
;; ;;
|
||||
;; ;; (let [result1 (:result out1)
|
||||
;; ;; result2 (:result out2)]
|
||||
;; ;; (t/is (not= (:path result2)
|
||||
;; ;; (:path result1)))
|
||||
;; ;; (t/is (not= (:thumb-path result2)
|
||||
;; ;; (:thumb-path result1)))))))
|
||||
;; ))
|
||||
|
||||
|
||||
;; TODO: delete file image
|
||||
|
|
|
@ -19,162 +19,162 @@
|
|||
[uxbox.tests.helpers :as th]
|
||||
[uxbox.util.storage :as ust]))
|
||||
|
||||
(t/use-fixtures :once th/state-init)
|
||||
(t/use-fixtures :each th/database-reset)
|
||||
|
||||
(t/deftest icon-libraries-crud
|
||||
(let [id (uuid/next)
|
||||
prof (th/create-profile db/pool 2)
|
||||
team-id (:default-team-id prof)]
|
||||
|
||||
(t/testing "create library"
|
||||
(let [data {::sm/type :create-icon-library
|
||||
:name "sample library"
|
||||
:profile-id (:id prof)
|
||||
:team-id team-id
|
||||
:id id}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
(t/is (= id (:id result)))
|
||||
(t/is (= team-id (:team-id result)))
|
||||
(t/is (= (:name data) (:name result))))))
|
||||
|
||||
(t/testing "rename library"
|
||||
(let [data {::sm/type :rename-icon-library
|
||||
:name "renamed"
|
||||
:profile-id (:id prof)
|
||||
:team-id team-id
|
||||
:id id}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
(t/is (= id (:id result)))
|
||||
(t/is (= "renamed" (:name result))))))
|
||||
|
||||
(t/testing "query libraries"
|
||||
(let [data {::sq/type :icon-libraries
|
||||
:profile-id (:id prof)
|
||||
:team-id team-id}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
(t/is (= 1 (count result)))
|
||||
(t/is (= id (get-in result [0 :id])))
|
||||
(t/is (= "renamed" (get-in result [0 :name]))))))
|
||||
|
||||
(t/testing "delete library"
|
||||
(let [data {::sm/type :delete-icon-library
|
||||
:profile-id (:id prof)
|
||||
:id id}
|
||||
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (nil? (:result out)))))
|
||||
|
||||
(t/testing "query libraries after delete"
|
||||
(let [data {::sq/type :icon-libraries
|
||||
:profile-id (:id prof)
|
||||
:team-id team-id}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
(t/is (= 0 (count result))))))
|
||||
))
|
||||
|
||||
(t/deftest icons-crud
|
||||
(let [prof (th/create-profile db/pool 1)
|
||||
team-id (:default-team-id prof)
|
||||
coll (th/create-icon-library db/pool team-id 1)
|
||||
icon-id (uuid/next)]
|
||||
|
||||
(t/testing "upload icon to library"
|
||||
(let [data {::sm/type :create-icon
|
||||
:id icon-id
|
||||
:profile-id (:id prof)
|
||||
:library-id (:id coll)
|
||||
:name "testfile"
|
||||
:content "<rect></rect>"
|
||||
:metadata {:width 100
|
||||
:height 100
|
||||
:view-box [0 0 100 100]
|
||||
:mimetype "text/svg"}}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
(t/is (= (:id data) (:id result)))
|
||||
(t/is (= (:name data) (:name result)))
|
||||
(t/is (= (:content data) (:content result))))))
|
||||
|
||||
(t/testing "list icons by library"
|
||||
(let [data {::sq/type :icons
|
||||
:profile-id (:id prof)
|
||||
:library-id (:id coll)}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
;; (th/print-result! out)
|
||||
|
||||
(t/is (= icon-id (get-in out [:result 0 :id])))
|
||||
(t/is (= "testfile" (get-in out [:result 0 :name])))))
|
||||
|
||||
(t/testing "single icon"
|
||||
(let [data {::sq/type :icon
|
||||
:profile-id (:id prof)
|
||||
:id icon-id}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
;; (th/print-result! out)
|
||||
|
||||
(t/is (= icon-id (get-in out [:result :id])))
|
||||
(t/is (= "testfile" (get-in out [:result :name])))))
|
||||
|
||||
(t/testing "delete icons"
|
||||
(let [data {::sm/type :delete-icon
|
||||
:profile-id (:id prof)
|
||||
:id icon-id}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (nil? (:result out)))))
|
||||
|
||||
(t/testing "query icon after delete"
|
||||
(let [data {::sq/type :icon
|
||||
:profile-id (:id prof)
|
||||
:id icon-id}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(let [error (:error out)]
|
||||
(t/is (th/ex-info? error))
|
||||
(t/is (th/ex-of-type? error :service-error)))
|
||||
|
||||
(let [error (ex-cause (:error out))]
|
||||
(t/is (th/ex-info? error))
|
||||
(t/is (th/ex-of-type? error :not-found)))))
|
||||
|
||||
(t/testing "query icons after delete"
|
||||
(let [data {::sq/type :icons
|
||||
:profile-id (:id prof)
|
||||
:library-id (:id coll)}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(let [result (:result out)]
|
||||
(t/is (= 0 (count result))))))
|
||||
))
|
||||
;; (t/use-fixtures :once th/state-init)
|
||||
;; (t/use-fixtures :each th/database-reset)
|
||||
;;
|
||||
;; (t/deftest icon-libraries-crud
|
||||
;; (let [id (uuid/next)
|
||||
;; prof (th/create-profile db/pool 2)
|
||||
;; team-id (:default-team-id prof)]
|
||||
;;
|
||||
;; (t/testing "create library"
|
||||
;; (let [data {::sm/type :create-icon-library
|
||||
;; :name "sample library"
|
||||
;; :profile-id (:id prof)
|
||||
;; :team-id team-id
|
||||
;; :id id}
|
||||
;; out (th/try-on! (sm/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;;
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= id (:id result)))
|
||||
;; (t/is (= team-id (:team-id result)))
|
||||
;; (t/is (= (:name data) (:name result))))))
|
||||
;;
|
||||
;; (t/testing "rename library"
|
||||
;; (let [data {::sm/type :rename-icon-library
|
||||
;; :name "renamed"
|
||||
;; :profile-id (:id prof)
|
||||
;; :team-id team-id
|
||||
;; :id id}
|
||||
;; out (th/try-on! (sm/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;;
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= id (:id result)))
|
||||
;; (t/is (= "renamed" (:name result))))))
|
||||
;;
|
||||
;; (t/testing "query libraries"
|
||||
;; (let [data {::sq/type :icon-libraries
|
||||
;; :profile-id (:id prof)
|
||||
;; :team-id team-id}
|
||||
;; out (th/try-on! (sq/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;;
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= 1 (count result)))
|
||||
;; (t/is (= id (get-in result [0 :id])))
|
||||
;; (t/is (= "renamed" (get-in result [0 :name]))))))
|
||||
;;
|
||||
;; (t/testing "delete library"
|
||||
;; (let [data {::sm/type :delete-icon-library
|
||||
;; :profile-id (:id prof)
|
||||
;; :id id}
|
||||
;;
|
||||
;; out (th/try-on! (sm/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;; (t/is (nil? (:result out)))))
|
||||
;;
|
||||
;; (t/testing "query libraries after delete"
|
||||
;; (let [data {::sq/type :icon-libraries
|
||||
;; :profile-id (:id prof)
|
||||
;; :team-id team-id}
|
||||
;; out (th/try-on! (sq/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;;
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= 0 (count result))))))
|
||||
;; ))
|
||||
;;
|
||||
;; (t/deftest icons-crud
|
||||
;; (let [prof (th/create-profile db/pool 1)
|
||||
;; team-id (:default-team-id prof)
|
||||
;; coll (th/create-icon-library db/pool team-id 1)
|
||||
;; icon-id (uuid/next)]
|
||||
;;
|
||||
;; (t/testing "upload icon to library"
|
||||
;; (let [data {::sm/type :create-icon
|
||||
;; :id icon-id
|
||||
;; :profile-id (:id prof)
|
||||
;; :library-id (:id coll)
|
||||
;; :name "testfile"
|
||||
;; :content "<rect></rect>"
|
||||
;; :metadata {:width 100
|
||||
;; :height 100
|
||||
;; :view-box [0 0 100 100]
|
||||
;; :mimetype "text/svg"}}
|
||||
;; out (th/try-on! (sm/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;;
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= (:id data) (:id result)))
|
||||
;; (t/is (= (:name data) (:name result)))
|
||||
;; (t/is (= (:content data) (:content result))))))
|
||||
;;
|
||||
;; (t/testing "list icons by library"
|
||||
;; (let [data {::sq/type :icons
|
||||
;; :profile-id (:id prof)
|
||||
;; :library-id (:id coll)}
|
||||
;; out (th/try-on! (sq/handle data))]
|
||||
;; ;; (th/print-result! out)
|
||||
;;
|
||||
;; (t/is (= icon-id (get-in out [:result 0 :id])))
|
||||
;; (t/is (= "testfile" (get-in out [:result 0 :name])))))
|
||||
;;
|
||||
;; (t/testing "single icon"
|
||||
;; (let [data {::sq/type :icon
|
||||
;; :profile-id (:id prof)
|
||||
;; :id icon-id}
|
||||
;; out (th/try-on! (sq/handle data))]
|
||||
;; ;; (th/print-result! out)
|
||||
;;
|
||||
;; (t/is (= icon-id (get-in out [:result :id])))
|
||||
;; (t/is (= "testfile" (get-in out [:result :name])))))
|
||||
;;
|
||||
;; (t/testing "delete icons"
|
||||
;; (let [data {::sm/type :delete-icon
|
||||
;; :profile-id (:id prof)
|
||||
;; :id icon-id}
|
||||
;; out (th/try-on! (sm/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;; (t/is (nil? (:result out)))))
|
||||
;;
|
||||
;; (t/testing "query icon after delete"
|
||||
;; (let [data {::sq/type :icon
|
||||
;; :profile-id (:id prof)
|
||||
;; :id icon-id}
|
||||
;; out (th/try-on! (sq/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (let [error (:error out)]
|
||||
;; (t/is (th/ex-info? error))
|
||||
;; (t/is (th/ex-of-type? error :service-error)))
|
||||
;;
|
||||
;; (let [error (ex-cause (:error out))]
|
||||
;; (t/is (th/ex-info? error))
|
||||
;; (t/is (th/ex-of-type? error :not-found)))))
|
||||
;;
|
||||
;; (t/testing "query icons after delete"
|
||||
;; (let [data {::sq/type :icons
|
||||
;; :profile-id (:id prof)
|
||||
;; :library-id (:id coll)}
|
||||
;; out (th/try-on! (sq/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= 0 (count result))))))
|
||||
;; ))
|
||||
|
|
|
@ -1,237 +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/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2020 UXBOX Labs SL
|
||||
|
||||
(ns uxbox.tests.test-services-images
|
||||
(:require
|
||||
[clojure.test :as t]
|
||||
[datoteka.core :as fs]
|
||||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.services.mutations :as sm]
|
||||
[uxbox.services.queries :as sq]
|
||||
[uxbox.tests.helpers :as th]
|
||||
[uxbox.util.storage :as ust]))
|
||||
|
||||
(t/use-fixtures :once th/state-init)
|
||||
(t/use-fixtures :each th/database-reset)
|
||||
|
||||
(t/deftest image-libraries-crud
|
||||
(let [id (uuid/next)
|
||||
prof (th/create-profile db/pool 2)
|
||||
team-id (:default-team-id prof)]
|
||||
|
||||
(t/testing "create library"
|
||||
(let [data {::sm/type :create-image-library
|
||||
:name "sample library"
|
||||
:profile-id (:id prof)
|
||||
:team-id team-id
|
||||
:id id}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
(t/is (= team-id (:team-id result)))
|
||||
(t/is (= (:name data) (:name result))))))
|
||||
|
||||
(t/testing "rename library"
|
||||
(let [data {::sm/type :rename-image-library
|
||||
:name "renamed"
|
||||
:profile-id (:id prof)
|
||||
:id id}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
(t/is (= id (:id result)))
|
||||
(t/is (= "renamed" (:name result))))))
|
||||
|
||||
(t/testing "query single library"
|
||||
(let [data {::sq/type :image-library
|
||||
:profile-id (:id prof)
|
||||
:id id}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
(t/is (= id (:id result)))
|
||||
(t/is (= "renamed" (:name result))))))
|
||||
|
||||
(t/testing "query libraries"
|
||||
(let [data {::sq/type :image-libraries
|
||||
:team-id team-id
|
||||
:profile-id (:id prof)}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(let [result (:result out)]
|
||||
(t/is (= 1 (count result)))
|
||||
(t/is (= id (get-in result [0 :id]))))))
|
||||
|
||||
(t/testing "delete library"
|
||||
(let [data {::sm/type :delete-image-library
|
||||
:profile-id (:id prof)
|
||||
:id id}
|
||||
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (nil? (:result out)))))
|
||||
|
||||
(t/testing "query libraries after delete"
|
||||
(let [data {::sq/type :image-libraries
|
||||
:profile-id (:id prof)
|
||||
:team-id team-id}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (= 0 (count (:result out))))))
|
||||
))
|
||||
|
||||
(t/deftest images-crud
|
||||
(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)
|
||||
: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 (not (nil? (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"
|
||||
:tempfile (th/tempfile "uxbox/tests/_files/sample.jpg")
|
||||
:content-type "image/jpeg"
|
||||
:size 312043}
|
||||
data {::sm/type :upload-image
|
||||
:id image-id-2
|
||||
:profile-id (:id prof)
|
||||
:library-id (:id lib)
|
||||
:name "testfile"
|
||||
:content content}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(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])))
|
||||
(t/is (= 800 (get-in out [:result :width])))
|
||||
(t/is (= 800 (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 "list images by library"
|
||||
(let [data {::sq/type :images
|
||||
:profile-id (:id prof)
|
||||
:library-id (:id lib)}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
;; (th/print-result! out)
|
||||
|
||||
;; 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])))
|
||||
(t/is (= 800 (get-in out [:result 0 :width])))
|
||||
(t/is (= 800 (get-in out [:result 0 :height])))
|
||||
|
||||
(t/is (string? (get-in out [:result 0 :path])))
|
||||
(t/is (string? (get-in out [:result 0 :thumb-path])))
|
||||
(t/is (string? (get-in out [:result 0 :uri])))
|
||||
(t/is (string? (get-in out [:result 0 :thumb-uri])))))
|
||||
|
||||
(t/testing "single image"
|
||||
(let [data {::sq/type :image
|
||||
:profile-id (:id prof)
|
||||
:id image-id-2}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
;; (th/print-result! out)
|
||||
|
||||
(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])))
|
||||
(t/is (= 800 (get-in out [:result :width])))
|
||||
(t/is (= 800 (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 "delete images"
|
||||
(let [data {::sm/type :delete-image
|
||||
:profile-id (:id prof)
|
||||
:id image-id-1}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (nil? (:result out)))))
|
||||
|
||||
(t/testing "query image after delete"
|
||||
(let [data {::sq/type :image
|
||||
:profile-id (:id prof)
|
||||
:id image-id-1}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(let [error (:error out)]
|
||||
(t/is (th/ex-info? error))
|
||||
(t/is (th/ex-of-type? error :service-error)))
|
||||
|
||||
(let [error (ex-cause (:error out))]
|
||||
(t/is (th/ex-info? error))
|
||||
(t/is (th/ex-of-type? error :not-found)))))
|
||||
|
||||
(t/testing "query images after delete"
|
||||
(let [data {::sq/type :images
|
||||
:profile-id (:id prof)
|
||||
:library-id (:id lib)}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
;; (th/print-result! out)
|
||||
(let [result (:result out)]
|
||||
(t/is (= 1 (count result))))))
|
||||
))
|
242
backend/tests/uxbox/tests/test_services_media.clj
Normal file
242
backend/tests/uxbox/tests/test_services_media.clj
Normal file
|
@ -0,0 +1,242 @@
|
|||
;; 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/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2020 UXBOX Labs SL
|
||||
|
||||
(ns uxbox.tests.test-services-media
|
||||
(:require
|
||||
[clojure.test :as t]
|
||||
[datoteka.core :as fs]
|
||||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.services.mutations :as sm]
|
||||
[uxbox.services.queries :as sq]
|
||||
[uxbox.tests.helpers :as th]
|
||||
[uxbox.util.storage :as ust]))
|
||||
|
||||
(t/use-fixtures :once th/state-init)
|
||||
(t/use-fixtures :each th/database-reset)
|
||||
|
||||
;; (t/deftest image-libraries-crud
|
||||
;; (let [id (uuid/next)
|
||||
;; prof (th/create-profile db/pool 2)
|
||||
;; team-id (:default-team-id prof)]
|
||||
;;
|
||||
;; (t/testing "create library"
|
||||
;; (let [data {::sm/type :create-image-library
|
||||
;; :name "sample library"
|
||||
;; :profile-id (:id prof)
|
||||
;; :team-id team-id
|
||||
;; :id id}
|
||||
;; out (th/try-on! (sm/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;;
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= team-id (:team-id result)))
|
||||
;; (t/is (= (:name data) (:name result))))))
|
||||
;;
|
||||
;; (t/testing "rename library"
|
||||
;; (let [data {::sm/type :rename-image-library
|
||||
;; :name "renamed"
|
||||
;; :profile-id (:id prof)
|
||||
;; :id id}
|
||||
;; out (th/try-on! (sm/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;;
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= id (:id result)))
|
||||
;; (t/is (= "renamed" (:name result))))))
|
||||
;;
|
||||
;; (t/testing "query single library"
|
||||
;; (let [data {::sq/type :image-library
|
||||
;; :profile-id (:id prof)
|
||||
;; :id id}
|
||||
;; out (th/try-on! (sq/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;;
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= id (:id result)))
|
||||
;; (t/is (= "renamed" (:name result))))))
|
||||
;;
|
||||
;; (t/testing "query libraries"
|
||||
;; (let [data {::sq/type :image-libraries
|
||||
;; :team-id team-id
|
||||
;; :profile-id (:id prof)}
|
||||
;; out (th/try-on! (sq/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;;
|
||||
;; (let [result (:result out)]
|
||||
;; (t/is (= 1 (count result)))
|
||||
;; (t/is (= id (get-in result [0 :id]))))))
|
||||
;;
|
||||
;; (t/testing "delete library"
|
||||
;; (let [data {::sm/type :delete-image-library
|
||||
;; :profile-id (:id prof)
|
||||
;; :id id}
|
||||
;;
|
||||
;; out (th/try-on! (sm/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;; (t/is (nil? (:result out)))))
|
||||
;;
|
||||
;; (t/testing "query libraries after delete"
|
||||
;; (let [data {::sq/type :image-libraries
|
||||
;; :profile-id (:id prof)
|
||||
;; :team-id team-id}
|
||||
;; out (th/try-on! (sq/handle data))]
|
||||
;;
|
||||
;; ;; (th/print-result! out)
|
||||
;; (t/is (nil? (:error out)))
|
||||
;; (t/is (= 0 (count (:result out))))))
|
||||
;; ))
|
||||
|
||||
(t/deftest media-crud
|
||||
(let [prof (th/create-profile db/pool 1)
|
||||
team-id (:default-team-id prof)
|
||||
proj (th/create-project db/pool (:id prof) team-id 1)
|
||||
file (th/create-file db/pool (:id prof) (:id proj) false 1)
|
||||
object-id-1 (uuid/next)
|
||||
object-id-2 (uuid/next)]
|
||||
|
||||
(t/testing "create media object from url to file"
|
||||
(let [url "https://raw.githubusercontent.com/uxbox/uxbox/develop/frontend/resources/images/penpot-login.jpg"
|
||||
data {::sm/type :add-media-object-from-url
|
||||
:id object-id-1
|
||||
:profile-id (:id prof)
|
||||
:file-id (:id file)
|
||||
:url url
|
||||
:is-local true}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(t/is (= object-id-1 (get-in out [:result :id])))
|
||||
(t/is (not (nil? (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 media object to file"
|
||||
(let [content {:filename "sample.jpg"
|
||||
:tempfile (th/tempfile "uxbox/tests/_files/sample.jpg")
|
||||
:content-type "image/jpeg"
|
||||
:size 312043}
|
||||
data {::sm/type :upload-media-object
|
||||
:id object-id-2
|
||||
:profile-id (:id prof)
|
||||
:file-id (:id file)
|
||||
:name "testfile"
|
||||
:content content
|
||||
:is-local true}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
|
||||
(t/is (= object-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])))
|
||||
(t/is (= 800 (get-in out [:result :width])))
|
||||
(t/is (= 800 (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 "list media objects by file"
|
||||
(let [data {::sq/type :media-objects
|
||||
:profile-id (:id prof)
|
||||
:file-id (:id file)
|
||||
:is-local true}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
;; (th/print-result! out)
|
||||
|
||||
;; Result is ordered by creation date descendent
|
||||
(t/is (= object-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])))
|
||||
(t/is (= 800 (get-in out [:result 0 :width])))
|
||||
(t/is (= 800 (get-in out [:result 0 :height])))
|
||||
|
||||
(t/is (string? (get-in out [:result 0 :path])))
|
||||
;; (t/is (string? (get-in out [:result 0 :thumb-path])))
|
||||
(t/is (string? (get-in out [:result 0 :uri])))))
|
||||
;; (t/is (string? (get-in out [:result 0 :thumb-uri])))))
|
||||
|
||||
(t/testing "single media object"
|
||||
(let [data {::sq/type :media-object
|
||||
:profile-id (:id prof)
|
||||
:id object-id-2}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
;; (th/print-result! out)
|
||||
|
||||
(t/is (= object-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])))
|
||||
(t/is (= 800 (get-in out [:result :width])))
|
||||
(t/is (= 800 (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 "delete media objects"
|
||||
(let [data {::sm/type :delete-media-object
|
||||
:profile-id (:id prof)
|
||||
:id object-id-1}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (nil? (:result out)))))
|
||||
|
||||
(t/testing "query media object after delete"
|
||||
(let [data {::sq/type :media-object
|
||||
:profile-id (:id prof)
|
||||
:id object-id-1}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
|
||||
;; (th/print-result! out)
|
||||
(let [error (:error out)]
|
||||
(t/is (th/ex-info? error))
|
||||
(t/is (th/ex-of-type? error :service-error)))
|
||||
|
||||
(let [error (ex-cause (:error out))]
|
||||
(t/is (th/ex-info? error))
|
||||
(t/is (th/ex-of-type? error :not-found)))))
|
||||
|
||||
(t/testing "query media objects after delete"
|
||||
(let [data {::sq/type :media-objects
|
||||
:profile-id (:id prof)
|
||||
:file-id (:id file)
|
||||
:is-local true}
|
||||
out (th/try-on! (sq/handle data))]
|
||||
;; (th/print-result! out)
|
||||
(let [result (:result out)]
|
||||
(t/is (= 1 (count result))))))
|
||||
))
|
|
@ -27,7 +27,7 @@
|
|||
(let [prof (th/create-profile db/pool 1)
|
||||
team-id (:default-team-id prof)
|
||||
proj-id (:default-project-id prof)
|
||||
file (th/create-file db/pool (:id prof) proj-id 1)
|
||||
file (th/create-file db/pool (:id prof) proj-id false 1)
|
||||
page-id (uuid/next)]
|
||||
|
||||
(t/testing "create page"
|
||||
|
@ -104,7 +104,7 @@
|
|||
(let [prof (th/create-profile db/pool 1)
|
||||
team-id (:default-team-id prof)
|
||||
proj-id (:default-project-id prof)
|
||||
file (th/create-file db/pool (:id prof) proj-id 1)
|
||||
file (th/create-file db/pool (:id prof) proj-id false 1)
|
||||
page-id (uuid/next)]
|
||||
|
||||
(t/testing "create empty page"
|
||||
|
@ -182,7 +182,7 @@
|
|||
(let [prof (th/create-profile db/pool 1)
|
||||
team-id (:default-team-id prof)
|
||||
proj-id (:default-project-id prof)
|
||||
file (th/create-file db/pool (:id prof) proj-id 1)
|
||||
file (th/create-file db/pool (:id prof) proj-id false 1)
|
||||
page (th/create-page db/pool (:id prof) (:id file) 1)]
|
||||
|
||||
(t/testing "lagging changes"
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.http :as http]
|
||||
[uxbox.media :as media]
|
||||
[uxbox.services.mutations :as sm]
|
||||
[uxbox.services.queries :as sq]
|
||||
[uxbox.tests.helpers :as th]
|
||||
|
@ -29,7 +28,7 @@
|
|||
team-id (:default-team-id prof)
|
||||
proj-id (:default-project-id prof)
|
||||
|
||||
file (th/create-file db/pool (:id prof) proj-id 1)
|
||||
file (th/create-file db/pool (:id prof) proj-id false 1)
|
||||
page (th/create-page db/pool (:id prof) (:id file) 1)
|
||||
token (atom nil)]
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue