♻️ The big media refactor (backend)

This commit is contained in:
Andrés Moya 2020-08-05 14:31:08 +02:00 committed by Andrey Antukh
parent 8b1ba8c020
commit bd7114182f
33 changed files with 2037 additions and 1937 deletions

View 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;

View File

@ -17,7 +17,6 @@
[uxbox.common.spec :as us] [uxbox.common.spec :as us]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.tasks :as tasks] [uxbox.tasks :as tasks]
[uxbox.media :as media]
[uxbox.util.emails :as emails])) [uxbox.util.emails :as emails]))
;; --- Defaults ;; --- Defaults

View File

@ -15,7 +15,6 @@
[uxbox.common.uuid :as uuid] [uxbox.common.uuid :as uuid]
[uxbox.config :as cfg] [uxbox.config :as cfg]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.media :as media]
[uxbox.migrations] [uxbox.migrations]
[uxbox.services.mutations.profile :as profile] [uxbox.services.mutations.profile :as profile]
[uxbox.util.blob :as blob])) [uxbox.util.blob :as blob]))

View File

@ -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}))))

View File

@ -28,7 +28,7 @@
[& args] [& args]
(require 'uxbox.config (require 'uxbox.config
'uxbox.migrations 'uxbox.migrations
'uxbox.images 'uxbox.media
'uxbox.http 'uxbox.http
'uxbox.tasks) 'uxbox.tasks)
(mount/start)) (mount/start))

View File

@ -5,32 +5,214 @@
;; This Source Code Form is "Incompatible With Secondary Licenses", as ;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0. ;; 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 (ns uxbox.media
"A media storage impl for uxbox." "Media postprocessing."
(:require (:require
[mount.core :refer [defstate]] [clojure.core.async :as a]
[clojure.java.io :as io] [clojure.java.io :as io]
[cuerdas.core :as str] [clojure.spec.alpha :as s]
[datoteka.core :as fs] [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.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 ;; --- Thumbnails Generation
:start (ust/create {:base-path (:assets-directory config)
:base-uri (:assets-uri config)}))
(defstate media-storage (s/def ::cmd keyword?)
:start (ust/create {:base-path (:media-directory config)
:base-uri (:media-uri config)
:xf (comp ust/random-path
ust/slugify-filename)}))
;; --- 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)))

View File

@ -23,7 +23,6 @@
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.http] [uxbox.http]
[uxbox.migrations] [uxbox.migrations]
[uxbox.media :as media]
[uxbox.util.svg :as svg] [uxbox.util.svg :as svg]
[uxbox.util.transit :as t] [uxbox.util.transit :as t]
[uxbox.util.blob :as blob] [uxbox.util.blob :as blob]
@ -32,8 +31,7 @@
[uxbox.services.mutations.projects :as projects] [uxbox.services.mutations.projects :as projects]
[uxbox.services.mutations.files :as files] [uxbox.services.mutations.files :as files]
[uxbox.services.mutations.colors :as colors] [uxbox.services.mutations.colors :as colors]
[uxbox.services.mutations.icons :as icons] [uxbox.services.mutations.media :as media]
[uxbox.services.mutations.images :as images]
[uxbox.util.storage :as ust]) [uxbox.util.storage :as ust])
(:import (:import
java.io.Reader java.io.Reader
@ -164,7 +162,7 @@
;; [conn {:keys [name] :as item}] ;; [conn {:keys [name] :as item}]
;; (let [id (uuid/namespaced +images-uuid-ns+ name)] ;; (let [id (uuid/namespaced +images-uuid-ns+ name)]
;; (log/info "Creating image library:" name) ;; (log/info "Creating image library:" name)
;; (images/create-library conn {:id id ;; (media/create-library conn {:id id
;; :team-id uuid/zero ;; :team-id uuid/zero
;; :name name}))) ;; :name name})))
;; ;;
@ -188,7 +186,7 @@
;; ".png" "image/png" ;; ".png" "image/png"
;; ".webp" "image/webp")] ;; ".webp" "image/webp")]
;; (log/info "Creating image" filename image-id) ;; (log/info "Creating image" filename image-id)
;; (images/create-image conn {:content {:tempfile localpath ;; (media/create-image conn {:content {:tempfile localpath
;; :filename filename ;; :filename filename
;; :content-type mtype ;; :content-type mtype
;; :size (.length file)} ;; :size (.length file)}
@ -298,19 +296,19 @@
".webp" "image/webp" ".webp" "image/webp"
".svg" "image/svg+xml")] ".svg" "image/svg+xml")]
(log/info "Creating image" filename image-id) (log/info "Creating image" filename image-id)
(images/create-image conn {:content {:tempfile localpath (media/create-media-object conn {:content {:tempfile localpath
:filename filename :filename filename
:content-type mtype :content-type mtype
:size (.length file)} :size (.length file)}
:id image-id :id image-id
:file-id file-id :file-id file-id
:user uuid/zero :name filename
:name filename}))) :is-local false})))
(defn- image-exists? (defn- image-exists?
[conn id] [conn id]
(s/assert ::us/uuid 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))) (if row true false)))
(defn- import-image-if-not-exists (defn- import-image-if-not-exists
@ -355,7 +353,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Libraries Importer ;; Library files Importer
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- library-file-exists? (defn- library-file-exists?

View 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)))

View File

@ -67,7 +67,11 @@
{:desc "Mark files shareable" {:desc "Mark files shareable"
:name "0013-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 ;; Entry point

View File

@ -14,8 +14,8 @@
(defn- load-query-services (defn- load-query-services
[] []
(require 'uxbox.services.queries.icons) ;; (require 'uxbox.services.queries.icons)
(require 'uxbox.services.queries.images) (require 'uxbox.services.queries.media)
(require 'uxbox.services.queries.colors) (require 'uxbox.services.queries.colors)
(require 'uxbox.services.queries.projects) (require 'uxbox.services.queries.projects)
(require 'uxbox.services.queries.files) (require 'uxbox.services.queries.files)
@ -28,8 +28,8 @@
(defn- load-mutation-services (defn- load-mutation-services
[] []
(require 'uxbox.services.mutations.demo) (require 'uxbox.services.mutations.demo)
(require 'uxbox.services.mutations.icons) ;; (require 'uxbox.services.mutations.icons)
(require 'uxbox.services.mutations.images) (require 'uxbox.services.mutations.media)
(require 'uxbox.services.mutations.colors) (require 'uxbox.services.mutations.colors)
(require 'uxbox.services.mutations.projects) (require 'uxbox.services.mutations.projects)
(require 'uxbox.services.mutations.files) (require 'uxbox.services.mutations.files)

View File

@ -30,92 +30,93 @@
(s/def ::content ::us/string) (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) ;; ;; --- Mutation: Rename Library
;;
(s/def ::create-color-library ;; (declare select-library-for-update)
(s/keys :req-un [::profile-id ::team-id ::name] ;; (declare rename-library)
:opt-un [::id])) ;;
;; (s/def ::rename-color-library
(sm/defmutation ::create-color-library ;; (s/keys :req-un [::profile-id ::name ::id]))
[{:keys [profile-id team-id] :as params}] ;;
(db/with-atomic [conn db/pool] ;; (sm/defmutation ::rename-color-library
(teams/check-edition-permissions! conn profile-id team-id) ;; [{:keys [id profile-id name] :as params}]
(create-library conn params))) ;; (db/with-atomic [conn db/pool]
;; (let [lib (select-library-for-update conn id)]
(defn create-library ;; (teams/check-edition-permissions! conn profile-id (:team-id lib))
[conn {:keys [id team-id name]}] ;; (rename-library conn id name))))
(let [id (or id (uuid/next))] ;;
(db/insert! conn :color-library ;; (def ^:private sql:select-library-for-update
{:id id ;; "select l.*
:team-id team-id ;; from color_library as l
:name name}))) ;; 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 ;; ;; --- Delete Library
;;
(declare select-library-for-update) ;; (declare delete-library)
(declare rename-library) ;;
;; (s/def ::delete-color-library
(s/def ::rename-color-library ;; (s/keys :req-un [::profile-id ::id]))
(s/keys :req-un [::profile-id ::name ::id])) ;;
;; (sm/defmutation ::delete-color-library
(sm/defmutation ::rename-color-library ;; [{:keys [id profile-id] :as params}]
[{:keys [id profile-id name] :as params}] ;; (db/with-atomic [conn db/pool]
(db/with-atomic [conn db/pool] ;; (let [lib (select-library-for-update conn id)]
(let [lib (select-library-for-update conn id)] ;; (teams/check-edition-permissions! conn profile-id (:team-id lib))
(teams/check-edition-permissions! conn profile-id (:team-id lib)) ;;
(rename-library conn id name)))) ;; ;; Schedule object deletion
;; (tasks/submit! conn {:name "delete-object"
(def ^:private sql:select-library-for-update ;; :delay cfg/default-deletion-delay
"select l.* ;; :props {:id id :type :color-library}})
from color_library as l ;;
where l.id = $1 ;; (db/update! conn :color-library
for update") ;; {:deleted-at (dt/now)}
;; {:id id})
(def ^:private sql:rename-library ;; nil)))
"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 ;; --- Mutation: Create Color
(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)
(declare select-file-for-update)
(declare create-color) (declare create-color)
(s/def ::create-color (s/def ::create-color
@ -125,10 +126,9 @@
(sm/defmutation ::create-color (sm/defmutation ::create-color
[{:keys [profile-id file-id] :as params}] [{:keys [profile-id file-id] :as params}]
(db/with-atomic [conn db/pool] (db/with-atomic [conn db/pool]
(create-color conn params))) (let [file (select-file-for-update conn file-id)]
;; (let [lib (select-library-for-update conn library-id)] (teams/check-edition-permissions! conn profile-id (:team-id file))
;; (teams/check-edition-permissions! conn profile-id (:team-id lib)) (create-color conn params))))
;; (create-color conn params))))
(def ^:private sql:create-color (def ^:private sql:create-color
"insert into color (id, name, file_id, content) "insert into color (id, name, file_id, content)
@ -142,6 +142,21 @@
:file-id file-id :file-id file-id
:content content}))) :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 ;; --- Mutation: Rename Color

View File

@ -18,10 +18,10 @@
[uxbox.common.uuid :as uuid] [uxbox.common.uuid :as uuid]
[uxbox.config :as cfg] [uxbox.config :as cfg]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.images :as images] ;; [uxbox.images :as images]
[uxbox.media :as media] ;; [uxbox.media :as media]
[uxbox.services.mutations :as sm] [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.mutations.projects :as proj]
[uxbox.services.queries.files :as files] [uxbox.services.queries.files :as files]
[uxbox.tasks :as tasks] [uxbox.tasks :as tasks]
@ -37,13 +37,14 @@
(s/def ::project-id ::us/uuid) (s/def ::project-id ::us/uuid)
(s/def ::url ::us/url) (s/def ::url ::us/url)
;; --- Mutation: Create Project File ;; --- Mutation: Create File
(declare create-file) (declare create-file)
(declare create-page) (declare create-page)
(s/def ::is-shared boolean?)
(s/def ::create-file (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])) :opt-un [::id]))
(sm/defmutation ::create-file (sm/defmutation ::create-file
@ -63,14 +64,13 @@
:can-edit true})) :can-edit true}))
(defn create-file (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)) (let [id (or id (uuid/next))
shared? (or shared? false)
file (db/insert! conn :file file (db/insert! conn :file
{:id id {:id id
:project-id project-id :project-id project-id
:name name :name name
:is-shared shared?})] :is-shared is-shared})]
(->> (assoc params :file-id id) (->> (assoc params :file-id id)
(create-file-profile conn)) (create-file-profile conn))
file)) file))
@ -153,135 +153,135 @@
nil) nil)
;; --- Mutations: Create File Image (Upload and create from url) ;; ;; --- Mutations: Create File Image (Upload and create from url)
;;
(declare create-file-image) ;; (declare create-file-image)
;;
(s/def ::file-id ::us/uuid) ;; (s/def ::file-id ::us/uuid)
(s/def ::image-id ::us/uuid) ;; (s/def ::image-id ::us/uuid)
(s/def ::content ::imgs/upload) ;; (s/def ::content ::imgs/upload)
;;
(s/def ::add-file-image-from-url ;; (s/def ::add-file-image-from-url
(s/keys :req-un [::profile-id ::file-id ::url] ;; (s/keys :req-un [::profile-id ::file-id ::url]
:opt-un [::id])) ;; :opt-un [::id]))
;;
(s/def ::upload-file-image ;; (s/def ::upload-file-image
(s/keys :req-un [::profile-id ::file-id ::name ::content] ;; (s/keys :req-un [::profile-id ::file-id ::name ::content]
:opt-un [::id])) ;; :opt-un [::id]))
;;
(sm/defmutation ::add-file-image-from-url ;; (sm/defmutation ::add-file-image-from-url
[{:keys [profile-id file-id url] :as params}] ;; [{:keys [profile-id file-id url] :as params}]
(db/with-atomic [conn db/pool] ;; (db/with-atomic [conn db/pool]
(files/check-edition-permissions! conn profile-id file-id) ;; (files/check-edition-permissions! conn profile-id file-id)
(let [content (images/download-image url) ;; (let [content (images/download-image url)
params' (merge params {:content content ;; params' (merge params {:content content
:name (:filename content)})] ;; :name (:filename content)})]
(create-file-image conn params')))) ;; (create-file-image conn params'))))
;;
(sm/defmutation ::upload-file-image ;; (sm/defmutation ::upload-file-image
[{:keys [profile-id file-id] :as params}] ;; [{:keys [profile-id file-id] :as params}]
(db/with-atomic [conn db/pool] ;; (db/with-atomic [conn db/pool]
(files/check-edition-permissions! conn profile-id file-id) ;; (files/check-edition-permissions! conn profile-id file-id)
(create-file-image conn params))) ;; (create-file-image conn params)))
;;
(defn- create-file-image ;; (defn- create-file-image
[conn {:keys [content file-id name] :as params}] ;; [conn {:keys [content file-id name] :as params}]
(when-not (imgs/valid-image-types? (:content-type content)) ;; (when-not (imgs/valid-image-types? (:content-type content))
(ex/raise :type :validation ;; (ex/raise :type :validation
:code :image-type-not-allowed ;; :code :image-type-not-allowed
:hint "Seems like you are uploading an invalid image.")) ;; :hint "Seems like you are uploading an invalid image."))
;;
(let [info (images/run {:cmd :info :input {:path (:tempfile content) ;; (let [info (images/run {:cmd :info :input {:path (:tempfile content)
:mtype (:content-type content)}}) ;; :mtype (:content-type content)}})
path (imgs/persist-image-on-fs content) ;; path (imgs/persist-image-on-fs content)
opts (assoc imgs/thumbnail-options ;; opts (assoc imgs/thumbnail-options
:input {:mtype (:mtype info) ;; :input {:mtype (:mtype info)
:path path}) ;; :path path})
thumb (if-not (= (:mtype info) "image/svg+xml") ;; thumb (if-not (= (:mtype info) "image/svg+xml")
(imgs/persist-image-thumbnail-on-fs opts) ;; (imgs/persist-image-thumbnail-on-fs opts)
(assoc info ;; (assoc info
:path path ;; :path path
:quality 0))] ;; :quality 0))]
;;
(-> (db/insert! conn :file-image ;; (-> (db/insert! conn :file-image
{:file-id file-id ;; {:file-id file-id
:name name ;; :name name
:path (str path) ;; :path (str path)
:width (:width info) ;; :width (:width info)
:height (:height info) ;; :height (:height info)
:mtype (:mtype info) ;; :mtype (:mtype info)
:thumb-path (str (:path thumb)) ;; :thumb-path (str (:path thumb))
:thumb-width (:width thumb) ;; :thumb-width (:width thumb)
:thumb-height (:height thumb) ;; :thumb-height (:height thumb)
:thumb-quality (:quality thumb) ;; :thumb-quality (:quality thumb)
:thumb-mtype (:mtype thumb)}) ;; :thumb-mtype (:mtype thumb)})
(images/resolve-urls :path :uri) ;; (images/resolve-urls :path :uri)
(images/resolve-urls :thumb-path :thumb-uri)))) ;; (images/resolve-urls :thumb-path :thumb-uri))))
;;
;;
;; --- Mutation: Delete File Image ;; ;; --- Mutation: Delete File Image
;;
(declare mark-file-image-deleted) ;; (declare mark-file-image-deleted)
;;
(s/def ::delete-file-image ;; (s/def ::delete-file-image
(s/keys :req-un [::file-id ::image-id ::profile-id])) ;; (s/keys :req-un [::file-id ::image-id ::profile-id]))
;;
(sm/defmutation ::delete-file-image ;; (sm/defmutation ::delete-file-image
[{:keys [file-id image-id profile-id] :as params}] ;; [{:keys [file-id image-id profile-id] :as params}]
(db/with-atomic [conn db/pool] ;; (db/with-atomic [conn db/pool]
(files/check-edition-permissions! conn profile-id file-id) ;; (files/check-edition-permissions! conn profile-id file-id)
;;
;; Schedule object deletion ;; ;; Schedule object deletion
(tasks/submit! conn {:name "delete-object" ;; (tasks/submit! conn {:name "delete-object"
:delay cfg/default-deletion-delay ;; :delay cfg/default-deletion-delay
:props {:id image-id :type :file-image}}) ;; :props {:id image-id :type :file-image}})
;;
(mark-file-image-deleted conn params))) ;; (mark-file-image-deleted conn params)))
;;
(defn mark-file-image-deleted ;; (defn mark-file-image-deleted
[conn {:keys [image-id] :as params}] ;; [conn {:keys [image-id] :as params}]
(db/update! conn :file-image ;; (db/update! conn :file-image
{:deleted-at (dt/now)} ;; {:deleted-at (dt/now)}
{:id image-id}) ;; {:id image-id})
nil) ;; nil)
;;
;;
;; --- Mutation: Import from collection ;; ;; --- Mutation: Import from collection
;;
(declare copy-image) ;; (declare copy-image)
(declare import-image-to-file) ;; (declare import-image-to-file)
;;
(s/def ::import-image-to-file ;; (s/def ::import-image-to-file
(s/keys :req-un [::image-id ::file-id ::profile-id])) ;; (s/keys :req-un [::image-id ::file-id ::profile-id]))
;;
(sm/defmutation ::import-image-to-file ;; (sm/defmutation ::import-image-to-file
[{:keys [image-id file-id profile-id] :as params}] ;; [{:keys [image-id file-id profile-id] :as params}]
(db/with-atomic [conn db/pool] ;; (db/with-atomic [conn db/pool]
(files/check-edition-permissions! conn profile-id file-id) ;; (files/check-edition-permissions! conn profile-id file-id)
(import-image-to-file conn params))) ;; (import-image-to-file conn params)))
;;
(defn- import-image-to-file ;; (defn- import-image-to-file
[conn {:keys [image-id file-id] :as params}] ;; [conn {:keys [image-id file-id] :as params}]
(let [image (db/get-by-id conn :image image-id) ;; (let [image (db/get-by-id conn :image image-id)
image-path (copy-image (:path image)) ;; image-path (copy-image (:path image))
thumb-path (copy-image (:thumb-path image))] ;; thumb-path (copy-image (:thumb-path image))]
;;
(-> (db/insert! conn :file-image ;; (-> (db/insert! conn :file-image
{:file-id file-id ;; {:file-id file-id
:name (:name image) ;; :name (:name image)
:path (str image-path) ;; :path (str image-path)
:width (:width image) ;; :width (:width image)
:height (:height image) ;; :height (:height image)
:mtype (:mtype image) ;; :mtype (:mtype image)
:thumb-path (str thumb-path) ;; :thumb-path (str thumb-path)
:thumb-width (:thumb-width image) ;; :thumb-width (:thumb-width image)
:thumb-height (:thumb-height image) ;; :thumb-height (:thumb-height image)
:thumb-quality (:thumb-quality image) ;; :thumb-quality (:thumb-quality image)
:thumb-mtype (:thumb-mtype image)}) ;; :thumb-mtype (:thumb-mtype image)})
(images/resolve-urls :path :uri) ;; (images/resolve-urls :path :uri)
(images/resolve-urls :thumb-path :thumb-uri)))) ;; (images/resolve-urls :thumb-path :thumb-uri))))
;;
(defn- copy-image ;; (defn- copy-image
[path] ;; [path]
(let [image-path (ust/lookup media/media-storage path)] ;; (let [image-path (ust/lookup media/media-storage path)]
(ust/save! media/media-storage (fs/name image-path) image-path))) ;; (ust/save! media/media-storage (fs/name image-path) image-path)))

View File

@ -7,200 +7,200 @@
;; ;;
;; Copyright (c) 2019-2020 Andrey Antukh <niwi@niwi.nz> ;; Copyright (c) 2019-2020 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.services.mutations.icons ;; (ns uxbox.services.mutations.icons
(:require ;; (:require
[clojure.spec.alpha :as s] ;; [clojure.spec.alpha :as s]
[uxbox.common.exceptions :as ex] ;; [uxbox.common.exceptions :as ex]
[uxbox.common.spec :as us] ;; [uxbox.common.spec :as us]
[uxbox.common.uuid :as uuid] ;; [uxbox.common.uuid :as uuid]
[uxbox.config :as cfg] ;; [uxbox.config :as cfg]
[uxbox.db :as db] ;; [uxbox.db :as db]
[uxbox.services.mutations :as sm] ;; [uxbox.services.mutations :as sm]
[uxbox.services.queries.icons :refer [decode-row]] ;; [uxbox.services.queries.icons :refer [decode-row]]
[uxbox.services.queries.teams :as teams] ;; [uxbox.services.queries.teams :as teams]
[uxbox.tasks :as tasks] ;; [uxbox.tasks :as tasks]
[uxbox.util.blob :as blob] ;; [uxbox.util.blob :as blob]
[uxbox.util.time :as dt])) ;; [uxbox.util.time :as dt]))
;;
;; --- Helpers & Specs ;; ;; --- Helpers & Specs
;;
(s/def ::height ::us/integer) ;; (s/def ::height ::us/integer)
(s/def ::id ::us/uuid) ;; (s/def ::id ::us/uuid)
(s/def ::library-id ::us/uuid) ;; (s/def ::library-id ::us/uuid)
(s/def ::name ::us/string) ;; (s/def ::name ::us/string)
(s/def ::profile-id ::us/uuid) ;; (s/def ::profile-id ::us/uuid)
(s/def ::team-id ::us/uuid) ;; (s/def ::team-id ::us/uuid)
(s/def ::width ::us/integer) ;; (s/def ::width ::us/integer)
;;
(s/def ::view-box ;; (s/def ::view-box
(s/and (s/coll-of number?) ;; (s/and (s/coll-of number?)
#(= 4 (count %)) ;; #(= 4 (count %))
vector?)) ;; vector?))
;;
(s/def ::content ::us/string) ;; (s/def ::content ::us/string)
(s/def ::mimetype ::us/string) ;; (s/def ::mimetype ::us/string)
;;
(s/def ::metadata ;; (s/def ::metadata
(s/keys :opt-un [::width ::height ::view-box ::mimetype])) ;; (s/keys :opt-un [::width ::height ::view-box ::mimetype]))
;;
;;
;; --- Mutation: Create Library ;; ;; --- Mutation: Create Library
;;
(declare create-library) ;; (declare create-library)
;;
(s/def ::create-icon-library ;; (s/def ::create-icon-library
(s/keys :req-un [::profile-id ::team-id ::name] ;; (s/keys :req-un [::profile-id ::team-id ::name]
:opt-un [::id])) ;; :opt-un [::id]))
;;
(sm/defmutation ::create-icon-library ;; (sm/defmutation ::create-icon-library
[{:keys [profile-id team-id id name] :as params}] ;; [{:keys [profile-id team-id id name] :as params}]
(db/with-atomic [conn db/pool] ;; (db/with-atomic [conn db/pool]
(teams/check-edition-permissions! conn profile-id team-id) ;; (teams/check-edition-permissions! conn profile-id team-id)
(create-library conn params))) ;; (create-library conn params)))
;;
(def ^:private sql:create-library ;; (def ^:private sql:create-library
"insert into icon_library (id, team_id, name) ;; "insert into icon_library (id, team_id, name)
values ($1, $2, $3) ;; values ($1, $2, $3)
returning *;") ;; returning *;")
;;
(defn create-library ;; (defn create-library
[conn {:keys [team-id id name] :as params}] ;; [conn {:keys [team-id id name] :as params}]
(let [id (or id (uuid/next))] ;; (let [id (or id (uuid/next))]
(db/insert! conn :icon-library ;; (db/insert! conn :icon-library
{:id id ;; {:id id
:team-id team-id ;; :team-id team-id
:name name}))) ;; :name name})))
;;
;;
;; --- Mutation: Rename Library ;; ;; --- Mutation: Rename Library
;;
(declare select-library-for-update) ;; (declare select-library-for-update)
(declare rename-library) ;; (declare rename-library)
;;
(s/def ::rename-icon-library ;; (s/def ::rename-icon-library
(s/keys :req-un [::profile-id ::name ::id])) ;; (s/keys :req-un [::profile-id ::name ::id]))
;;
(sm/defmutation ::rename-icon-library ;; (sm/defmutation ::rename-icon-library
[{:keys [id profile-id name] :as params}] ;; [{:keys [id profile-id name] :as params}]
(db/with-atomic [conn db/pool] ;; (db/with-atomic [conn db/pool]
(let [lib (select-library-for-update conn id)] ;; (let [lib (select-library-for-update conn id)]
(teams/check-edition-permissions! conn profile-id (:team-id lib)) ;; (teams/check-edition-permissions! conn profile-id (:team-id lib))
(rename-library conn id name)))) ;; (rename-library conn id name))))
;;
(defn- select-library-for-update ;; (defn- select-library-for-update
[conn id] ;; [conn id]
(db/get-by-id conn :icon-library id {:for-update true})) ;; (db/get-by-id conn :icon-library id {:for-update true}))
;;
(defn- rename-library ;; (defn- rename-library
[conn id name] ;; [conn id name]
(db/update! conn :icon-library ;; (db/update! conn :icon-library
{:name name} ;; {:name name}
{:id id})) ;; {:id id}))
;;
;; --- Mutation: Delete Library ;; ;; --- Mutation: Delete Library
;;
(declare delete-library) ;; (declare delete-library)
;;
(s/def ::delete-icon-library ;; (s/def ::delete-icon-library
(s/keys :req-un [::profile-id ::id])) ;; (s/keys :req-un [::profile-id ::id]))
;;
(sm/defmutation ::delete-icon-library ;; (sm/defmutation ::delete-icon-library
[{:keys [profile-id id] :as params}] ;; [{:keys [profile-id id] :as params}]
(db/with-atomic [conn db/pool] ;; (db/with-atomic [conn db/pool]
(let [lib (select-library-for-update conn id)] ;; (let [lib (select-library-for-update conn id)]
(teams/check-edition-permissions! conn profile-id (:team-id lib)) ;; (teams/check-edition-permissions! conn profile-id (:team-id lib))
;;
;; Schedule object deletion ;; ;; Schedule object deletion
(tasks/submit! conn {:name "delete-object" ;; (tasks/submit! conn {:name "delete-object"
:delay cfg/default-deletion-delay ;; :delay cfg/default-deletion-delay
:props {:id id :type :icon-library}}) ;; :props {:id id :type :icon-library}})
;;
(db/update! conn :icon-library ;; (db/update! conn :icon-library
{:deleted-at (dt/now)} ;; {:deleted-at (dt/now)}
{:id id}) ;; {:id id})
nil))) ;; nil)))
;;
;;
;; --- Mutation: Create Icon (Upload) ;; ;; --- Mutation: Create Icon (Upload)
;;
(declare create-icon) ;; (declare create-icon)
;;
(s/def ::create-icon ;; (s/def ::create-icon
(s/keys :req-un [::profile-id ::name ::metadata ::content ::library-id] ;; (s/keys :req-un [::profile-id ::name ::metadata ::content ::library-id]
:opt-un [::id])) ;; :opt-un [::id]))
;;
(sm/defmutation ::create-icon ;; (sm/defmutation ::create-icon
[{:keys [profile-id library-id] :as params}] ;; [{:keys [profile-id library-id] :as params}]
(db/with-atomic [conn db/pool] ;; (db/with-atomic [conn db/pool]
(let [lib (select-library-for-update conn library-id)] ;; (let [lib (select-library-for-update conn library-id)]
(teams/check-edition-permissions! conn profile-id (:team-id lib)) ;; (teams/check-edition-permissions! conn profile-id (:team-id lib))
(create-icon conn params)))) ;; (create-icon conn params))))
;;
(defn create-icon ;; (defn create-icon
[conn {:keys [id name library-id metadata content]}] ;; [conn {:keys [id name library-id metadata content]}]
(let [id (or id (uuid/next))] ;; (let [id (or id (uuid/next))]
(-> (db/insert! conn :icon ;; (-> (db/insert! conn :icon
{:id id ;; {:id id
:name name ;; :name name
:library-id library-id ;; :library-id library-id
:content content ;; :content content
:metadata (blob/encode metadata)}) ;; :metadata (blob/encode metadata)})
(decode-row)))) ;; (decode-row))))
;;
;;
;; --- Mutation: Rename Icon ;; ;; --- Mutation: Rename Icon
;;
(declare select-icon-for-update) ;; (declare select-icon-for-update)
(declare rename-icon) ;; (declare rename-icon)
;;
(s/def ::rename-icon ;; (s/def ::rename-icon
(s/keys :req-un [::id ::profile-id ::name])) ;; (s/keys :req-un [::id ::profile-id ::name]))
;;
(sm/defmutation ::rename-icon ;; (sm/defmutation ::rename-icon
[{:keys [id profile-id name] :as params}] ;; [{:keys [id profile-id name] :as params}]
(db/with-atomic [conn db/pool] ;; (db/with-atomic [conn db/pool]
(let [icon (select-icon-for-update conn id)] ;; (let [icon (select-icon-for-update conn id)]
(teams/check-edition-permissions! conn profile-id (:team-id icon)) ;; (teams/check-edition-permissions! conn profile-id (:team-id icon))
(db/update! conn :icon ;; (db/update! conn :icon
{:name name} ;; {:name name}
{:id id})))) ;; {:id id}))))
;;
(def ^:private ;; (def ^:private
sql:select-icon-for-update ;; sql:select-icon-for-update
"select i.*, ;; "select i.*,
lib.team_id as team_id ;; lib.team_id as team_id
from icon as i ;; from icon as i
inner join icon_library as lib on (lib.id = i.library_id) ;; inner join icon_library as lib on (lib.id = i.library_id)
where i.id = ? ;; where i.id = ?
for update") ;; for update")
;;
(defn- select-icon-for-update ;; (defn- select-icon-for-update
[conn id] ;; [conn id]
(let [row (db/exec-one! conn [sql:select-icon-for-update id])] ;; (let [row (db/exec-one! conn [sql:select-icon-for-update id])]
(when-not row ;; (when-not row
(ex/raise :type :not-found)) ;; (ex/raise :type :not-found))
row)) ;; row))
;;
;;
;; --- Mutation: Delete Icon ;; ;; --- Mutation: Delete Icon
;;
(declare delete-icon) ;; (declare delete-icon)
;;
(s/def ::delete-icon ;; (s/def ::delete-icon
(s/keys :req-un [::profile-id ::id])) ;; (s/keys :req-un [::profile-id ::id]))
;;
(sm/defmutation ::delete-icon ;; (sm/defmutation ::delete-icon
[{:keys [id profile-id] :as params}] ;; [{:keys [id profile-id] :as params}]
(db/with-atomic [conn db/pool] ;; (db/with-atomic [conn db/pool]
(let [icn (select-icon-for-update conn id)] ;; (let [icn (select-icon-for-update conn id)]
(teams/check-edition-permissions! conn profile-id (:team-id icn)) ;; (teams/check-edition-permissions! conn profile-id (:team-id icn))
;;
;; Schedule object deletion ;; ;; Schedule object deletion
(tasks/submit! conn {:name "delete-object" ;; (tasks/submit! conn {:name "delete-object"
:delay cfg/default-deletion-delay ;; :delay cfg/default-deletion-delay
:props {:id id :type :icon}}) ;; :props {:id id :type :icon}})
;;
(db/update! conn :icon ;; (db/update! conn :icon
{:deleted-at (dt/now)} ;; {:deleted-at (dt/now)}
{:id id}) ;; {:id id})
nil))) ;; nil)))

View File

@ -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)))

View 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)))

View File

@ -23,11 +23,11 @@
[uxbox.config :as cfg] [uxbox.config :as cfg]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.emails :as emails] [uxbox.emails :as emails]
[uxbox.images :as images]
[uxbox.media :as media] [uxbox.media :as media]
[uxbox.media-storage :as mst]
[uxbox.services.tokens :as tokens] [uxbox.services.tokens :as tokens]
[uxbox.services.mutations :as sm] [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.projects :as projects]
[uxbox.services.mutations.teams :as teams] [uxbox.services.mutations.teams :as teams]
[uxbox.services.queries.profile :as profile] [uxbox.services.queries.profile :as profile]
@ -266,20 +266,20 @@
(declare upload-photo) (declare upload-photo)
(declare update-profile-photo) (declare update-profile-photo)
(s/def ::file ::imgs/upload) (s/def ::file ::media-mutations/upload)
(s/def ::update-profile-photo (s/def ::update-profile-photo
(s/keys :req-un [::profile-id ::file])) (s/keys :req-un [::profile-id ::file]))
(sm/defmutation ::update-profile-photo (sm/defmutation ::update-profile-photo
[{:keys [profile-id file] :as params}] [{: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 (ex/raise :type :validation
:code :image-type-not-allowed :code :media-type-not-allowed
:hint "Seems like you are uploading an invalid image.")) :hint "Seems like you are uploading an invalid media object"))
(db/with-atomic [conn db/pool] (db/with-atomic [conn db/pool]
(let [profile (profile/retrieve-profile conn profile-id) (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)}}) :mtype (:content-type file)}})
photo (upload-photo conn params)] photo (upload-photo conn params)]
@ -295,7 +295,7 @@
[conn {:keys [file profile-id]}] [conn {:keys [file profile-id]}]
(let [prefix (-> (sodi.prng/random-bytes 8) (let [prefix (-> (sodi.prng/random-bytes 8)
(sodi.util/bytes->b64s)) (sodi.util/bytes->b64s))
thumb (images/run thumb (media/run
{:cmd :profile-thumbnail {:cmd :profile-thumbnail
:format :jpeg :format :jpeg
:quality 85 :quality 85
@ -303,8 +303,8 @@
:height 256 :height 256
:input {:path (fs/path (:tempfile file)) :input {:path (fs/path (:tempfile file))
:mtype (:content-type file)}}) :mtype (:content-type file)}})
name (str prefix (images/format->extension (:format thumb)))] name (str prefix (media/format->extension (:format thumb)))]
(ust/save! media/media-storage name (:data thumb)))) (ust/save! mst/media-storage name (:data thumb))))
(defn- update-profile-photo (defn- update-profile-photo
[conn profile-id path] [conn profile-id path]

View File

@ -16,8 +16,6 @@
[uxbox.common.spec :as us] [uxbox.common.spec :as us]
[uxbox.common.uuid :as uuid] [uxbox.common.uuid :as uuid]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.images :as images]
[uxbox.media :as media]
[uxbox.services.queries :as sq] [uxbox.services.queries :as sq]
[uxbox.services.queries.teams :as teams] [uxbox.services.queries.teams :as teams]
[uxbox.util.blob :as blob] [uxbox.util.blob :as blob]
@ -29,59 +27,60 @@
(s/def ::profile-id ::us/uuid) (s/def ::profile-id ::us/uuid)
(s/def ::team-id ::us/uuid) (s/def ::team-id ::us/uuid)
(s/def ::file-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 ;; ;; --- Query: Colors Libraries
;;
(def ^:private sql:libraries ;; (def ^:private sql:libraries
"select lib.*, ;; "select lib.*,
(select count(*) from color where library_id = lib.id) as num_colors ;; (select count(*) from color where library_id = lib.id) as num_colors
from color_library as lib ;; from color_library as lib
where lib.team_id = ? ;; where lib.team_id = ?
and lib.deleted_at is null ;; and lib.deleted_at is null
order by lib.created_at desc") ;; order by lib.created_at desc")
;;
(s/def ::color-libraries ;; (s/def ::color-libraries
(s/keys :req-un [::profile-id ::team-id])) ;; (s/keys :req-un [::profile-id ::team-id]))
;;
(sq/defquery ::color-libraries ;; (sq/defquery ::color-libraries
[{:keys [profile-id team-id]}] ;; [{:keys [profile-id team-id]}]
(db/with-atomic [conn db/pool] ;; (db/with-atomic [conn db/pool]
(teams/check-read-permissions! conn profile-id team-id) ;; (teams/check-read-permissions! conn profile-id team-id)
(db/exec! conn [sql:libraries team-id]))) ;; (db/exec! conn [sql:libraries team-id])))
;;
;;
;; --- Query: Color Library ;; ;; --- Query: Color Library
;;
(declare retrieve-library) ;; (declare retrieve-library)
;;
(s/def ::color-library ;; (s/def ::color-library
(s/keys :req-un [::profile-id ::id])) ;; (s/keys :req-un [::profile-id ::id]))
;;
(sq/defquery ::color-library ;; (sq/defquery ::color-library
[{:keys [profile-id id]}] ;; [{:keys [profile-id id]}]
(db/with-atomic [conn db/pool] ;; (db/with-atomic [conn db/pool]
(let [lib (retrieve-library conn id)] ;; (let [lib (retrieve-library conn id)]
(teams/check-read-permissions! conn profile-id (:team-id lib)) ;; (teams/check-read-permissions! conn profile-id (:team-id lib))
lib))) ;; lib)))
;;
(def ^:private sql:single-library ;; (def ^:private sql:single-library
"select lib.*, ;; "select lib.*,
(select count(*) from color where library_id = lib.id) as num_colors ;; (select count(*) from color where library_id = lib.id) as num_colors
from color_library as lib ;; from color_library as lib
where lib.deleted_at is null ;; where lib.deleted_at is null
and lib.id = ?") ;; and lib.id = ?")
;;
(defn- retrieve-library ;; (defn- retrieve-library
[conn id] ;; [conn id]
(let [row (db/exec-one! conn [sql:single-library id])] ;; (let [row (db/exec-one! conn [sql:single-library id])]
(when-not row ;; (when-not row
(ex/raise :type :not-found)) ;; (ex/raise :type :not-found))
row)) ;; row))
;; --- Query: Colors (by file) ;; --- Query: Colors (by file)
(declare retrieve-colors) (declare retrieve-colors)
(declare retrieve-file)
(s/def ::colors (s/def ::colors
(s/keys :req-un [::profile-id ::file-id])) (s/keys :req-un [::profile-id ::file-id]))
@ -89,10 +88,9 @@
(sq/defquery ::colors (sq/defquery ::colors
[{:keys [profile-id file-id] :as params}] [{:keys [profile-id file-id] :as params}]
(db/with-atomic [conn db/pool] (db/with-atomic [conn db/pool]
(retrieve-colors conn file-id))) (let [file (retrieve-file conn file-id)]
;; (let [lib (retrieve-library conn library-id)] (teams/check-read-permissions! conn profile-id (:team-id file))
;; (teams/check-read-permissions! conn profile-id (:team-id lib)) (retrieve-colors conn file-id))))
;; (retrieve-colors conn library-id))))
(def ^:private sql:colors (def ^:private sql:colors
"select * "select *
@ -105,6 +103,20 @@
[conn file-id] [conn file-id]
(db/exec! conn [sql:colors 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) ;; --- Query: Color (by ID)
@ -123,9 +135,10 @@
(def ^:private sql:single-color (def ^:private sql:single-color
"select color.*, "select color.*,
lib.team_id as team_id p.team_id as team_id
from color as color 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 where color.deleted_at is null
and color.id = ? and color.id = ?
order by created_at desc") order by created_at desc")
@ -136,3 +149,4 @@
(when-not row (when-not row
(ex/raise :type :not-found)) (ex/raise :type :not-found))
row)) row))

View File

@ -14,7 +14,7 @@
[uxbox.common.exceptions :as ex] [uxbox.common.exceptions :as ex]
[uxbox.common.spec :as us] [uxbox.common.spec :as us]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.images :as images] [uxbox.media :as media]
[uxbox.services.queries :as sq] [uxbox.services.queries :as sq]
[uxbox.util.blob :as blob])) [uxbox.util.blob :as blob]))
@ -220,32 +220,32 @@
(ex/raise :type :validation (ex/raise :type :validation
:code :not-authorized)))) :code :not-authorized))))
;; --- Query: Images of the File ;; ;; --- Query: Images of the File
;;
(declare retrieve-file-images) ;; (declare retrieve-file-images)
;;
(s/def ::file-images ;; (s/def ::file-images
(s/keys :req-un [::profile-id ::file-id])) ;; (s/keys :req-un [::profile-id ::file-id]))
;;
(sq/defquery ::file-images ;; (sq/defquery ::file-images
[{:keys [profile-id file-id] :as params}] ;; [{:keys [profile-id file-id] :as params}]
(db/with-atomic [conn db/pool] ;; (db/with-atomic [conn db/pool]
(check-edition-permissions! conn profile-id file-id) ;; (check-edition-permissions! conn profile-id file-id)
(retrieve-file-images conn params))) ;; (retrieve-file-images conn params)))
;;
(def ^:private sql:file-images ;; (def ^:private sql:file-images
"select fi.* ;; "select fi.*
from file_image as fi ;; from file_image as fi
where fi.file_id = ? ;; where fi.file_id = ?
and fi.deleted_at is null") ;; and fi.deleted_at is null")
;;
(defn retrieve-file-images ;; (defn retrieve-file-images
[conn {:keys [file-id] :as params}] ;; [conn {:keys [file-id] :as params}]
(let [sqlv [sql:file-images file-id] ;; (let [sqlv [sql:file-images file-id]
xf (comp (map #(images/resolve-urls % :path :uri)) ;; xf (comp (map #(media/resolve-urls % :path :uri))
(map #(images/resolve-urls % :thumb-path :thumb-uri)))] ;; (map #(media/resolve-urls % :thumb-path :thumb-uri)))]
(->> (db/exec! conn sqlv) ;; (->> (db/exec! conn sqlv)
(into [] xf)))) ;; (into [] xf))))
;; --- Query: File (By ID) ;; --- Query: File (By ID)
@ -284,7 +284,7 @@
(defn retrieve-file-users (defn retrieve-file-users
[conn id] [conn id]
(->> (db/exec! conn [sql:file-users id 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/def ::file-users
(s/keys :req-un [::profile-id ::id])) (s/keys :req-un [::profile-id ::id]))

View File

@ -1,148 +1,148 @@
;; This Source Code Form is subject to the terms of the Mozilla Public ;; ;; 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 ;; ;; 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/. ;; ;; 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 ;; (ns uxbox.services.queries.icons
;; defined by the Mozilla Public License, v. 2.0. ;; (: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))

View File

@ -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))

View 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))

View File

@ -10,7 +10,7 @@
[uxbox.common.exceptions :as ex] [uxbox.common.exceptions :as ex]
[uxbox.common.spec :as us] [uxbox.common.spec :as us]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.images :as images] [uxbox.media :as media]
[uxbox.services.queries :as sq] [uxbox.services.queries :as sq]
[uxbox.common.uuid :as uuid] [uxbox.common.uuid :as uuid]
[uxbox.util.blob :as blob])) [uxbox.util.blob :as blob]))
@ -78,7 +78,7 @@
(defn retrieve-profile (defn retrieve-profile
[conn id] [conn id]
(let [profile (some-> (retrieve-profile-data 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) (strip-private-attrs)
(merge (retrieve-additional-data conn id)))] (merge (retrieve-additional-data conn id)))]
(when (nil? profile) (when (nil? profile)

View File

@ -16,10 +16,9 @@
[uxbox.common.spec :as us] [uxbox.common.spec :as us]
[uxbox.common.uuid :as uuid] [uxbox.common.uuid :as uuid]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.images :as images]
[uxbox.media :as media]
[uxbox.services.queries :as sq] [uxbox.services.queries :as sq]
[uxbox.services.queries.files :as files] [uxbox.services.queries.files :as files]
[uxbox.services.queries.media :as media-queries]
[uxbox.services.queries.pages :as pages] [uxbox.services.queries.pages :as pages]
[uxbox.util.blob :as blob] [uxbox.util.blob :as blob]
[uxbox.util.data :as data])) [uxbox.util.data :as data]))
@ -52,7 +51,7 @@
(db/with-atomic [conn db/pool] (db/with-atomic [conn db/pool]
(let [page (pages/retrieve-page conn page-id) (let [page (pages/retrieve-page conn page-id)
file (files/retrieve-file conn (:file-id page)) 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))] project (retrieve-project conn (:project-id file))]
(if (string? share-token) (if (string? share-token)
(when (not= share-token (:share-token page)) (when (not= share-token (:share-token page))

View File

@ -18,7 +18,7 @@
[uxbox.common.spec :as us] [uxbox.common.spec :as us]
[uxbox.config :as cfg] [uxbox.config :as cfg]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.media :as media] [uxbox.media-storage :as mst]
[uxbox.util.blob :as blob] [uxbox.util.blob :as blob]
[uxbox.util.storage :as ust])) [uxbox.util.storage :as ust]))
@ -39,8 +39,8 @@
(run! (fn [item] (run! (fn [item]
(let [path1 (get item "path") (let [path1 (get item "path")
path2 (get item "thumb_path")] path2 (get item "thumb_path")]
(ust/delete! media/media-storage path1) (ust/delete! mst/media-storage path1)
(ust/delete! media/media-storage path2))) (ust/delete! mst/media-storage path2)))
result)) result))
(defn- decode-row (defn- decode-row

View File

@ -14,7 +14,7 @@
[clojure.tools.logging :as log] [clojure.tools.logging :as log]
[uxbox.common.exceptions :as ex] [uxbox.common.exceptions :as ex]
[uxbox.common.spec :as us] [uxbox.common.spec :as us]
[uxbox.media :as media] [uxbox.media-storage :as mst]
[uxbox.metrics :as mtx] [uxbox.metrics :as mtx]
[uxbox.util.storage :as ust])) [uxbox.util.storage :as ust]))
@ -25,8 +25,8 @@
(defn handler (defn handler
[{:keys [props] :as task}] [{:keys [props] :as task}]
(us/verify ::props props) (us/verify ::props props)
(when (ust/exists? media/media-storage (:path props)) (when (ust/exists? mst/media-storage (:path props))
(ust/delete! media/media-storage (:path props)) (ust/delete! mst/media-storage (:path props))
(log/debug "Media " (:path props) " removed."))) (log/debug "Media " (:path props) " removed.")))
(mtx/instrument-with-summary! (mtx/instrument-with-summary!

View File

@ -14,13 +14,12 @@
[uxbox.services.mutations.teams :as teams] [uxbox.services.mutations.teams :as teams]
[uxbox.services.mutations.files :as files] [uxbox.services.mutations.files :as files]
[uxbox.services.mutations.pages :as pages] [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.services.mutations.colors :as colors]
[uxbox.fixtures :as fixtures] [uxbox.fixtures :as fixtures]
[uxbox.migrations] [uxbox.migrations]
[uxbox.images]
[uxbox.media] [uxbox.media]
[uxbox.media-storage]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.util.blob :as blob] [uxbox.util.blob :as blob]
[uxbox.common.uuid :as uuid] [uxbox.common.uuid :as uuid]
@ -45,12 +44,12 @@
#'uxbox.db/pool #'uxbox.db/pool
#'uxbox.redis/client #'uxbox.redis/client
#'uxbox.redis/conn #'uxbox.redis/conn
#'uxbox.images/semaphore #'uxbox.media/semaphore
#'uxbox.services.init/query-services #'uxbox.services.init/query-services
#'uxbox.services.init/mutation-services #'uxbox.services.init/mutation-services
#'uxbox.migrations/migrations #'uxbox.migrations/migrations
#'uxbox.media/assets-storage #'uxbox.media-storage/assets-storage
#'uxbox.media/media-storage}) #'uxbox.media-storage/media-storage})
(mount/swap {#'uxbox.config/config config (mount/swap {#'uxbox.config/config config
#'uxbox.db/pool pool}) #'uxbox.db/pool pool})
(mount/start))) (mount/start)))
@ -73,8 +72,8 @@
(try (try
(next) (next)
(finally (finally
(ust/clear! uxbox.media/media-storage) (ust/clear! uxbox.media-storage/media-storage)
(ust/clear! uxbox.media/assets-storage)))) (ust/clear! uxbox.media-storage/assets-storage))))
(defn mk-uuid (defn mk-uuid
[prefix & args] [prefix & args]
@ -105,10 +104,11 @@
:name (str "project" i)})) :name (str "project" i)}))
(defn create-file (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) (#'files/create-file conn {:id (mk-uuid "file" i)
:profile-id profile-id :profile-id profile-id
:project-id project-id :project-id project-id
:is-shared is-shared
:name (str "file" i)})) :name (str "file" i)}))
(defn create-page (defn create-page
@ -120,23 +120,22 @@
:ordering i :ordering i
:data cp/default-page-data})) :data cp/default-page-data}))
;; (defn create-image-library
(defn create-image-library ;; [conn team-id i]
[conn team-id i] ;; (#'images/create-library conn {:id (mk-uuid "imgcoll" i)
(#'images/create-library conn {:id (mk-uuid "imgcoll" i) ;; :team-id team-id
:team-id team-id ;; :name (str "image library " i)}))
:name (str "image library " i)})) ;;
;; (defn create-icon-library
(defn create-icon-library ;; [conn team-id i]
[conn team-id i] ;; (#'icons/create-library conn {:id (mk-uuid "imgcoll" i)
(#'icons/create-library conn {:id (mk-uuid "imgcoll" i) ;; :team-id team-id
:team-id team-id ;; :name (str "icon library " i)}))
:name (str "icon library " i)})) ;; (defn create-color-library
(defn create-color-library ;; [conn team-id i]
[conn team-id i] ;; (#'colors/create-library conn {:id (mk-uuid "imgcoll" i)
(#'colors/create-library conn {:id (mk-uuid "imgcoll" i) ;; :team-id team-id
:team-id team-id ;; :name (str "color library " i)}))
:name (str "color library " i)}))
(defn handle-error (defn handle-error
[^Throwable err] [^Throwable err]

View File

@ -22,74 +22,77 @@
(t/use-fixtures :once th/state-init) (t/use-fixtures :once th/state-init)
(t/use-fixtures :each th/database-reset) (t/use-fixtures :each th/database-reset)
(t/deftest color-libraries-crud ;; (t/deftest color-libraries-crud
(let [id (uuid/next) ;; (let [id (uuid/next)
prof (th/create-profile db/pool 2) ;; prof (th/create-profile db/pool 2)
team-id (:default-team-id prof)] ;; team-id (:default-team-id prof)
;; proj (th/create-project db/pool (:id prof) team-id 2)]
(t/testing "create library" ;;
(let [data {::sm/type :create-color-library ;; (t/testing "create library file"
:name "sample library" ;; (let [data {::sm/type :create-file
:profile-id (:id prof) ;; :profile-id (:id prof)
:team-id team-id ;; :name "sample library"
:id id} ;; :project-id (:id proj)
out (th/try-on! (sm/handle data))] ;; :id id
;; :is-shared true}
;; (th/print-result! out) ;; out (th/try-on! (sm/handle data))]
(t/is (nil? (:error out))) ;;
;; ;; (th/print-result! out)
(let [result (:result out)] ;; (t/is (nil? (:error out)))
(t/is (= id (:id result))) ;;
(t/is (= team-id (:team-id result))) ;; (let [result (:result out)]
(t/is (= (:name data) (:name result)))))) ;; (t/is (= id (:id result)))
;; (t/is (= (:id proj) (:project-id result)))
(t/testing "update library" ;; (t/is (= (:name data) (:name result))))))
(let [data {::sm/type :rename-color-library ;;
:name "renamed" ;; (t/testing "update library file"
:profile-id (:id prof) ;; (let [data {::sm/type :rename-color-library
:id id} ;; :name "renamed"
out (th/try-on! (sm/handle data))] ;; :profile-id (:id prof)
;; :id id}
;; (th/print-result! out) ;; out (th/try-on! (sm/handle data))]
(t/is (nil? (:error out))) ;;
;; ;; (th/print-result! out)
(let [result (:result out)] ;; (t/is (nil? (:error out)))
(t/is (= "renamed" (get-in result [:name])))))) ;;
;; (let [result (:result out)]
(t/testing "delete library" ;; (t/is (= "renamed" (get-in result [:name]))))))
(let [data {::sm/type :delete-color-library ;;
:profile-id (:id prof) ;; (t/testing "delete library"
:id id} ;; (let [data {::sm/type :delete-color-library
;; :profile-id (:id prof)
out (th/try-on! (sm/handle data))] ;; :id id}
;;
;; (th/print-result! out) ;; out (th/try-on! (sm/handle data))]
(t/is (nil? (:error out))) ;;
(t/is (nil? (:result out))))) ;; ;; (th/print-result! out)
;; (t/is (nil? (:error out)))
(t/testing "query libraries after delete" ;; (t/is (nil? (:result out)))))
(let [data {::sq/type :color-libraries ;;
:profile-id (:id prof) ;; (t/testing "query libraries after delete"
:team-id team-id} ;; (let [data {::sq/type :color-libraries
out (th/try-on! (sq/handle data))] ;; :profile-id (:id prof)
;; :team-id team-id}
;; (th/print-result! out) ;; out (th/try-on! (sq/handle data))]
(t/is (nil? (:error out))) ;;
(let [result (:result out)] ;; ;; (th/print-result! out)
(t/is (= 0 (count result)))))) ;; (t/is (nil? (:error out)))
)) ;; (let [result (:result out)]
;; (t/is (= 0 (count result))))))
;; ))
(t/deftest colors-crud (t/deftest colors-crud
(let [prof (th/create-profile db/pool 1) (let [prof (th/create-profile db/pool 1)
team-id (:default-team-id prof) 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)] color-id (uuid/next)]
(t/testing "upload color to library" (t/testing "upload color to library"
(let [data {::sm/type :create-color (let [data {::sm/type :create-color
:id color-id :id color-id
:profile-id (:id prof) :profile-id (:id prof)
:library-id (:id coll) :file-id (:id file)
:name "testfile" :name "testfile"
:content "#222222"} :content "#222222"}
out (th/try-on! (sm/handle data))] out (th/try-on! (sm/handle data))]
@ -102,17 +105,17 @@
(t/is (= (:name data) (:name result))) (t/is (= (:name data) (:name result)))
(t/is (= (:content data) (:content 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 (let [data {::sq/type :colors
:profile-id (:id prof) :profile-id (:id prof)
:library-id (:id coll)} :file-id (:id file)}
out (th/try-on! (sq/handle data))] out (th/try-on! (sq/handle data))]
;; (th/print-result! out) ;; (th/print-result! out)
(t/is (= color-id (get-in out [:result 0 :id]))) (t/is (= color-id (get-in out [:result 0 :id])))
(t/is (= "testfile" (get-in out [:result 0 :name]))))) (t/is (= "testfile" (get-in out [:result 0 :name])))))
(t/testing "single color" (t/testing "get single color"
(let [data {::sq/type :color (let [data {::sq/type :color
:profile-id (:id prof) :profile-id (:id prof)
:id color-id} :id color-id}
@ -150,7 +153,7 @@
(t/testing "query colors after delete" (t/testing "query colors after delete"
(let [data {::sq/type :colors (let [data {::sq/type :colors
:profile-id (:id prof) :profile-id (:id prof)
:library-id (:id coll)} :file-id (:id file)}
out (th/try-on! (sq/handle data))] out (th/try-on! (sq/handle data))]
;; (th/print-result! out) ;; (th/print-result! out)
(let [result (:result out)] (let [result (:result out)]

View File

@ -14,7 +14,6 @@
[uxbox.common.uuid :as uuid] [uxbox.common.uuid :as uuid]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.http :as http] [uxbox.http :as http]
[uxbox.media :as media]
[uxbox.services.mutations :as sm] [uxbox.services.mutations :as sm]
[uxbox.services.queries :as sq] [uxbox.services.queries :as sq]
[uxbox.tests.helpers :as th] [uxbox.tests.helpers :as th]
@ -35,6 +34,7 @@
:profile-id (:id prof) :profile-id (:id prof)
:project-id proj-id :project-id proj-id
:id file-id :id file-id
:is-shared false
:name "test file"} :name "test file"}
out (th/try-on! (sm/handle data))] out (th/try-on! (sm/handle data))]
@ -129,105 +129,105 @@
(t/is (= 0 (count result)))))) (t/is (= 0 (count result))))))
)) ))
(t/deftest file-images-crud ;; (t/deftest file-images-crud
(let [prof (th/create-profile db/pool 1) ;; (let [prof (th/create-profile db/pool 1)
team-id (:default-team-id prof) ;; team-id (:default-team-id prof)
proj-id (:default-project-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 1)]
;;
(t/testing "create file image from url" ;; (t/testing "create file image from url"
(let [url "https://raw.githubusercontent.com/uxbox/uxbox/develop/frontend/resources/images/penpot-login.jpg" ;; (let [url "https://raw.githubusercontent.com/uxbox/uxbox/develop/frontend/resources/images/penpot-login.jpg"
data {::sm/type :add-file-image-from-url ;; data {::sm/type :add-file-image-from-url
:profile-id (:id prof) ;; :profile-id (:id prof)
:file-id (:id file) ;; :file-id (:id file)
:url url} ;; :url url}
out (th/try-on! (sm/handle data))] ;; out (th/try-on! (sm/handle data))]
;;
;; (th/print-result! out) ;; ;; (th/print-result! out)
(t/is (nil? (:error out))) ;; (t/is (nil? (:error out)))
;;
(let [result (:result out)] ;; (let [result (:result out)]
(t/is (= (:id file) (:file-id result))) ;; (t/is (= (:id file) (:file-id result)))
(t/is (not (nil? (:name result)))) ;; (t/is (not (nil? (:name result))))
(t/is (= 787 (:width result))) ;; (t/is (= 787 (:width result)))
(t/is (= 2000 (:height result))) ;; (t/is (= 2000 (:height result)))
(t/is (= "image/jpeg" (:mtype result))) ;; (t/is (= "image/jpeg" (:mtype result)))
;;
(t/is (string? (:path result))) ;; (t/is (string? (:path result)))
(t/is (string? (:uri result))) ;; (t/is (string? (:uri result)))
(t/is (string? (:thumb-path result))) ;; (t/is (string? (:thumb-path result)))
(t/is (string? (:thumb-uri result)))))) ;; (t/is (string? (:thumb-uri result))))))
;;
(t/testing "upload file image" ;; (t/testing "upload file image"
(let [content {:filename "sample.jpg" ;; (let [content {:filename "sample.jpg"
:tempfile (th/tempfile "uxbox/tests/_files/sample.jpg") ;; :tempfile (th/tempfile "uxbox/tests/_files/sample.jpg")
:content-type "image/jpeg" ;; :content-type "image/jpeg"
:size 312043} ;; :size 312043}
data {::sm/type :upload-file-image ;; data {::sm/type :upload-file-image
:profile-id (:id prof) ;; :profile-id (:id prof)
:file-id (:id file) ;; :file-id (:id file)
:name "testfile" ;; :name "testfile"
:content content} ;; :content content}
;;
out (th/try-on! (sm/handle data))] ;; out (th/try-on! (sm/handle data))]
;;
;; (th/print-result! out) ;; ;; (th/print-result! out)
(t/is (nil? (:error out))) ;; (t/is (nil? (:error out)))
;;
(let [result (:result out)] ;; (let [result (:result out)]
(t/is (= (:id file) (:file-id result))) ;; (t/is (= (:id file) (:file-id result)))
(t/is (= (:name data) (:name result))) ;; (t/is (= (:name data) (:name result)))
(t/is (= 800 (:width result))) ;; (t/is (= 800 (:width result)))
(t/is (= 800 (:height result))) ;; (t/is (= 800 (:height result)))
(t/is (= (:content-type content) (:mtype result))) ;; (t/is (= (:content-type content) (:mtype result)))
;;
(t/is (string? (:path result))) ;; (t/is (string? (:path result)))
(t/is (string? (:uri result))) ;; (t/is (string? (:uri result)))
(t/is (string? (:thumb-path result))) ;; (t/is (string? (:thumb-path result)))
(t/is (string? (:thumb-uri result)))))) ;; (t/is (string? (:thumb-uri result))))))
;;
(t/testing "import from library" ;; ;; (t/testing "import from library"
(let [lib (th/create-image-library db/pool team-id 1) ;; ;; (let [lib (th/create-image-library db/pool team-id 1)
image-id (uuid/next) ;; ;; image-id (uuid/next)
;; ;;
content {:filename "sample.jpg" ;; ;; content {:filename "sample.jpg"
:tempfile (th/tempfile "uxbox/tests/_files/sample.jpg") ;; ;; :tempfile (th/tempfile "uxbox/tests/_files/sample.jpg")
:content-type "image/jpeg" ;; ;; :content-type "image/jpeg"
:size 312043} ;; ;; :size 312043}
;; ;;
data {::sm/type :upload-image ;; ;; data {::sm/type :upload-image
:id image-id ;; ;; :id image-id
:profile-id (:id prof) ;; ;; :profile-id (:id prof)
:library-id (:id lib) ;; ;; :library-id (:id lib)
:name "testfile" ;; ;; :name "testfile"
:content content} ;; ;; :content content}
out1 (th/try-on! (sm/handle data))] ;; ;; out1 (th/try-on! (sm/handle data))]
;; ;;
;; (th/print-result! out1) ;; ;; ;; (th/print-result! out1)
(t/is (nil? (:error out1))) ;; ;; (t/is (nil? (:error out1)))
;; ;;
(let [result (:result out1)] ;; ;; (let [result (:result out1)]
(t/is (= image-id (:id result))) ;; ;; (t/is (= image-id (:id result)))
(t/is (= "testfile" (:name result))) ;; ;; (t/is (= "testfile" (:name result)))
(t/is (= "image/jpeg" (:mtype result))) ;; ;; (t/is (= "image/jpeg" (:mtype result)))
(t/is (= "image/jpeg" (:thumb-mtype result)))) ;; ;; (t/is (= "image/jpeg" (:thumb-mtype result))))
;; ;;
(let [data2 {::sm/type :import-image-to-file ;; ;; (let [data2 {::sm/type :import-image-to-file
:image-id image-id ;; ;; :image-id image-id
:file-id (:id file) ;; ;; :file-id (:id file)
:profile-id (:id prof)} ;; ;; :profile-id (:id prof)}
out2 (th/try-on! (sm/handle data2))] ;; ;; out2 (th/try-on! (sm/handle data2))]
;; ;;
;; (th/print-result! out2) ;; ;; ;; (th/print-result! out2)
(t/is (nil? (:error out2))) ;; ;; (t/is (nil? (:error out2)))
;; ;;
(let [result1 (:result out1) ;; ;; (let [result1 (:result out1)
result2 (:result out2)] ;; ;; result2 (:result out2)]
(t/is (not= (:path result2) ;; ;; (t/is (not= (:path result2)
(:path result1))) ;; ;; (:path result1)))
(t/is (not= (:thumb-path result2) ;; ;; (t/is (not= (:thumb-path result2)
(:thumb-path result1))))))) ;; ;; (:thumb-path result1)))))))
)) ;; ))
;; TODO: delete file image ;; TODO: delete file image

View File

@ -19,162 +19,162 @@
[uxbox.tests.helpers :as th] [uxbox.tests.helpers :as th]
[uxbox.util.storage :as ust])) [uxbox.util.storage :as ust]))
(t/use-fixtures :once th/state-init) ;; (t/use-fixtures :once th/state-init)
(t/use-fixtures :each th/database-reset) ;; (t/use-fixtures :each th/database-reset)
;;
(t/deftest icon-libraries-crud ;; (t/deftest icon-libraries-crud
(let [id (uuid/next) ;; (let [id (uuid/next)
prof (th/create-profile db/pool 2) ;; prof (th/create-profile db/pool 2)
team-id (:default-team-id prof)] ;; team-id (:default-team-id prof)]
;;
(t/testing "create library" ;; (t/testing "create library"
(let [data {::sm/type :create-icon-library ;; (let [data {::sm/type :create-icon-library
:name "sample library" ;; :name "sample library"
:profile-id (:id prof) ;; :profile-id (:id prof)
:team-id team-id ;; :team-id team-id
:id id} ;; :id id}
out (th/try-on! (sm/handle data))] ;; out (th/try-on! (sm/handle data))]
;;
;; (th/print-result! out) ;; ;; (th/print-result! out)
(t/is (nil? (:error out))) ;; (t/is (nil? (:error out)))
;;
(let [result (:result out)] ;; (let [result (:result out)]
(t/is (= id (:id result))) ;; (t/is (= id (:id result)))
(t/is (= team-id (:team-id result))) ;; (t/is (= team-id (:team-id result)))
(t/is (= (:name data) (:name result)))))) ;; (t/is (= (:name data) (:name result))))))
;;
(t/testing "rename library" ;; (t/testing "rename library"
(let [data {::sm/type :rename-icon-library ;; (let [data {::sm/type :rename-icon-library
:name "renamed" ;; :name "renamed"
:profile-id (:id prof) ;; :profile-id (:id prof)
:team-id team-id ;; :team-id team-id
:id id} ;; :id id}
out (th/try-on! (sm/handle data))] ;; out (th/try-on! (sm/handle data))]
;;
;; (th/print-result! out) ;; ;; (th/print-result! out)
(t/is (nil? (:error out))) ;; (t/is (nil? (:error out)))
;;
(let [result (:result out)] ;; (let [result (:result out)]
(t/is (= id (:id result))) ;; (t/is (= id (:id result)))
(t/is (= "renamed" (:name result)))))) ;; (t/is (= "renamed" (:name result))))))
;;
(t/testing "query libraries" ;; (t/testing "query libraries"
(let [data {::sq/type :icon-libraries ;; (let [data {::sq/type :icon-libraries
:profile-id (:id prof) ;; :profile-id (:id prof)
:team-id team-id} ;; :team-id team-id}
out (th/try-on! (sq/handle data))] ;; out (th/try-on! (sq/handle data))]
;;
;; (th/print-result! out) ;; ;; (th/print-result! out)
(t/is (nil? (:error out))) ;; (t/is (nil? (:error out)))
;;
(let [result (:result out)] ;; (let [result (:result out)]
(t/is (= 1 (count result))) ;; (t/is (= 1 (count result)))
(t/is (= id (get-in result [0 :id]))) ;; (t/is (= id (get-in result [0 :id])))
(t/is (= "renamed" (get-in result [0 :name])))))) ;; (t/is (= "renamed" (get-in result [0 :name]))))))
;;
(t/testing "delete library" ;; (t/testing "delete library"
(let [data {::sm/type :delete-icon-library ;; (let [data {::sm/type :delete-icon-library
:profile-id (:id prof) ;; :profile-id (:id prof)
:id id} ;; :id id}
;;
out (th/try-on! (sm/handle data))] ;; out (th/try-on! (sm/handle data))]
;;
;; (th/print-result! out) ;; ;; (th/print-result! out)
(t/is (nil? (:error out))) ;; (t/is (nil? (:error out)))
(t/is (nil? (:result out))))) ;; (t/is (nil? (:result out)))))
;;
(t/testing "query libraries after delete" ;; (t/testing "query libraries after delete"
(let [data {::sq/type :icon-libraries ;; (let [data {::sq/type :icon-libraries
:profile-id (:id prof) ;; :profile-id (:id prof)
:team-id team-id} ;; :team-id team-id}
out (th/try-on! (sq/handle data))] ;; out (th/try-on! (sq/handle data))]
;;
;; (th/print-result! out) ;; ;; (th/print-result! out)
(t/is (nil? (:error out))) ;; (t/is (nil? (:error out)))
;;
(let [result (:result out)] ;; (let [result (:result out)]
(t/is (= 0 (count result)))))) ;; (t/is (= 0 (count result))))))
)) ;; ))
;;
(t/deftest icons-crud ;; (t/deftest icons-crud
(let [prof (th/create-profile db/pool 1) ;; (let [prof (th/create-profile db/pool 1)
team-id (:default-team-id prof) ;; team-id (:default-team-id prof)
coll (th/create-icon-library db/pool team-id 1) ;; coll (th/create-icon-library db/pool team-id 1)
icon-id (uuid/next)] ;; icon-id (uuid/next)]
;;
(t/testing "upload icon to library" ;; (t/testing "upload icon to library"
(let [data {::sm/type :create-icon ;; (let [data {::sm/type :create-icon
:id icon-id ;; :id icon-id
:profile-id (:id prof) ;; :profile-id (:id prof)
:library-id (:id coll) ;; :library-id (:id coll)
:name "testfile" ;; :name "testfile"
:content "<rect></rect>" ;; :content "<rect></rect>"
:metadata {:width 100 ;; :metadata {:width 100
:height 100 ;; :height 100
:view-box [0 0 100 100] ;; :view-box [0 0 100 100]
:mimetype "text/svg"}} ;; :mimetype "text/svg"}}
out (th/try-on! (sm/handle data))] ;; out (th/try-on! (sm/handle data))]
;;
;; (th/print-result! out) ;; ;; (th/print-result! out)
(t/is (nil? (:error out))) ;; (t/is (nil? (:error out)))
;;
(let [result (:result out)] ;; (let [result (:result out)]
(t/is (= (:id data) (:id result))) ;; (t/is (= (:id data) (:id result)))
(t/is (= (:name data) (:name result))) ;; (t/is (= (:name data) (:name result)))
(t/is (= (:content data) (:content result)))))) ;; (t/is (= (:content data) (:content result))))))
;;
(t/testing "list icons by library" ;; (t/testing "list icons by library"
(let [data {::sq/type :icons ;; (let [data {::sq/type :icons
:profile-id (:id prof) ;; :profile-id (:id prof)
:library-id (:id coll)} ;; :library-id (:id coll)}
out (th/try-on! (sq/handle data))] ;; out (th/try-on! (sq/handle data))]
;; (th/print-result! out) ;; ;; (th/print-result! out)
;;
(t/is (= icon-id (get-in out [:result 0 :id]))) ;; (t/is (= icon-id (get-in out [:result 0 :id])))
(t/is (= "testfile" (get-in out [:result 0 :name]))))) ;; (t/is (= "testfile" (get-in out [:result 0 :name])))))
;;
(t/testing "single icon" ;; (t/testing "single icon"
(let [data {::sq/type :icon ;; (let [data {::sq/type :icon
:profile-id (:id prof) ;; :profile-id (:id prof)
:id icon-id} ;; :id icon-id}
out (th/try-on! (sq/handle data))] ;; out (th/try-on! (sq/handle data))]
;; (th/print-result! out) ;; ;; (th/print-result! out)
;;
(t/is (= icon-id (get-in out [:result :id]))) ;; (t/is (= icon-id (get-in out [:result :id])))
(t/is (= "testfile" (get-in out [:result :name]))))) ;; (t/is (= "testfile" (get-in out [:result :name])))))
;;
(t/testing "delete icons" ;; (t/testing "delete icons"
(let [data {::sm/type :delete-icon ;; (let [data {::sm/type :delete-icon
:profile-id (:id prof) ;; :profile-id (:id prof)
:id icon-id} ;; :id icon-id}
out (th/try-on! (sm/handle data))] ;; out (th/try-on! (sm/handle data))]
;;
;; (th/print-result! out) ;; ;; (th/print-result! out)
(t/is (nil? (:error out))) ;; (t/is (nil? (:error out)))
(t/is (nil? (:result out))))) ;; (t/is (nil? (:result out)))))
;;
(t/testing "query icon after delete" ;; (t/testing "query icon after delete"
(let [data {::sq/type :icon ;; (let [data {::sq/type :icon
:profile-id (:id prof) ;; :profile-id (:id prof)
:id icon-id} ;; :id icon-id}
out (th/try-on! (sq/handle data))] ;; out (th/try-on! (sq/handle data))]
;;
;; (th/print-result! out) ;; ;; (th/print-result! out)
(let [error (:error out)] ;; (let [error (:error out)]
(t/is (th/ex-info? error)) ;; (t/is (th/ex-info? error))
(t/is (th/ex-of-type? error :service-error))) ;; (t/is (th/ex-of-type? error :service-error)))
;;
(let [error (ex-cause (:error out))] ;; (let [error (ex-cause (:error out))]
(t/is (th/ex-info? error)) ;; (t/is (th/ex-info? error))
(t/is (th/ex-of-type? error :not-found))))) ;; (t/is (th/ex-of-type? error :not-found)))))
;;
(t/testing "query icons after delete" ;; (t/testing "query icons after delete"
(let [data {::sq/type :icons ;; (let [data {::sq/type :icons
:profile-id (:id prof) ;; :profile-id (:id prof)
:library-id (:id coll)} ;; :library-id (:id coll)}
out (th/try-on! (sq/handle data))] ;; out (th/try-on! (sq/handle data))]
;;
;; (th/print-result! out) ;; ;; (th/print-result! out)
(let [result (:result out)] ;; (let [result (:result out)]
(t/is (= 0 (count result)))))) ;; (t/is (= 0 (count result))))))
)) ;; ))

View File

@ -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))))))
))

View 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))))))
))

View File

@ -27,7 +27,7 @@
(let [prof (th/create-profile db/pool 1) (let [prof (th/create-profile db/pool 1)
team-id (:default-team-id prof) team-id (:default-team-id prof)
proj-id (:default-project-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)] page-id (uuid/next)]
(t/testing "create page" (t/testing "create page"
@ -104,7 +104,7 @@
(let [prof (th/create-profile db/pool 1) (let [prof (th/create-profile db/pool 1)
team-id (:default-team-id prof) team-id (:default-team-id prof)
proj-id (:default-project-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)] page-id (uuid/next)]
(t/testing "create empty page" (t/testing "create empty page"
@ -182,7 +182,7 @@
(let [prof (th/create-profile db/pool 1) (let [prof (th/create-profile db/pool 1)
team-id (:default-team-id prof) team-id (:default-team-id prof)
proj-id (:default-project-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)] page (th/create-page db/pool (:id prof) (:id file) 1)]
(t/testing "lagging changes" (t/testing "lagging changes"

View File

@ -14,7 +14,6 @@
[uxbox.common.uuid :as uuid] [uxbox.common.uuid :as uuid]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.http :as http] [uxbox.http :as http]
[uxbox.media :as media]
[uxbox.services.mutations :as sm] [uxbox.services.mutations :as sm]
[uxbox.services.queries :as sq] [uxbox.services.queries :as sq]
[uxbox.tests.helpers :as th] [uxbox.tests.helpers :as th]
@ -29,7 +28,7 @@
team-id (:default-team-id prof) team-id (:default-team-id prof)
proj-id (:default-project-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) page (th/create-page db/pool (:id prof) (:id file) 1)
token (atom nil)] token (atom nil)]