mirror of
https://github.com/penpot/penpot.git
synced 2025-05-18 18:36:12 +02:00
♻️ Restructure the services directory.
This commit is contained in:
parent
eeb5482d36
commit
b66bc02098
45 changed files with 951 additions and 960 deletions
|
@ -5,6 +5,7 @@
|
||||||
</Console>
|
</Console>
|
||||||
</Appenders>
|
</Appenders>
|
||||||
<Loggers>
|
<Loggers>
|
||||||
|
<Logger name="io.vertx.sqlclient.impl.SocketConnectionBase" level="INFO"/>
|
||||||
<Root level="info">
|
<Root level="info">
|
||||||
<AppenderRef ref="console"/>
|
<AppenderRef ref="console"/>
|
||||||
</Root>
|
</Root>
|
||||||
|
|
|
@ -13,6 +13,28 @@ CREATE TABLE users (
|
||||||
metadata bytea NOT NULL
|
metadata bytea NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS user_storage (
|
||||||
|
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
||||||
|
modified_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
||||||
|
|
||||||
|
key text NOT NULL,
|
||||||
|
val bytea NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (key, user_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE user_tokens (
|
||||||
|
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
token text NOT NULL,
|
||||||
|
|
||||||
|
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
||||||
|
used_at timestamptz DEFAULT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (token, user_id)
|
||||||
|
);
|
||||||
|
|
||||||
CREATE TABLE sessions (
|
CREATE TABLE sessions (
|
||||||
id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
|
||||||
|
@ -24,6 +46,7 @@ CREATE TABLE sessions (
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Insert a placeholder system user.
|
-- Insert a placeholder system user.
|
||||||
|
|
||||||
INSERT INTO users (id, fullname, username, email, photo, password, metadata)
|
INSERT INTO users (id, fullname, username, email, photo, password, metadata)
|
||||||
VALUES ('00000000-0000-0000-0000-000000000000'::uuid,
|
VALUES ('00000000-0000-0000-0000-000000000000'::uuid,
|
||||||
'System User',
|
'System User',
|
||||||
|
@ -44,18 +67,6 @@ CREATE UNIQUE INDEX users_email_idx
|
||||||
CREATE TRIGGER users_modified_at_tgr BEFORE UPDATE ON users
|
CREATE TRIGGER users_modified_at_tgr BEFORE UPDATE ON users
|
||||||
FOR EACH ROW EXECUTE PROCEDURE update_modified_at();
|
FOR EACH ROW EXECUTE PROCEDURE update_modified_at();
|
||||||
|
|
||||||
CREATE TABLE user_pswd_recovery (
|
CREATE TRIGGER user_storage_modified_at_tgr BEFORE UPDATE ON user_storage
|
||||||
id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
|
FOR EACH ROW EXECUTE PROCEDURE update_modified_at();
|
||||||
user_id uuid REFERENCES users(id) ON DELETE CASCADE,
|
|
||||||
token text NOT NULL,
|
|
||||||
|
|
||||||
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
||||||
used_at timestamptz DEFAULT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE INDEX user_pswd_recovery_user_idx
|
|
||||||
ON user_pswd_recovery USING btree (user_id);
|
|
||||||
|
|
||||||
CREATE UNIQUE INDEX user_pswd_recovery_token_idx
|
|
||||||
ON user_pswd_recovery USING btree (token);
|
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
CREATE TABLE IF NOT EXISTS kvstore (
|
|
||||||
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
||||||
|
|
||||||
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
||||||
modified_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
||||||
|
|
||||||
key text NOT NULL,
|
|
||||||
value bytea NOT NULL,
|
|
||||||
|
|
||||||
PRIMARY KEY (key, user_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TRIGGER kvstore_modified_at_tgr BEFORE UPDATE ON kvstore
|
|
||||||
FOR EACH ROW EXECUTE PROCEDURE update_modified_at();
|
|
|
@ -1 +0,0 @@
|
||||||
select version();
|
|
|
@ -16,7 +16,6 @@
|
||||||
[uxbox.http.session :as session]
|
[uxbox.http.session :as session]
|
||||||
[uxbox.http.handlers :as handlers]
|
[uxbox.http.handlers :as handlers]
|
||||||
[uxbox.http.debug :as debug]
|
[uxbox.http.debug :as debug]
|
||||||
[uxbox.services.core :as sv]
|
|
||||||
[vertx.core :as vc]
|
[vertx.core :as vc]
|
||||||
[vertx.http :as vh]
|
[vertx.http :as vh]
|
||||||
[vertx.web :as vw]
|
[vertx.web :as vw]
|
||||||
|
@ -62,6 +61,7 @@
|
||||||
(vw/assets "/static/*" {:root "resources/public/static"})
|
(vw/assets "/static/*" {:root "resources/public/static"})
|
||||||
(vw/router routes))]
|
(vw/router routes))]
|
||||||
|
|
||||||
|
(log/info "Starting http server on" (:http-server-port cfg/config) "port.")
|
||||||
(vh/server ctx {:handler handler
|
(vh/server ctx {:handler handler
|
||||||
:port (:http-server-port cfg/config)})))
|
:port (:http-server-port cfg/config)})))
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
[promesa.core :as p]
|
[promesa.core :as p]
|
||||||
[uxbox.http.errors :as errors]
|
[uxbox.http.errors :as errors]
|
||||||
[uxbox.http.session :as session]
|
[uxbox.http.session :as session]
|
||||||
[uxbox.services.core :as sv]
|
|
||||||
[uxbox.util.uuid :as uuid]))
|
[uxbox.util.uuid :as uuid]))
|
||||||
|
|
||||||
(defn emails-list
|
(defn emails-list
|
||||||
|
|
|
@ -9,16 +9,18 @@
|
||||||
[promesa.core :as p]
|
[promesa.core :as p]
|
||||||
[uxbox.emails :as emails]
|
[uxbox.emails :as emails]
|
||||||
[uxbox.http.session :as session]
|
[uxbox.http.session :as session]
|
||||||
[uxbox.services.core :as sv]
|
[uxbox.services.init]
|
||||||
|
[uxbox.services.mutations :as sm]
|
||||||
|
[uxbox.services.queries :as sq]
|
||||||
[uxbox.util.uuid :as uuid]))
|
[uxbox.util.uuid :as uuid]))
|
||||||
|
|
||||||
(defn query-handler
|
(defn query-handler
|
||||||
[req]
|
[req]
|
||||||
(let [type (get-in req [:path-params :type])
|
(let [type (get-in req [:path-params :type])
|
||||||
data (merge (:params req)
|
data (merge (:params req)
|
||||||
{::sv/type (keyword type)
|
{::sq/type (keyword type)
|
||||||
:user (:user req)})]
|
:user (:user req)})]
|
||||||
(-> (sv/query (with-meta data {:req req}))
|
(-> (sq/handle (with-meta data {:req req}))
|
||||||
(p/then' (fn [result]
|
(p/then' (fn [result]
|
||||||
{:status 200
|
{:status 200
|
||||||
:body result})))))
|
:body result})))))
|
||||||
|
@ -29,9 +31,9 @@
|
||||||
data (merge (:params req)
|
data (merge (:params req)
|
||||||
(:body-params req)
|
(:body-params req)
|
||||||
(:uploads req)
|
(:uploads req)
|
||||||
{::sv/type (keyword type)
|
{::sm/type (keyword type)
|
||||||
:user (:user req)})]
|
:user (:user req)})]
|
||||||
(-> (sv/mutation (with-meta data {:req req}))
|
(-> (sm/handle (with-meta data {:req req}))
|
||||||
(p/then' (fn [result]
|
(p/then' (fn [result]
|
||||||
{:status 200 :body result})))))
|
{:status 200 :body result})))))
|
||||||
|
|
||||||
|
@ -39,7 +41,7 @@
|
||||||
[req]
|
[req]
|
||||||
(let [data (:body-params req)
|
(let [data (:body-params req)
|
||||||
user-agent (get-in req [:headers "user-agent"])]
|
user-agent (get-in req [:headers "user-agent"])]
|
||||||
(-> (sv/mutation (assoc data ::sv/type :login))
|
(-> (sm/handle (assoc data ::sm/type :login))
|
||||||
(p/then #(session/create % user-agent))
|
(p/then #(session/create % user-agent))
|
||||||
(p/then' (fn [token]
|
(p/then' (fn [token]
|
||||||
{:status 204
|
{:status 204
|
||||||
|
@ -59,9 +61,9 @@
|
||||||
(defn register-handler
|
(defn register-handler
|
||||||
[req]
|
[req]
|
||||||
(let [data (merge (:body-params req)
|
(let [data (merge (:body-params req)
|
||||||
{::sv/type :register-profile})
|
{::sm/type :register-profile})
|
||||||
user-agent (get-in req [:headers "user-agent"])]
|
user-agent (get-in req [:headers "user-agent"])]
|
||||||
(-> (sv/mutation (with-meta data {:req req}))
|
(-> (sm/handle (with-meta data {:req req}))
|
||||||
(p/then (fn [{:keys [id] :as user}]
|
(p/then (fn [{:keys [id] :as user}]
|
||||||
(session/create id user-agent)))
|
(session/create id user-agent)))
|
||||||
(p/then' (fn [token]
|
(p/then' (fn [token]
|
||||||
|
|
|
@ -19,28 +19,25 @@
|
||||||
:steps
|
:steps
|
||||||
[{:desc "Initial triggers and utils."
|
[{:desc "Initial triggers and utils."
|
||||||
:name "0001-main"
|
:name "0001-main"
|
||||||
:fn (mg/resource "migrations/0001.main.up.sql")}
|
:fn (mg/resource "migrations/0001.main.sql")}
|
||||||
{:desc "Initial auth related tables"
|
{:desc "Initial auth related tables"
|
||||||
:name "0002-auth"
|
:name "0002-users"
|
||||||
:fn (mg/resource "migrations/0002.auth.up.sql")}
|
:fn (mg/resource "migrations/0002.users.sql")}
|
||||||
{:desc "Initial projects tables"
|
{:desc "Initial projects tables"
|
||||||
:name "0003-projects"
|
:name "0003-projects"
|
||||||
:fn (mg/resource "migrations/0003.projects.up.sql")}
|
:fn (mg/resource "migrations/0003.projects.sql")}
|
||||||
{:desc "Initial pages tables"
|
{:desc "Initial pages tables"
|
||||||
:name "0004-pages"
|
:name "0004-pages"
|
||||||
:fn (mg/resource "migrations/0004.pages.up.sql")}
|
:fn (mg/resource "migrations/0004.pages.sql")}
|
||||||
{:desc "Initial kvstore tables"
|
|
||||||
:name "0005-kvstore"
|
|
||||||
:fn (mg/resource "migrations/0005.kvstore.up.sql")}
|
|
||||||
{:desc "Initial emails related tables"
|
{:desc "Initial emails related tables"
|
||||||
:name "0006-emails"
|
:name "0005-emails"
|
||||||
:fn (mg/resource "migrations/0006.emails.up.sql")}
|
:fn (mg/resource "migrations/0005.emails.sql")}
|
||||||
{:desc "Initial images tables"
|
{:desc "Initial images tables"
|
||||||
:name "0007-images"
|
:name "0006-images"
|
||||||
:fn (mg/resource "migrations/0007.images.up.sql")}
|
:fn (mg/resource "migrations/0006.images.sql")}
|
||||||
{:desc "Initial icons tables"
|
{:desc "Initial icons tables"
|
||||||
:name "0008-icons"
|
:name "0007-icons"
|
||||||
:fn (mg/resource "migrations/0008.icons.up.sql")}
|
:fn (mg/resource "migrations/0007.icons.sql")}
|
||||||
]})
|
]})
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
;;
|
|
||||||
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
|
|
||||||
|
|
||||||
(ns uxbox.portation
|
|
||||||
"Support for export/import operations of projects."
|
|
||||||
(:refer-clojure :exclude [with-open])
|
|
||||||
#_(:require [clojure.java.io :as io]
|
|
||||||
[suricatta.core :as sc]
|
|
||||||
[datoteka.core :as fs]
|
|
||||||
[uxbox.db :as db]
|
|
||||||
[uxbox.util.uuid :as uuid]
|
|
||||||
[uxbox.util.closeable :refer (with-open)]
|
|
||||||
[uxbox.util.transit :as t]))
|
|
||||||
|
|
||||||
;; ;; --- Export
|
|
||||||
|
|
||||||
;; (defn- write-project
|
|
||||||
;; [conn writer id]
|
|
||||||
;; (let [sql (sql/get-project-by-id {:id id})
|
|
||||||
;; result (sc/fetch-one conn sql)]
|
|
||||||
;; (when-not result
|
|
||||||
;; (ex-info "No project found with specified id" {:id id}))
|
|
||||||
;; (t/write! writer {::type ::project ::payload result})))
|
|
||||||
|
|
||||||
;; (defn- write-pages
|
|
||||||
;; [conn writer id]
|
|
||||||
;; (let [sql (sql/get-pages-for-project {:project id})
|
|
||||||
;; results (sc/fetch conn sql)]
|
|
||||||
;; (run! #(t/write! writer {::type ::page ::payload %}) results)))
|
|
||||||
|
|
||||||
;; (defn- write-pages-history
|
|
||||||
;; [conn writer id]
|
|
||||||
;; (let [sql (sql/get-page-history-for-project {:project id})
|
|
||||||
;; results (sc/fetch conn sql)]
|
|
||||||
;; (run! #(t/write! writer {::type ::page-history ::payload %}) results)))
|
|
||||||
|
|
||||||
;; (defn- write-data
|
|
||||||
;; [path id]
|
|
||||||
;; (with-open [ostream (io/output-stream path)
|
|
||||||
;; zstream (snappy/output-stream ostream)
|
|
||||||
;; conn (db/connection)]
|
|
||||||
;; (let [writer (t/writer zstream {:type :msgpack})]
|
|
||||||
;; (sc/atomic conn
|
|
||||||
;; (write-project conn writer id)
|
|
||||||
;; (write-pages conn writer id)
|
|
||||||
;; (write-pages-history conn writer id)))))
|
|
||||||
|
|
||||||
;; (defn export
|
|
||||||
;; "Given an id, returns a path to a temporal file with the exported
|
|
||||||
;; bundle of the specified project."
|
|
||||||
;; [id]
|
|
||||||
;; (let [path (fs/create-tempfile)]
|
|
||||||
;; (write-data path id)
|
|
||||||
;; path))
|
|
||||||
|
|
||||||
;; ;; --- Import
|
|
||||||
|
|
||||||
;; (defn- read-entry
|
|
||||||
;; [reader]
|
|
||||||
;; (try
|
|
||||||
;; (t/read! reader)
|
|
||||||
;; (catch RuntimeException e
|
|
||||||
;; (let [cause (.getCause e)]
|
|
||||||
;; (if (instance? java.io.EOFException cause)
|
|
||||||
;; ::eof
|
|
||||||
;; (throw e))))))
|
|
||||||
|
|
||||||
;; (defn- persist-project
|
|
||||||
;; [conn project]
|
|
||||||
;; (let [sql (sql/create-project project)]
|
|
||||||
;; (sc/execute conn sql)))
|
|
||||||
|
|
||||||
;; (defn- persist-page
|
|
||||||
;; [conn page]
|
|
||||||
;; (let [sql (sql/create-page page)]
|
|
||||||
;; (sc/execute conn sql)))
|
|
||||||
|
|
||||||
;; (defn- persist-page-history
|
|
||||||
;; [conn history]
|
|
||||||
;; (let [sql (sql/create-page-history history)]
|
|
||||||
;; (sc/execute conn sql)))
|
|
||||||
|
|
||||||
;; (defn- persist-entry
|
|
||||||
;; [conn entry]
|
|
||||||
;; (let [payload (::payload entry)
|
|
||||||
;; type (::type entry)]
|
|
||||||
;; (case type
|
|
||||||
;; ::project (persist-project conn payload)
|
|
||||||
;; ::page (persist-page conn payload)
|
|
||||||
;; ::page-history (persist-page-history conn payload))))
|
|
||||||
|
|
||||||
;; (defn- read-data
|
|
||||||
;; [conn reader]
|
|
||||||
;; (loop [entry (read-entry reader)]
|
|
||||||
;; (when (not= entry ::eof)
|
|
||||||
;; (persist-entry conn entry)
|
|
||||||
;; (recur (read-entry reader)))))
|
|
||||||
|
|
||||||
;; (defn import!
|
|
||||||
;; "Given a path to the previously exported bundle, try to import it."
|
|
||||||
;; [path]
|
|
||||||
;; (with-open [istream (io/input-stream (fs/path path))
|
|
||||||
;; zstream (snappy/input-stream istream)
|
|
||||||
;; conn (db/connection)]
|
|
||||||
;; (let [reader (t/reader zstream {:type :msgpack})]
|
|
||||||
;; (sc/atomic conn
|
|
||||||
;; (read-data conn reader)
|
|
||||||
;; nil))))
|
|
|
@ -1,71 +0,0 @@
|
||||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
;;
|
|
||||||
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
|
||||||
|
|
||||||
(ns uxbox.services.core
|
|
||||||
(:require
|
|
||||||
[clojure.tools.logging :as log]
|
|
||||||
[promesa.core :as p]
|
|
||||||
[vertx.core :as vc]
|
|
||||||
[uxbox.core :refer [system]]
|
|
||||||
[uxbox.util.uuid :as uuid]
|
|
||||||
[uxbox.util.dispatcher :as uds]
|
|
||||||
[uxbox.util.exceptions :as ex])
|
|
||||||
(:import
|
|
||||||
java.util.Map
|
|
||||||
java.util.List
|
|
||||||
java.util.Map$Entry
|
|
||||||
java.util.HashMap))
|
|
||||||
|
|
||||||
;; (def context-interceptor
|
|
||||||
;; {:enter (fn [data]
|
|
||||||
;; (update data :request assoc ::ctx (vc/get-or-create-context system)))})
|
|
||||||
|
|
||||||
(def logging-interceptor
|
|
||||||
{:enter (fn [data]
|
|
||||||
(let [type (get-in data [:request ::type])]
|
|
||||||
(assoc data ::start-time (System/nanoTime))))
|
|
||||||
:leave (fn [data]
|
|
||||||
(let [elapsed (- (System/nanoTime) (::start-time data))
|
|
||||||
elapsed (str (quot elapsed 1000000) "ms")
|
|
||||||
type (get-in data [:request ::type])]
|
|
||||||
(log/info "service" type "processed in" elapsed)
|
|
||||||
data))})
|
|
||||||
|
|
||||||
|
|
||||||
(uds/defservice query
|
|
||||||
{:dispatch-by ::type
|
|
||||||
:interceptors [uds/spec-interceptor
|
|
||||||
logging-interceptor
|
|
||||||
#_context-interceptor]})
|
|
||||||
|
|
||||||
(uds/defservice mutation
|
|
||||||
{:dispatch-by ::type
|
|
||||||
:interceptors [uds/spec-interceptor
|
|
||||||
#_context-interceptor]})
|
|
||||||
|
|
||||||
;; --- Helpers
|
|
||||||
|
|
||||||
(defmacro defmutation
|
|
||||||
[key & rest]
|
|
||||||
`(uds/defmethod mutation ~key ~@rest))
|
|
||||||
|
|
||||||
(defmacro defquery
|
|
||||||
[key & rest]
|
|
||||||
`(uds/defmethod query ~key ~@rest))
|
|
||||||
|
|
||||||
(defn raise-not-found-if-nil
|
|
||||||
[v]
|
|
||||||
(if (nil? v)
|
|
||||||
(ex/raise :type :not-found
|
|
||||||
:hint "Object doest not exists.")
|
|
||||||
v))
|
|
||||||
|
|
||||||
(def constantly-nil (constantly nil))
|
|
||||||
|
|
||||||
(defn handle-on-context
|
|
||||||
[p]
|
|
||||||
(->> (vc/get-or-create-context system)
|
|
||||||
(vc/handle-on-context p)))
|
|
35
backend/src/uxbox/services/init.clj
Normal file
35
backend/src/uxbox/services/init.clj
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
|
(ns uxbox.services.init
|
||||||
|
"A initialization of services."
|
||||||
|
(:require
|
||||||
|
[mount.core :as mount :refer [defstate]]))
|
||||||
|
|
||||||
|
(defn- load-query-services
|
||||||
|
[]
|
||||||
|
(require 'uxbox.services.queries.icons)
|
||||||
|
(require 'uxbox.services.queries.images)
|
||||||
|
(require 'uxbox.services.queries.pages)
|
||||||
|
(require 'uxbox.services.queries.profiles)
|
||||||
|
(require 'uxbox.services.queries.projects)
|
||||||
|
(require 'uxbox.services.queries.user-storage))
|
||||||
|
|
||||||
|
(defn- load-mutation-services
|
||||||
|
[]
|
||||||
|
(require 'uxbox.services.mutations.auth)
|
||||||
|
(require 'uxbox.services.mutations.icons)
|
||||||
|
(require 'uxbox.services.mutations.images)
|
||||||
|
(require 'uxbox.services.mutations.projects)
|
||||||
|
(require 'uxbox.services.mutations.pages)
|
||||||
|
(require 'uxbox.services.mutations.profiles)
|
||||||
|
(require 'uxbox.services.mutations.user-storage))
|
||||||
|
|
||||||
|
(defstate query-services
|
||||||
|
:start (load-query-services))
|
||||||
|
|
||||||
|
(defstate mutation-services
|
||||||
|
:start (load-mutation-services))
|
|
@ -1,70 +0,0 @@
|
||||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
;;
|
|
||||||
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
|
||||||
|
|
||||||
(ns uxbox.services.kvstore
|
|
||||||
(:require
|
|
||||||
[clojure.spec.alpha :as s]
|
|
||||||
[promesa.core :as p]
|
|
||||||
[uxbox.db :as db]
|
|
||||||
[uxbox.services.core :as sv]
|
|
||||||
[uxbox.util.blob :as blob]
|
|
||||||
[uxbox.util.data :as data]
|
|
||||||
[uxbox.util.spec :as us]
|
|
||||||
[uxbox.util.time :as dt]
|
|
||||||
[uxbox.util.uuid :as uuid]))
|
|
||||||
|
|
||||||
(defn- decode-row
|
|
||||||
[{:keys [value] :as row}]
|
|
||||||
(when row
|
|
||||||
(cond-> row
|
|
||||||
value (assoc :value (blob/decode value)))))
|
|
||||||
|
|
||||||
;; --- Update KVStore
|
|
||||||
|
|
||||||
(s/def ::user ::us/uuid)
|
|
||||||
(s/def ::key ::us/string)
|
|
||||||
(s/def ::value any?)
|
|
||||||
|
|
||||||
(s/def ::upsert-kvstore
|
|
||||||
(s/keys :req-un [::key ::value ::user]))
|
|
||||||
|
|
||||||
(sv/defmutation ::upsert-kvstore
|
|
||||||
[{:keys [key value user] :as params}]
|
|
||||||
(let [sql "insert into kvstore (key, value, user_id)
|
|
||||||
values ($1, $2, $3)
|
|
||||||
on conflict (user_id, key)
|
|
||||||
do update set value = $2"
|
|
||||||
val (blob/encode value)]
|
|
||||||
(-> (db/query-one db/pool [sql key val user])
|
|
||||||
(p/then' sv/constantly-nil))))
|
|
||||||
|
|
||||||
;; --- Retrieve KVStore
|
|
||||||
|
|
||||||
(s/def ::kvstore-entry
|
|
||||||
(s/keys :req-un [::key ::user]))
|
|
||||||
|
|
||||||
(sv/defquery ::kvstore-entry
|
|
||||||
[{:keys [key user]}]
|
|
||||||
(let [sql "select kv.*
|
|
||||||
from kvstore as kv
|
|
||||||
where kv.user_id = $2
|
|
||||||
and kv.key = $1"]
|
|
||||||
(-> (db/query-one db/pool [sql key user])
|
|
||||||
(p/then' sv/raise-not-found-if-nil)
|
|
||||||
(p/then' decode-row))))
|
|
||||||
|
|
||||||
;; --- Delete KVStore
|
|
||||||
|
|
||||||
(s/def ::delete-kvstore
|
|
||||||
(s/keys :req-un [::key ::user]))
|
|
||||||
|
|
||||||
(sv/defmutation ::delete-kvstore
|
|
||||||
[{:keys [user key] :as params}]
|
|
||||||
(let [sql "delete from kvstore
|
|
||||||
where user_id = $2
|
|
||||||
and key = $1"]
|
|
||||||
(-> (db/query-one db/pool [sql key user])
|
|
||||||
(p/then' sv/constantly-nil))))
|
|
19
backend/src/uxbox/services/mutations.clj
Normal file
19
backend/src/uxbox/services/mutations.clj
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
|
(ns uxbox.services.mutations
|
||||||
|
(:require
|
||||||
|
[uxbox.util.dispatcher :as uds]))
|
||||||
|
|
||||||
|
(uds/defservice handle
|
||||||
|
{:dispatch-by ::type
|
||||||
|
:interceptors [uds/spec-interceptor
|
||||||
|
#_logging-interceptor
|
||||||
|
#_context-interceptor]})
|
||||||
|
|
||||||
|
(defmacro defmutation
|
||||||
|
[key & rest]
|
||||||
|
`(uds/defmethod handle ~key ~@rest))
|
|
@ -4,33 +4,32 @@
|
||||||
;;
|
;;
|
||||||
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
(ns uxbox.services.auth
|
(ns uxbox.services.mutations.auth
|
||||||
(:require
|
(:require
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[buddy.hashers :as hashers]
|
[buddy.hashers :as hashers]
|
||||||
[promesa.core :as p]
|
[promesa.core :as p]
|
||||||
[uxbox.config :as cfg]
|
[uxbox.config :as cfg]
|
||||||
[uxbox.db :as db]
|
[uxbox.db :as db]
|
||||||
[uxbox.services.core :as sc]
|
[uxbox.services.mutations :as sm]
|
||||||
[uxbox.services.users :as users]
|
|
||||||
[uxbox.util.spec :as us]
|
[uxbox.util.spec :as us]
|
||||||
[uxbox.util.exceptions :as ex]))
|
[uxbox.util.exceptions :as ex]))
|
||||||
|
|
||||||
(s/def ::username ::us/string)
|
|
||||||
(s/def ::password ::us/string)
|
|
||||||
(s/def ::scope ::us/string)
|
|
||||||
|
|
||||||
(s/def ::login-params
|
|
||||||
(s/keys :req-un [::username ::password]
|
|
||||||
:opt-un [::scope]))
|
|
||||||
|
|
||||||
(def ^:private user-by-username-sql
|
(def ^:private user-by-username-sql
|
||||||
"select id, password
|
"select id, password
|
||||||
from users
|
from users
|
||||||
where username=$1 or email=$1
|
where username=$1 or email=$1
|
||||||
and deleted_at is null")
|
and deleted_at is null")
|
||||||
|
|
||||||
(sc/defmutation :login
|
(s/def ::username ::us/string)
|
||||||
|
(s/def ::password ::us/string)
|
||||||
|
(s/def ::scope ::us/string)
|
||||||
|
|
||||||
|
(s/def ::login
|
||||||
|
(s/keys :req-un [::username ::password]
|
||||||
|
:opt-un [::scope]))
|
||||||
|
|
||||||
|
(sm/defmutation ::login
|
||||||
{:doc "User login"
|
{:doc "User login"
|
||||||
:spec ::login-params}
|
:spec ::login-params}
|
||||||
[{:keys [username password scope] :as params}]
|
[{:keys [username password scope] :as params}]
|
||||||
|
@ -44,7 +43,7 @@
|
||||||
(when-not (check-password user password)
|
(when-not (check-password user password)
|
||||||
(ex/raise :type :validation
|
(ex/raise :type :validation
|
||||||
:code ::wrong-credentials))
|
:code ::wrong-credentials))
|
||||||
(:id user))]
|
|
||||||
|
|
||||||
|
{:id (:id user)})]
|
||||||
(-> (db/query-one db/pool [user-by-username-sql username])
|
(-> (db/query-one db/pool [user-by-username-sql username])
|
||||||
(p/then' check-user))))
|
(p/then' check-user))))
|
|
@ -4,15 +4,15 @@
|
||||||
;;
|
;;
|
||||||
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
(ns uxbox.services.icons
|
(ns uxbox.services.mutations.icons
|
||||||
"Icons library related services."
|
|
||||||
(:require
|
(:require
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[promesa.core :as p]
|
[promesa.core :as p]
|
||||||
[uxbox.db :as db]
|
[uxbox.db :as db]
|
||||||
[uxbox.services.core :as sv]
|
[uxbox.services.mutations :as sm]
|
||||||
|
[uxbox.services.util :as su]
|
||||||
|
[uxbox.services.queries.icons :refer [decode-icon-row]]
|
||||||
[uxbox.util.blob :as blob]
|
[uxbox.util.blob :as blob]
|
||||||
[uxbox.util.exceptions :as ex]
|
|
||||||
[uxbox.util.spec :as us]
|
[uxbox.util.spec :as us]
|
||||||
[uxbox.util.uuid :as uuid]))
|
[uxbox.util.uuid :as uuid]))
|
||||||
|
|
||||||
|
@ -36,75 +36,13 @@
|
||||||
(s/def ::metadata
|
(s/def ::metadata
|
||||||
(s/keys :opt-un [::width ::height ::view-box ::mimetype]))
|
(s/keys :opt-un [::width ::height ::view-box ::mimetype]))
|
||||||
|
|
||||||
(defn- decode-icon-row
|
|
||||||
[{:keys [metadata] :as row}]
|
|
||||||
(when row
|
|
||||||
(cond-> row
|
|
||||||
metadata (assoc :metadata (blob/decode metadata)))))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Queries
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; --- Query: Collections
|
|
||||||
|
|
||||||
(def ^:private icons-collections-sql
|
|
||||||
"select *,
|
|
||||||
(select count(*) from icons where collection_id = ic.id) as num_icons
|
|
||||||
from icons_collections as ic
|
|
||||||
where (ic.user_id = $1 or
|
|
||||||
ic.user_id = '00000000-0000-0000-0000-000000000000'::uuid)
|
|
||||||
and ic.deleted_at is null
|
|
||||||
order by ic.created_at desc")
|
|
||||||
|
|
||||||
(s/def ::icons-collections
|
|
||||||
(s/keys :req-un [::user]))
|
|
||||||
|
|
||||||
(sv/defquery :icons-collections
|
|
||||||
{:doc "Retrieve all icons collections for current user."
|
|
||||||
:spec ::icons-collections}
|
|
||||||
[{:keys [user] :as params}]
|
|
||||||
(let [sqlv [icons-collections-sql user]]
|
|
||||||
(db/query db/pool sqlv)))
|
|
||||||
|
|
||||||
;; --- List Icons
|
|
||||||
|
|
||||||
(def ^:private icons-by-collection-sql
|
|
||||||
"select *
|
|
||||||
from icons as i
|
|
||||||
where (i.user_id = $1 or
|
|
||||||
i.user_id = '00000000-0000-0000-0000-000000000000'::uuid)
|
|
||||||
and i.deleted_at is null
|
|
||||||
and case when $2::uuid is null then i.collection_id is null
|
|
||||||
else i.collection_id = $2::uuid
|
|
||||||
end
|
|
||||||
order by i.created_at desc")
|
|
||||||
|
|
||||||
(s/def ::icons-by-collection
|
|
||||||
(s/keys :req-un [::user]
|
|
||||||
:opt-un [::collection-id]))
|
|
||||||
|
|
||||||
(sv/defquery :icons-by-collection
|
|
||||||
{:doc "Retrieve icons for specified collection."
|
|
||||||
:spec ::icons-by-collection}
|
|
||||||
[{:keys [user collection-id] :as params}]
|
|
||||||
(let [sqlv [icons-by-collection-sql user collection-id]]
|
|
||||||
(-> (db/query db/pool sqlv)
|
|
||||||
(p/then' #(mapv decode-icon-row %)))))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Mutations
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; --- Mutation: Create Collection
|
;; --- Mutation: Create Collection
|
||||||
|
|
||||||
(s/def ::create-icons-collection
|
(s/def ::create-icons-collection
|
||||||
(s/keys :req-un [::user ::name]
|
(s/keys :req-un [::user ::name]
|
||||||
:opt-un [::id]))
|
:opt-un [::id]))
|
||||||
|
|
||||||
(sv/defmutation :create-icons-collection
|
(sm/defmutation ::create-icons-collection
|
||||||
{:doc "Create a new collection of icons."
|
|
||||||
:spec ::create-icons-collection}
|
|
||||||
[{:keys [id user name] :as params}]
|
[{:keys [id user name] :as params}]
|
||||||
(let [id (or id (uuid/next))
|
(let [id (or id (uuid/next))
|
||||||
sql "insert into icons_collections (id, user_id, name)
|
sql "insert into icons_collections (id, user_id, name)
|
||||||
|
@ -116,9 +54,7 @@
|
||||||
(s/def ::update-icons-collection
|
(s/def ::update-icons-collection
|
||||||
(s/keys :req-un [::user ::name ::id]))
|
(s/keys :req-un [::user ::name ::id]))
|
||||||
|
|
||||||
(sv/defmutation :update-icons-collection
|
(sm/defmutation ::update-icons-collection
|
||||||
{:doc "Update a collection of icons."
|
|
||||||
:spec ::update-icons-collection}
|
|
||||||
[{:keys [id user name] :as params}]
|
[{:keys [id user name] :as params}]
|
||||||
(let [sql "update icons_collections
|
(let [sql "update icons_collections
|
||||||
set name = $3
|
set name = $3
|
||||||
|
@ -126,7 +62,7 @@
|
||||||
and user_id = $2
|
and user_id = $2
|
||||||
returning *"]
|
returning *"]
|
||||||
(-> (db/query-one db/pool [sql id user name])
|
(-> (db/query-one db/pool [sql id user name])
|
||||||
(p/then' sv/raise-not-found-if-nil))))
|
(p/then' su/raise-not-found-if-nil))))
|
||||||
|
|
||||||
;; --- Copy Icon
|
;; --- Copy Icon
|
||||||
|
|
||||||
|
@ -140,14 +76,12 @@
|
||||||
and (user_id = $2 or
|
and (user_id = $2 or
|
||||||
user_id = '00000000-0000-0000-0000-000000000000'::uuid)"]
|
user_id = '00000000-0000-0000-0000-000000000000'::uuid)"]
|
||||||
(-> (db/query-one conn [sql id user])
|
(-> (db/query-one conn [sql id user])
|
||||||
(p/then' sv/raise-not-found-if-nil))))
|
(p/then' su/raise-not-found-if-nil))))
|
||||||
|
|
||||||
(s/def ::copy-icon
|
(s/def ::copy-icon
|
||||||
(s/keys :req-un [:us/id ::collection-id ::user]))
|
(s/keys :req-un [:us/id ::collection-id ::user]))
|
||||||
|
|
||||||
(sv/defmutation :copy-icon
|
(sm/defmutation ::copy-icon
|
||||||
{:doc "Copy an icon from one collection to other."
|
|
||||||
:spec ::copy-icon}
|
|
||||||
[{:keys [user id collection-id] :as params}]
|
[{:keys [user id collection-id] :as params}]
|
||||||
(db/with-atomic [conn db/pool]
|
(db/with-atomic [conn db/pool]
|
||||||
(-> (retrieve-icon conn {:user user :id id})
|
(-> (retrieve-icon conn {:user user :id id})
|
||||||
|
@ -161,9 +95,7 @@
|
||||||
(s/def ::delete-icons-collection
|
(s/def ::delete-icons-collection
|
||||||
(s/keys :req-un [::user ::id]))
|
(s/keys :req-un [::user ::id]))
|
||||||
|
|
||||||
(sv/defmutation :delete-icons-collection
|
(sm/defmutation ::delete-icons-collection
|
||||||
{:doc "Delete a collection of icons."
|
|
||||||
:spec ::delete-icons-collection}
|
|
||||||
[{:keys [user id] :as params}]
|
[{:keys [user id] :as params}]
|
||||||
(let [sql "update icons_collections
|
(let [sql "update icons_collections
|
||||||
set deleted_at = clock_timestamp()
|
set deleted_at = clock_timestamp()
|
||||||
|
@ -171,8 +103,8 @@
|
||||||
and user_id = $2
|
and user_id = $2
|
||||||
returning id"]
|
returning id"]
|
||||||
(-> (db/query-one db/pool [sql id user])
|
(-> (db/query-one db/pool [sql id user])
|
||||||
(p/then' sv/raise-not-found-if-nil)
|
(p/then' su/raise-not-found-if-nil)
|
||||||
(p/then' sv/constantly-nil))))
|
(p/then' su/constantly-nil))))
|
||||||
|
|
||||||
;; --- Mutation: Create Icon (Upload)
|
;; --- Mutation: Create Icon (Upload)
|
||||||
|
|
||||||
|
@ -194,9 +126,7 @@
|
||||||
(s/keys :req-un [::user ::name ::metadata ::content]
|
(s/keys :req-un [::user ::name ::metadata ::content]
|
||||||
:opt-un [::id ::collection-id]))
|
:opt-un [::id ::collection-id]))
|
||||||
|
|
||||||
(sv/defmutation :create-icon
|
(sm/defmutation ::create-icon
|
||||||
{:doc "Create (upload) a new icon."
|
|
||||||
:spec ::create-icon}
|
|
||||||
[params]
|
[params]
|
||||||
(create-icon db/pool params))
|
(create-icon db/pool params))
|
||||||
|
|
||||||
|
@ -205,9 +135,7 @@
|
||||||
(s/def ::update-icon
|
(s/def ::update-icon
|
||||||
(s/keys :req-un [::id ::user ::name ::collection-id]))
|
(s/keys :req-un [::id ::user ::name ::collection-id]))
|
||||||
|
|
||||||
(sv/defmutation :update-icon
|
(sm/defmutation ::update-icon
|
||||||
{:doc "Update an icon entry."
|
|
||||||
:spec ::update-icon}
|
|
||||||
[{:keys [id name user collection-id] :as params}]
|
[{:keys [id name user collection-id] :as params}]
|
||||||
(let [sql "update icons
|
(let [sql "update icons
|
||||||
set name = $1,
|
set name = $1,
|
||||||
|
@ -216,16 +144,14 @@
|
||||||
and user_id = $4
|
and user_id = $4
|
||||||
returning *"]
|
returning *"]
|
||||||
(-> (db/query-one db/pool [sql name collection-id id user])
|
(-> (db/query-one db/pool [sql name collection-id id user])
|
||||||
(p/then' sv/raise-not-found-if-nil))))
|
(p/then' su/raise-not-found-if-nil))))
|
||||||
|
|
||||||
;; --- Mutation: Delete Icon
|
;; --- Mutation: Delete Icon
|
||||||
|
|
||||||
(s/def ::delete-icon
|
(s/def ::delete-icon
|
||||||
(s/keys :req-un [::user ::id]))
|
(s/keys :req-un [::user ::id]))
|
||||||
|
|
||||||
(sv/defmutation :delete-icon
|
(sm/defmutation ::delete-icon
|
||||||
{:doc "Delete an icon entry."
|
|
||||||
:spec ::delete-icon}
|
|
||||||
[{:keys [id user] :as params}]
|
[{:keys [id user] :as params}]
|
||||||
(let [sql "update icons
|
(let [sql "update icons
|
||||||
set deleted_at = clock_timestamp()
|
set deleted_at = clock_timestamp()
|
||||||
|
@ -233,5 +159,5 @@
|
||||||
and user_id = $2
|
and user_id = $2
|
||||||
returning id"]
|
returning id"]
|
||||||
(-> (db/query-one db/pool [sql id user])
|
(-> (db/query-one db/pool [sql id user])
|
||||||
(p/then' sv/raise-not-found-if-nil)
|
(p/then' su/raise-not-found-if-nil)
|
||||||
(p/then' sv/constantly-nil))))
|
(p/then' su/constantly-nil))))
|
|
@ -4,8 +4,7 @@
|
||||||
;;
|
;;
|
||||||
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
(ns uxbox.services.images
|
(ns uxbox.services.mutations.images
|
||||||
"Images library related services."
|
|
||||||
(:require
|
(:require
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[datoteka.core :as fs]
|
[datoteka.core :as fs]
|
||||||
|
@ -15,7 +14,8 @@
|
||||||
[uxbox.db :as db]
|
[uxbox.db :as db]
|
||||||
[uxbox.media :as media]
|
[uxbox.media :as media]
|
||||||
[uxbox.images :as images]
|
[uxbox.images :as images]
|
||||||
[uxbox.services.core :as sc]
|
[uxbox.services.mutations :as sm]
|
||||||
|
[uxbox.services.util :as su]
|
||||||
[uxbox.util.blob :as blob]
|
[uxbox.util.blob :as blob]
|
||||||
[uxbox.util.data :as data]
|
[uxbox.util.data :as data]
|
||||||
[uxbox.util.exceptions :as ex]
|
[uxbox.util.exceptions :as ex]
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
[row]
|
[row]
|
||||||
(let [opts +thumbnail-options+]
|
(let [opts +thumbnail-options+]
|
||||||
(-> (px/submit! #(images/populate-thumbnails row opts))
|
(-> (px/submit! #(images/populate-thumbnails row opts))
|
||||||
(sc/handle-on-context))))
|
(su/handle-on-context))))
|
||||||
|
|
||||||
(defn- populate-thumbnails
|
(defn- populate-thumbnails
|
||||||
[rows]
|
[rows]
|
||||||
|
@ -58,9 +58,7 @@
|
||||||
(s/keys :req-un [::user ::us/name]
|
(s/keys :req-un [::user ::us/name]
|
||||||
:opt-un [::id]))
|
:opt-un [::id]))
|
||||||
|
|
||||||
(sc/defmutation :create-image-collection
|
(sm/defmutation ::create-image-collection
|
||||||
{:doc "Create image collection"
|
|
||||||
:spec ::create-image-collection}
|
|
||||||
[{:keys [id user name] :as params}]
|
[{:keys [id user name] :as params}]
|
||||||
(let [sql "insert into images_collections (id, user_id, name)
|
(let [sql "insert into images_collections (id, user_id, name)
|
||||||
values ($1, $2, $3) returning *;"]
|
values ($1, $2, $3) returning *;"]
|
||||||
|
@ -71,9 +69,7 @@
|
||||||
(s/def ::update-images-collection
|
(s/def ::update-images-collection
|
||||||
(s/keys :req-un [::id ::user ::us/name]))
|
(s/keys :req-un [::id ::user ::us/name]))
|
||||||
|
|
||||||
(sc/defmutation :update-images-collection
|
(sm/defmutation ::update-images-collection
|
||||||
{:doc "Update image collection."
|
|
||||||
:spec ::update-images-collection}
|
|
||||||
[{:keys [id user name] :as params}]
|
[{:keys [id user name] :as params}]
|
||||||
(let [sql "update images_collections
|
(let [sql "update images_collections
|
||||||
set name = $3
|
set name = $3
|
||||||
|
@ -82,30 +78,12 @@
|
||||||
returning *;"]
|
returning *;"]
|
||||||
(db/query-one db/pool [sql id user name])))
|
(db/query-one db/pool [sql id user name])))
|
||||||
|
|
||||||
;; --- List Collections
|
|
||||||
|
|
||||||
(def ^:private images-collections-sql
|
|
||||||
"select *,
|
|
||||||
(select count(*) from images where collection_id = ic.id) as num_images
|
|
||||||
from images_collections as ic
|
|
||||||
where (ic.user_id = $1 or
|
|
||||||
ic.user_id = '00000000-0000-0000-0000-000000000000'::uuid)
|
|
||||||
and ic.deleted_at is null
|
|
||||||
order by ic.created_at desc;")
|
|
||||||
|
|
||||||
(sc/defquery :images-collections
|
|
||||||
{:doc "Retrieve image collections for the current logged user"}
|
|
||||||
[{:keys [user] :as params}]
|
|
||||||
(db/query db/pool [images-collections-sql user]))
|
|
||||||
|
|
||||||
;; --- Delete Collection
|
;; --- Delete Collection
|
||||||
|
|
||||||
(s/def ::delete-images-collection
|
(s/def ::delete-images-collection
|
||||||
(s/keys :req-un [::user ::id]))
|
(s/keys :req-un [::user ::id]))
|
||||||
|
|
||||||
(sc/defmutation :delete-images-collection
|
(sm/defmutation ::delete-images-collection
|
||||||
{:doc "Delete an image collection"
|
|
||||||
:spec ::delete-images-collection}
|
|
||||||
[{:keys [id user] :as params}]
|
[{:keys [id user] :as params}]
|
||||||
(let [sql "update images_collections
|
(let [sql "update images_collections
|
||||||
set deleted_at = clock_timestamp()
|
set deleted_at = clock_timestamp()
|
||||||
|
@ -113,35 +91,16 @@
|
||||||
and user_id = $2
|
and user_id = $2
|
||||||
returning id"]
|
returning id"]
|
||||||
(-> (db/query-one db/pool [sql id user])
|
(-> (db/query-one db/pool [sql id user])
|
||||||
(p/then' sc/raise-not-found-if-nil))))
|
(p/then' su/raise-not-found-if-nil))))
|
||||||
|
|
||||||
;; --- Retrieve Image
|
|
||||||
|
|
||||||
(defn retrieve-image
|
|
||||||
[conn id]
|
|
||||||
(let [sql "select * from images
|
|
||||||
where id = $1
|
|
||||||
and deleted_at is null;"]
|
|
||||||
(db/query-one conn [sql id])))
|
|
||||||
|
|
||||||
;; (s/def ::retrieve-image
|
|
||||||
;; (s/keys :req-un [::user ::us/id]))
|
|
||||||
|
|
||||||
;; (defmethod core/query :retrieve-image
|
|
||||||
;; [params]
|
|
||||||
;; (s/assert ::retrieve-image params)
|
|
||||||
;; (with-open [conn (db/connection)]
|
|
||||||
;; (retrieve-image conn params)))
|
|
||||||
|
|
||||||
;; --- Create Image (Upload)
|
;; --- Create Image (Upload)
|
||||||
|
|
||||||
(defn- store-image-in-fs
|
(defn- store-image-in-fs
|
||||||
[{:keys [name path] :as upload}]
|
[{:keys [name path] :as upload}]
|
||||||
(prn "store-image-in-fs" upload)
|
|
||||||
(let [filename (fs/name name)
|
(let [filename (fs/name name)
|
||||||
storage media/images-storage]
|
storage media/images-storage]
|
||||||
(-> (ds/save storage filename path)
|
(-> (ds/save storage filename path)
|
||||||
(vc/handle-on-context))))
|
(su/handle-on-context))))
|
||||||
|
|
||||||
(def ^:private create-image-sql
|
(def ^:private create-image-sql
|
||||||
"insert into images (user_id, name, collection_id, path, width, height, mimetype)
|
"insert into images (user_id, name, collection_id, path, width, height, mimetype)
|
||||||
|
@ -167,9 +126,7 @@
|
||||||
(s/keys :req-un [::user ::name ::file ::width ::height ::mimetype]
|
(s/keys :req-un [::user ::name ::file ::width ::height ::mimetype]
|
||||||
:opt-un [::id ::collection-id]))
|
:opt-un [::id ::collection-id]))
|
||||||
|
|
||||||
(sc/defmutation :create-image
|
(sm/defmutation ::create-image
|
||||||
{:doc "Create (upload) new image."
|
|
||||||
:spec ::create-image}
|
|
||||||
[{:keys [file] :as params}]
|
[{:keys [file] :as params}]
|
||||||
(when-not (valid-image-types? (:mtype file))
|
(when-not (valid-image-types? (:mtype file))
|
||||||
(ex/raise :type :validation
|
(ex/raise :type :validation
|
||||||
|
@ -192,9 +149,7 @@
|
||||||
and user_id = $4
|
and user_id = $4
|
||||||
returning *;")
|
returning *;")
|
||||||
|
|
||||||
(sc/defmutation :update-image
|
(sm/defmutation ::update-image
|
||||||
{:doc "Update a image entry."
|
|
||||||
:spec ::update-image}
|
|
||||||
[{:keys [id name user collection-id] :as params}]
|
[{:keys [id name user collection-id] :as params}]
|
||||||
(let [sql update-image-sql]
|
(let [sql update-image-sql]
|
||||||
(db/query-one db/pool [sql id collection-id name user])))
|
(db/query-one db/pool [sql id collection-id name user])))
|
||||||
|
@ -206,9 +161,7 @@
|
||||||
(s/def ::copy-image
|
(s/def ::copy-image
|
||||||
(s/keys :req-un [::id ::collection-id ::user]))
|
(s/keys :req-un [::id ::collection-id ::user]))
|
||||||
|
|
||||||
(sc/defmutation :copy-image
|
(sm/defmutation ::copy-image
|
||||||
{:doc "Copy image from one collection to an other."
|
|
||||||
:spec ::copy-image}
|
|
||||||
[{:keys [user id collection-id] :as params}]
|
[{:keys [user id collection-id] :as params}]
|
||||||
(letfn [(copy-image [conn {:keys [path] :as image}]
|
(letfn [(copy-image [conn {:keys [path] :as image}]
|
||||||
(-> (ds/lookup media/images-storage (:path image))
|
(-> (ds/lookup media/images-storage (:path image))
|
||||||
|
@ -221,7 +174,7 @@
|
||||||
|
|
||||||
(db/with-atomic [conn db/pool]
|
(db/with-atomic [conn db/pool]
|
||||||
(-> (retrieve-image conn {:id id :user user})
|
(-> (retrieve-image conn {:id id :user user})
|
||||||
(p/then sc/raise-not-found-if-nil)
|
(p/then su/raise-not-found-if-nil)
|
||||||
(p/then (partial copy-image conn))))))
|
(p/then (partial copy-image conn))))))
|
||||||
|
|
||||||
;; --- Delete Image
|
;; --- Delete Image
|
||||||
|
@ -237,9 +190,7 @@
|
||||||
(s/def ::delete-image
|
(s/def ::delete-image
|
||||||
(s/keys :req-un [::id ::user]))
|
(s/keys :req-un [::id ::user]))
|
||||||
|
|
||||||
(sc/defmutation :delete-image
|
(sm/defmutation ::delete-image
|
||||||
{:doc "Delete image entry."
|
|
||||||
:spec ::delete-image}
|
|
||||||
[{:keys [user id] :as params}]
|
[{:keys [user id] :as params}]
|
||||||
(let [sql "update images
|
(let [sql "update images
|
||||||
set deleted_at = clock_timestamp()
|
set deleted_at = clock_timestamp()
|
||||||
|
@ -247,29 +198,3 @@
|
||||||
and user_id = $2
|
and user_id = $2
|
||||||
returning *"]
|
returning *"]
|
||||||
(db/query-one db/pool [sql id user])))
|
(db/query-one db/pool [sql id user])))
|
||||||
|
|
||||||
;; --- Query Images by Collection (id)
|
|
||||||
|
|
||||||
(def images-by-collection-sql
|
|
||||||
"select * from images
|
|
||||||
where (user_id = $1 or
|
|
||||||
user_id = '00000000-0000-0000-0000-000000000000'::uuid)
|
|
||||||
and deleted_at is null
|
|
||||||
and case when $2::uuid is null then collection_id is null
|
|
||||||
else collection_id = $2::uuid
|
|
||||||
end
|
|
||||||
order by created_at desc;")
|
|
||||||
|
|
||||||
(s/def ::images-by-collection-query
|
|
||||||
(s/keys :req-un [::user]
|
|
||||||
:opt-un [::collection-id]))
|
|
||||||
|
|
||||||
(sc/defquery :images-by-collection
|
|
||||||
{:doc "Get all images of a collection"
|
|
||||||
:spec ::images-by-collection-query}
|
|
||||||
[{:keys [user collection-id] :as params}]
|
|
||||||
(let [sqlv [images-by-collection-sql user collection-id]]
|
|
||||||
(-> (db/query db/pool sqlv)
|
|
||||||
(p/then populate-thumbnails)
|
|
||||||
(p/then #(mapv populate-urls %)))))
|
|
||||||
|
|
|
@ -4,22 +4,21 @@
|
||||||
;;
|
;;
|
||||||
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
(ns uxbox.services.pages
|
(ns uxbox.services.mutations.pages
|
||||||
(:require
|
(:require
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[promesa.core :as p]
|
[promesa.core :as p]
|
||||||
[uxbox.db :as db]
|
[uxbox.db :as db]
|
||||||
[uxbox.util.spec :as us]
|
[uxbox.util.spec :as us]
|
||||||
[uxbox.services.core :as sv]
|
[uxbox.services.mutations :as sm]
|
||||||
|
[uxbox.services.util :as su]
|
||||||
|
[uxbox.services.queries.pages :refer [decode-row]]
|
||||||
[uxbox.util.sql :as sql]
|
[uxbox.util.sql :as sql]
|
||||||
[uxbox.util.time :as dt]
|
|
||||||
[uxbox.util.blob :as blob]
|
[uxbox.util.blob :as blob]
|
||||||
[uxbox.util.uuid :as uuid]))
|
[uxbox.util.uuid :as uuid]))
|
||||||
|
|
||||||
;; --- Helpers & Specs
|
;; --- Helpers & Specs
|
||||||
|
|
||||||
(declare decode-row)
|
|
||||||
|
|
||||||
;; TODO: validate `:data` and `:metadata`
|
;; TODO: validate `:data` and `:metadata`
|
||||||
|
|
||||||
(s/def ::id ::us/uuid)
|
(s/def ::id ::us/uuid)
|
||||||
|
@ -29,84 +28,23 @@
|
||||||
(s/def ::project-id ::us/uuid)
|
(s/def ::project-id ::us/uuid)
|
||||||
(s/def ::metadata any?)
|
(s/def ::metadata any?)
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Queries
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; --- Query: Pages by Project
|
|
||||||
|
|
||||||
(s/def ::pages-by-project
|
|
||||||
(s/keys :req-un [::user ::project-id]))
|
|
||||||
|
|
||||||
(sv/defquery ::pages-by-project
|
|
||||||
[{:keys [user project-id] :as params}]
|
|
||||||
(let [sql "select pg.*,
|
|
||||||
pg.data,
|
|
||||||
pg.metadata
|
|
||||||
from pages as pg
|
|
||||||
where pg.user_id = $2
|
|
||||||
and pg.project_id = $1
|
|
||||||
and pg.deleted_at is null
|
|
||||||
order by pg.created_at asc;"]
|
|
||||||
(-> (db/query db/pool [sql project-id user])
|
|
||||||
(p/then #(mapv decode-row %)))))
|
|
||||||
|
|
||||||
;; --- Query: Page by Id
|
|
||||||
|
|
||||||
(s/def ::page
|
|
||||||
(s/keys :req-un [::user ::id]))
|
|
||||||
|
|
||||||
(sv/defquery ::page
|
|
||||||
[{:keys [user id] :as params}]
|
|
||||||
(let [sql "select pg.*,
|
|
||||||
pg.data,
|
|
||||||
pg.metadata
|
|
||||||
from pages as pg
|
|
||||||
where pg.user_id = $2
|
|
||||||
and pg.id = $1
|
|
||||||
and pg.deleted_at is null"]
|
|
||||||
(-> (db/query-one db/pool [sql id user])
|
|
||||||
(p/then' decode-row))))
|
|
||||||
|
|
||||||
;; --- Query: Page History
|
|
||||||
|
|
||||||
(s/def ::page-id ::us/uuid)
|
|
||||||
(s/def ::max ::us/integer)
|
|
||||||
(s/def ::pinned ::us/boolean)
|
|
||||||
(s/def ::since ::us/integer)
|
|
||||||
|
|
||||||
(s/def ::page-history
|
|
||||||
(s/keys :req-un [::page-id ::user]
|
|
||||||
:opt-un [::max ::pinned ::since]))
|
|
||||||
|
|
||||||
(sv/defquery ::page-history
|
|
||||||
[{:keys [page-id user since max pinned] :or {since Long/MAX_VALUE max 10}}]
|
|
||||||
(let [sql (-> (sql/from ["pages_history" "ph"])
|
|
||||||
(sql/select "ph.*")
|
|
||||||
(sql/where ["ph.user_id = ?" user]
|
|
||||||
["ph.page_id = ?" page-id]
|
|
||||||
["ph.version < ?" since]
|
|
||||||
(when pinned
|
|
||||||
["ph.pinned = ?" true]))
|
|
||||||
(sql/order "ph.version desc")
|
|
||||||
(sql/limit max))]
|
|
||||||
(-> (db/query db/pool (sql/fmt sql))
|
|
||||||
(p/then (partial mapv decode-row)))))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Mutations
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; --- Mutation: Create Page
|
;; --- Mutation: Create Page
|
||||||
|
|
||||||
|
(declare create-page)
|
||||||
|
|
||||||
(s/def ::create-page
|
(s/def ::create-page
|
||||||
(s/keys :req-un [::data ::user ::project-id ::name ::metadata]
|
(s/keys :req-un [::data ::user ::project-id ::name ::metadata]
|
||||||
:opt-un [::id]))
|
:opt-un [::id]))
|
||||||
|
|
||||||
(sv/defmutation ::create-page
|
(sm/defmutation ::create-page
|
||||||
[{:keys [id user project-id name data metadata]}]
|
[params]
|
||||||
(let [sql "insert into pages (id, user_id, project_id, name, data, metadata)
|
(create-page db/pool params))
|
||||||
values ($1, $2, $3, $4, $5, $6) returning *"
|
|
||||||
|
(defn create-page
|
||||||
|
[conn {:keys [id user project-id name data metadata] :as params}]
|
||||||
|
(let [sql "insert into pages (id, user_id, project_id, name, data, metadata, version)
|
||||||
|
values ($1, $2, $3, $4, $5, $6, 0)
|
||||||
|
returning *"
|
||||||
id (or id (uuid/next))
|
id (or id (uuid/next))
|
||||||
data (blob/encode data)
|
data (blob/encode data)
|
||||||
mdata (blob/encode metadata)]
|
mdata (blob/encode metadata)]
|
||||||
|
@ -125,7 +63,7 @@
|
||||||
and deleted_at is null
|
and deleted_at is null
|
||||||
for update;"]
|
for update;"]
|
||||||
(-> (db/query-one conn [sql id])
|
(-> (db/query-one conn [sql id])
|
||||||
(p/then' sv/raise-not-found-if-nil))))
|
(p/then' su/raise-not-found-if-nil))))
|
||||||
|
|
||||||
(update-page [conn {:keys [id name version data metadata user]}]
|
(update-page [conn {:keys [id name version data metadata user]}]
|
||||||
(let [sql "update pages
|
(let [sql "update pages
|
||||||
|
@ -136,15 +74,15 @@
|
||||||
where id = $5
|
where id = $5
|
||||||
and user_id = $6"]
|
and user_id = $6"]
|
||||||
(-> (db/query-one conn [sql name version data metadata id user])
|
(-> (db/query-one conn [sql name version data metadata id user])
|
||||||
(p/then' sv/constantly-nil))))
|
(p/then' su/constantly-nil))))
|
||||||
|
|
||||||
(update-history [conn {:keys [user id version data metadata]}]
|
(update-history [conn {:keys [user id version data metadata]}]
|
||||||
(let [sql "insert into pages_history (user_id, page_id, version, data, metadata)
|
(let [sql "insert into pages_history (user_id, page_id, version, data, metadata)
|
||||||
values ($1, $2, $3, $4, $5)"]
|
values ($1, $2, $3, $4, $5)"]
|
||||||
(-> (db/query-one conn [sql user id version data metadata])
|
(-> (db/query-one conn [sql user id version data metadata])
|
||||||
(p/then' sv/constantly-nil))))]
|
(p/then' su/constantly-nil))))]
|
||||||
|
|
||||||
(sv/defmutation ::update-page
|
(sm/defmutation ::update-page
|
||||||
[{:keys [id data metadata] :as params}]
|
[{:keys [id data metadata] :as params}]
|
||||||
(db/with-atomic [conn db/pool]
|
(db/with-atomic [conn db/pool]
|
||||||
(-> (select-for-update conn id)
|
(-> (select-for-update conn id)
|
||||||
|
@ -166,7 +104,7 @@
|
||||||
(s/def ::update-page-metadata
|
(s/def ::update-page-metadata
|
||||||
(s/keys :req-un [::user ::project-id ::name ::metadata ::id]))
|
(s/keys :req-un [::user ::project-id ::name ::metadata ::id]))
|
||||||
|
|
||||||
(sv/defmutation ::update-page-metadata
|
(sm/defmutation ::update-page-metadata
|
||||||
[{:keys [id user project-id name metadata]}]
|
[{:keys [id user project-id name metadata]}]
|
||||||
(let [sql "update pages
|
(let [sql "update pages
|
||||||
set name = $3,
|
set name = $3,
|
||||||
|
@ -184,7 +122,7 @@
|
||||||
(s/def ::delete-page
|
(s/def ::delete-page
|
||||||
(s/keys :req-un [::user ::id]))
|
(s/keys :req-un [::user ::id]))
|
||||||
|
|
||||||
(sv/defmutation ::delete-page
|
(sm/defmutation ::delete-page
|
||||||
[{:keys [id user]}]
|
[{:keys [id user]}]
|
||||||
(let [sql "update pages
|
(let [sql "update pages
|
||||||
set deleted_at = clock_timestamp()
|
set deleted_at = clock_timestamp()
|
||||||
|
@ -193,8 +131,8 @@
|
||||||
and deleted_at is null
|
and deleted_at is null
|
||||||
returning id"]
|
returning id"]
|
||||||
(-> (db/query-one db/pool [sql id user])
|
(-> (db/query-one db/pool [sql id user])
|
||||||
(p/then sv/raise-not-found-if-nil)
|
(p/then su/raise-not-found-if-nil)
|
||||||
(p/then sv/constantly-nil))))
|
(p/then su/constantly-nil))))
|
||||||
|
|
||||||
;; ;; --- Update Page History
|
;; ;; --- Update Page History
|
||||||
|
|
||||||
|
@ -211,29 +149,9 @@
|
||||||
;; (s/def ::update-page-history
|
;; (s/def ::update-page-history
|
||||||
;; (s/keys :req-un [::user ::id ::pinned ::label]))
|
;; (s/keys :req-un [::user ::id ::pinned ::label]))
|
||||||
|
|
||||||
;; (sv/defmutation :update-page-history
|
;; (sm/defmutation :update-page-history
|
||||||
;; {:doc "Update page history"
|
;; {:doc "Update page history"
|
||||||
;; :spec ::update-page-history}
|
;; :spec ::update-page-history}
|
||||||
;; [params]
|
;; [params]
|
||||||
;; (with-open [conn (db/connection)]
|
;; (with-open [conn (db/connection)]
|
||||||
;; (update-page-history conn params)))
|
;; (update-page-history conn params)))
|
||||||
|
|
||||||
;; --- Helpers
|
|
||||||
|
|
||||||
(defn- decode-row
|
|
||||||
[{:keys [data metadata] :as row}]
|
|
||||||
(when row
|
|
||||||
(cond-> row
|
|
||||||
data (assoc :data (blob/decode data))
|
|
||||||
metadata (assoc :metadata (blob/decode metadata)))))
|
|
||||||
|
|
||||||
;; select pg.* from pages as pg
|
|
||||||
;; where pg.id = :id
|
|
||||||
;; and pg.deleted_at is null;
|
|
||||||
|
|
||||||
;; (defn get-page-by-id
|
|
||||||
;; [conn id]
|
|
||||||
;; (s/assert ::us/id id)
|
|
||||||
;; (let [sqlv (sql/get-page-by-id {:id id})]
|
|
||||||
;; (some-> (db/fetch-one conn sqlv)
|
|
||||||
;; (decode-row))))
|
|
|
@ -4,7 +4,7 @@
|
||||||
;;
|
;;
|
||||||
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
|
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
(ns uxbox.services.users
|
(ns uxbox.services.mutations.profiles
|
||||||
(:require
|
(:require
|
||||||
[buddy.hashers :as hashers]
|
[buddy.hashers :as hashers]
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
|
@ -17,7 +17,12 @@
|
||||||
[uxbox.emails :as emails]
|
[uxbox.emails :as emails]
|
||||||
[uxbox.images :as images]
|
[uxbox.images :as images]
|
||||||
[uxbox.media :as media]
|
[uxbox.media :as media]
|
||||||
[uxbox.services.core :as sv]
|
[uxbox.services.mutations :as sm]
|
||||||
|
[uxbox.services.util :as su]
|
||||||
|
[uxbox.services.queries.profiles :refer [get-profile
|
||||||
|
decode-profile-row
|
||||||
|
strip-private-attrs
|
||||||
|
resolve-thumbnail]]
|
||||||
[uxbox.util.blob :as blob]
|
[uxbox.util.blob :as blob]
|
||||||
[uxbox.util.exceptions :as ex]
|
[uxbox.util.exceptions :as ex]
|
||||||
[uxbox.util.spec :as us]
|
[uxbox.util.spec :as us]
|
||||||
|
@ -27,9 +32,6 @@
|
||||||
|
|
||||||
;; --- Helpers & Specs
|
;; --- Helpers & Specs
|
||||||
|
|
||||||
(declare decode-profile-row)
|
|
||||||
(declare strip-private-attrs)
|
|
||||||
|
|
||||||
(s/def ::email ::us/email)
|
(s/def ::email ::us/email)
|
||||||
(s/def ::fullname ::us/string)
|
(s/def ::fullname ::us/string)
|
||||||
(s/def ::metadata any?)
|
(s/def ::metadata any?)
|
||||||
|
@ -39,42 +41,6 @@
|
||||||
(s/def ::user ::us/uuid)
|
(s/def ::user ::us/uuid)
|
||||||
(s/def ::username ::us/string)
|
(s/def ::username ::us/string)
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Queries
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; --- Query: Profile (own)
|
|
||||||
|
|
||||||
(defn- resolve-thumbnail
|
|
||||||
[user]
|
|
||||||
(let [opts {:src :photo
|
|
||||||
:dst :photo
|
|
||||||
:size [100 100]
|
|
||||||
:quality 90
|
|
||||||
:format "jpg"}]
|
|
||||||
(-> (px/submit! #(images/populate-thumbnails user opts))
|
|
||||||
(sv/handle-on-context))))
|
|
||||||
|
|
||||||
(defn- get-profile
|
|
||||||
[conn id]
|
|
||||||
(let [sql "select * from users where id=$1 and deleted_at is null"]
|
|
||||||
(-> (db/query-one db/pool [sql id])
|
|
||||||
(p/then' decode-profile-row))))
|
|
||||||
|
|
||||||
(s/def ::profile
|
|
||||||
(s/keys :req-un [::user]))
|
|
||||||
|
|
||||||
(sv/defquery :profile
|
|
||||||
{:doc "Retrieve the user profile."
|
|
||||||
:spec ::profile}
|
|
||||||
[{:keys [user] :as params}]
|
|
||||||
(-> (get-profile db/pool user)
|
|
||||||
(p/then' strip-private-attrs)))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Mutations
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; --- Mutation: Update Profile (own)
|
;; --- Mutation: Update Profile (own)
|
||||||
|
|
||||||
(defn- check-username-and-email!
|
(defn- check-username-and-email!
|
||||||
|
@ -110,14 +76,14 @@
|
||||||
and deleted_at is null
|
and deleted_at is null
|
||||||
returning *"]
|
returning *"]
|
||||||
(-> (db/query-one conn [sql id username email fullname (blob/encode metadata)])
|
(-> (db/query-one conn [sql id username email fullname (blob/encode metadata)])
|
||||||
(p/then' sv/raise-not-found-if-nil)
|
(p/then' su/raise-not-found-if-nil)
|
||||||
(p/then' decode-profile-row)
|
(p/then' decode-profile-row)
|
||||||
(p/then' strip-private-attrs))))
|
(p/then' strip-private-attrs))))
|
||||||
|
|
||||||
(s/def ::update-profile
|
(s/def ::update-profile
|
||||||
(s/keys :req-un [::id ::username ::email ::fullname ::metadata]))
|
(s/keys :req-un [::id ::username ::email ::fullname ::metadata]))
|
||||||
|
|
||||||
(sv/defmutation :update-profile
|
(sm/defmutation :update-profile
|
||||||
{:doc "Update self profile."
|
{:doc "Update self profile."
|
||||||
:spec ::update-profile}
|
:spec ::update-profile}
|
||||||
[params]
|
[params]
|
||||||
|
@ -144,13 +110,13 @@
|
||||||
and deleted_at is null
|
and deleted_at is null
|
||||||
returning id"]
|
returning id"]
|
||||||
(-> (db/query-one conn [sql user password])
|
(-> (db/query-one conn [sql user password])
|
||||||
(p/then' sv/raise-not-found-if-nil)
|
(p/then' su/raise-not-found-if-nil)
|
||||||
(p/then' sv/constantly-nil))))
|
(p/then' su/constantly-nil))))
|
||||||
|
|
||||||
(s/def ::update-password
|
(s/def ::update-password
|
||||||
(s/keys :req-un [::user ::us/password ::old-password]))
|
(s/keys :req-un [::user ::us/password ::old-password]))
|
||||||
|
|
||||||
(sv/defmutation :update-password
|
(sm/defmutation :update-password
|
||||||
{:doc "Update self password."
|
{:doc "Update self password."
|
||||||
:spec ::update-password}
|
:spec ::update-password}
|
||||||
[params]
|
[params]
|
||||||
|
@ -168,7 +134,7 @@
|
||||||
(def valid-image-types?
|
(def valid-image-types?
|
||||||
#{"image/jpeg", "image/png", "image/webp"})
|
#{"image/jpeg", "image/png", "image/webp"})
|
||||||
|
|
||||||
(sv/defmutation :update-profile-photo
|
(sm/defmutation :update-profile-photo
|
||||||
{:doc "Update profile photo."
|
{:doc "Update profile photo."
|
||||||
:spec ::update-profile-photo}
|
:spec ::update-profile-photo}
|
||||||
[{:keys [user file] :as params}]
|
[{:keys [user file] :as params}]
|
||||||
|
@ -176,7 +142,7 @@
|
||||||
(let [filename (fs/name name)
|
(let [filename (fs/name name)
|
||||||
storage media/images-storage]
|
storage media/images-storage]
|
||||||
(-> (ds/save storage filename path)
|
(-> (ds/save storage filename path)
|
||||||
#_(sv/handle-on-context))))
|
#_(su/handle-on-context))))
|
||||||
|
|
||||||
(update-user-photo [path]
|
(update-user-photo [path]
|
||||||
(let [sql "update users
|
(let [sql "update users
|
||||||
|
@ -185,7 +151,7 @@
|
||||||
and deleted_at is null
|
and deleted_at is null
|
||||||
returning *"]
|
returning *"]
|
||||||
(-> (db/query-one db/pool [sql (str path) user])
|
(-> (db/query-one db/pool [sql (str path) user])
|
||||||
(p/then' sv/raise-not-found-if-nil)
|
(p/then' su/raise-not-found-if-nil)
|
||||||
(p/then' strip-private-attrs)
|
(p/then' strip-private-attrs)
|
||||||
(p/then resolve-thumbnail))))]
|
(p/then resolve-thumbnail))))]
|
||||||
|
|
||||||
|
@ -216,33 +182,38 @@
|
||||||
:code ::username-or-email-already-exists))
|
:code ::username-or-email-already-exists))
|
||||||
params)))))
|
params)))))
|
||||||
|
|
||||||
(defn- register-profile
|
(defn create-profile
|
||||||
"Create the user entry on the database with limited input
|
"Create the user entry on the database with limited input
|
||||||
filling all the other fields with defaults."
|
filling all the other fields with defaults."
|
||||||
[conn {:keys [username fullname email password] :as params}]
|
[conn {:keys [id username fullname email password metadata] :as params}]
|
||||||
(let [metadata (blob/encode {})
|
(let [id (or id (uuid/next))
|
||||||
|
metadata (blob/encode metadata)
|
||||||
password (hashers/encrypt password)
|
password (hashers/encrypt password)
|
||||||
sqlv [create-user-sql
|
sqlv [create-user-sql
|
||||||
(uuid/next)
|
id
|
||||||
fullname
|
fullname
|
||||||
username
|
username
|
||||||
email
|
email
|
||||||
password
|
password
|
||||||
metadata]]
|
metadata]]
|
||||||
(-> (db/query-one conn sqlv)
|
(-> (db/query-one conn sqlv)
|
||||||
(p/then' decode-profile-row)
|
(p/then' decode-profile-row))))
|
||||||
(p/then' strip-private-attrs)
|
|
||||||
#_(p/then (fn [profile]
|
(defn register-profile
|
||||||
|
[conn params]
|
||||||
|
(-> (create-profile conn params)
|
||||||
|
(p/then' strip-private-attrs)
|
||||||
|
#_(p/then (fn [profile]
|
||||||
(-> (emails/send! {::emails/id :users/register
|
(-> (emails/send! {::emails/id :users/register
|
||||||
::emails/to (:email params)
|
::emails/to (:email params)
|
||||||
::emails/priority :high
|
::emails/priority :high
|
||||||
:name (:fullname params)})
|
:name (:fullname params)})
|
||||||
(p/then' (constantly profile))))))))
|
(p/then' (constantly profile)))))))
|
||||||
|
|
||||||
(s/def ::register-profile
|
(s/def ::register-profile
|
||||||
(s/keys :req-un [::username ::email ::password ::fullname]))
|
(s/keys :req-un [::username ::email ::password ::fullname]))
|
||||||
|
|
||||||
(sv/defmutation :register-profile
|
(sm/defmutation :register-profile
|
||||||
{:doc "Register new user."
|
{:doc "Register new user."
|
||||||
:spec ::register-profile}
|
:spec ::register-profile}
|
||||||
[params]
|
[params]
|
||||||
|
@ -366,16 +337,3 @@
|
||||||
;; (some-> (db/fetch-one conn sqlv)
|
;; (some-> (db/fetch-one conn sqlv)
|
||||||
;; (trim-user-attrs))))
|
;; (trim-user-attrs))))
|
||||||
|
|
||||||
;; --- Attrs Helpers
|
|
||||||
|
|
||||||
(defn- decode-profile-row
|
|
||||||
[{:keys [metadata] :as row}]
|
|
||||||
(when row
|
|
||||||
(cond-> row
|
|
||||||
metadata (assoc :metadata (blob/decode metadata)))))
|
|
||||||
|
|
||||||
(defn strip-private-attrs
|
|
||||||
"Only selects a publicy visible user attrs."
|
|
||||||
[profile]
|
|
||||||
(select-keys profile [:id :username :fullname :metadata
|
|
||||||
:email :created-at :photo]))
|
|
83
backend/src/uxbox/services/mutations/projects.clj
Normal file
83
backend/src/uxbox/services/mutations/projects.clj
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
|
(ns uxbox.services.mutations.projects
|
||||||
|
(:require
|
||||||
|
[clojure.spec.alpha :as s]
|
||||||
|
[promesa.core :as p]
|
||||||
|
[uxbox.db :as db]
|
||||||
|
[uxbox.util.spec :as us]
|
||||||
|
[uxbox.services.mutations :as sm]
|
||||||
|
[uxbox.services.util :as su]
|
||||||
|
[uxbox.util.blob :as blob]
|
||||||
|
[uxbox.util.uuid :as uuid]))
|
||||||
|
|
||||||
|
;; --- Helpers & Specs
|
||||||
|
|
||||||
|
(s/def ::id ::us/uuid)
|
||||||
|
(s/def ::name ::us/string)
|
||||||
|
(s/def ::token ::us/string)
|
||||||
|
(s/def ::user ::us/uuid)
|
||||||
|
|
||||||
|
;; --- Mutation: Create Project
|
||||||
|
|
||||||
|
(declare create-project)
|
||||||
|
|
||||||
|
(s/def ::create-project
|
||||||
|
(s/keys :req-un [::user ::name]
|
||||||
|
:opt-un [::id]))
|
||||||
|
|
||||||
|
;; TODO: create role on project creation (maybe in DB?)
|
||||||
|
|
||||||
|
(sm/defmutation ::create-project
|
||||||
|
[{:keys [id user name] :as params}]
|
||||||
|
(let [id (or id (uuid/next))
|
||||||
|
sql "insert into projects (id, user_id, name)
|
||||||
|
values ($1, $2, $3) returning *"]
|
||||||
|
(db/query-one db/pool [sql id user name])))
|
||||||
|
|
||||||
|
(defn create-project
|
||||||
|
[conn {:keys [id user name] :as params}]
|
||||||
|
(let [id (or id (uuid/next))
|
||||||
|
sql "insert into projects (id, user_id, name)
|
||||||
|
values ($1, $2, $3) returning *"]
|
||||||
|
(db/query-one conn [sql id user name])))
|
||||||
|
|
||||||
|
;; --- Mutation: Update Project
|
||||||
|
|
||||||
|
(s/def ::update-project
|
||||||
|
(s/keys :req-un [::user ::name ::id]))
|
||||||
|
|
||||||
|
(sm/defmutation :update-project
|
||||||
|
{:doc "Update project."
|
||||||
|
:spec ::update-project}
|
||||||
|
[{:keys [id name user] :as params}]
|
||||||
|
(let [sql "update projects
|
||||||
|
set name = $3
|
||||||
|
where id = $1
|
||||||
|
and user_id = $2
|
||||||
|
and deleted_at is null
|
||||||
|
returning *"]
|
||||||
|
(db/query-one db/pool [sql id user name])))
|
||||||
|
|
||||||
|
;; --- Mutation: Delete Project
|
||||||
|
|
||||||
|
(s/def ::delete-project
|
||||||
|
(s/keys :req-un [::id ::user]))
|
||||||
|
|
||||||
|
(sm/defmutation :delete-project
|
||||||
|
{:doc "Delete project"
|
||||||
|
:spec ::delete-project}
|
||||||
|
[{:keys [id user] :as params}]
|
||||||
|
(let [sql "update projects
|
||||||
|
set deleted_at = clock_timestamp()
|
||||||
|
where id = $1
|
||||||
|
and user_id = $2
|
||||||
|
and deleted_at is null
|
||||||
|
returning id"]
|
||||||
|
(-> (db/query-one db/pool [sql id user])
|
||||||
|
(p/then' su/raise-not-found-if-nil)
|
||||||
|
(p/then' su/constantly-nil))))
|
48
backend/src/uxbox/services/mutations/user_storage.clj
Normal file
48
backend/src/uxbox/services/mutations/user_storage.clj
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
|
(ns uxbox.services.mutations.user-storage
|
||||||
|
(:require
|
||||||
|
[clojure.spec.alpha :as s]
|
||||||
|
[promesa.core :as p]
|
||||||
|
[uxbox.db :as db]
|
||||||
|
[uxbox.services.mutations :as sm]
|
||||||
|
[uxbox.services.util :as su]
|
||||||
|
[uxbox.services.queries.user-storage :refer [decode-row]]
|
||||||
|
[uxbox.util.blob :as blob]
|
||||||
|
[uxbox.util.spec :as us]))
|
||||||
|
|
||||||
|
;; --- Update
|
||||||
|
|
||||||
|
(s/def ::user ::us/uuid)
|
||||||
|
(s/def ::key ::us/string)
|
||||||
|
(s/def ::val any?)
|
||||||
|
|
||||||
|
(s/def ::upsert-user-storage-entry
|
||||||
|
(s/keys :req-un [::key ::val ::user]))
|
||||||
|
|
||||||
|
(sm/defmutation ::upsert-user-storage-entry
|
||||||
|
[{:keys [key val user] :as params}]
|
||||||
|
(let [sql "insert into user_storage (key, val, user_id)
|
||||||
|
values ($1, $2, $3)
|
||||||
|
on conflict (user_id, key)
|
||||||
|
do update set val = $2"
|
||||||
|
val (blob/encode val)]
|
||||||
|
(-> (db/query-one db/pool [sql key val user])
|
||||||
|
(p/then' su/constantly-nil))))
|
||||||
|
|
||||||
|
;; --- Delete KVStore
|
||||||
|
|
||||||
|
(s/def ::delete-user-storage-entry
|
||||||
|
(s/keys :req-un [::key ::user]))
|
||||||
|
|
||||||
|
(sm/defmutation ::delete-user-storage-entry
|
||||||
|
[{:keys [user key] :as params}]
|
||||||
|
(let [sql "delete from user_storage
|
||||||
|
where user_id = $2
|
||||||
|
and key = $1"]
|
||||||
|
(-> (db/query-one db/pool [sql key user])
|
||||||
|
(p/then' su/constantly-nil))))
|
|
@ -1,133 +0,0 @@
|
||||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
;;
|
|
||||||
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
|
||||||
|
|
||||||
(ns uxbox.services.projects
|
|
||||||
(:require
|
|
||||||
[clojure.spec.alpha :as s]
|
|
||||||
[promesa.core :as p]
|
|
||||||
[uxbox.db :as db]
|
|
||||||
[uxbox.util.spec :as us]
|
|
||||||
[uxbox.services.core :as sv]
|
|
||||||
[uxbox.util.blob :as blob]
|
|
||||||
[uxbox.util.uuid :as uuid]))
|
|
||||||
|
|
||||||
;; --- Helpers & Specs
|
|
||||||
|
|
||||||
(s/def ::id ::us/uuid)
|
|
||||||
(s/def ::name ::us/string)
|
|
||||||
(s/def ::token ::us/string)
|
|
||||||
(s/def ::user ::us/uuid)
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Queries
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; --- Query: Projects
|
|
||||||
|
|
||||||
(s/def ::projects-query
|
|
||||||
(s/keys :req-un [::user]))
|
|
||||||
|
|
||||||
(sv/defquery :projects
|
|
||||||
{:doc "Query all projects"
|
|
||||||
:spec ::projects-query}
|
|
||||||
[{:keys [user] :as params}]
|
|
||||||
(let [sql "select distinct on (p.id, p.created_at)
|
|
||||||
p.*,
|
|
||||||
array_agg(pg.id) over (
|
|
||||||
partition by p.id
|
|
||||||
order by pg.created_at
|
|
||||||
range between unbounded preceding and unbounded following
|
|
||||||
) as pages
|
|
||||||
from projects as p
|
|
||||||
right join pages as pg
|
|
||||||
on (pg.project_id = p.id)
|
|
||||||
where p.user_id = $1
|
|
||||||
order by p.created_at asc"]
|
|
||||||
(-> (db/query db/pool [sql user])
|
|
||||||
(p/then (fn [rows]
|
|
||||||
(mapv #(update % :pages vec) rows))))))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Mutations
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; --- Mutation: Create Project
|
|
||||||
|
|
||||||
(s/def ::create-project
|
|
||||||
(s/keys :req-un [::user ::name]
|
|
||||||
:opt-un [::id]))
|
|
||||||
|
|
||||||
(sv/defmutation :create-project
|
|
||||||
{:doc "Create a project."
|
|
||||||
:spec ::create-project}
|
|
||||||
[{:keys [id user name] :as params}]
|
|
||||||
(let [id (or id (uuid/next))
|
|
||||||
sql "insert into projects (id, user_id, name)
|
|
||||||
values ($1, $2, $3) returning *"]
|
|
||||||
(db/query-one db/pool [sql id user name])))
|
|
||||||
|
|
||||||
;; --- Mutation: Update Project
|
|
||||||
|
|
||||||
(s/def ::update-project
|
|
||||||
(s/keys :req-un [::user ::name ::id]))
|
|
||||||
|
|
||||||
(sv/defmutation :update-project
|
|
||||||
{:doc "Update project."
|
|
||||||
:spec ::update-project}
|
|
||||||
[{:keys [id name user] :as params}]
|
|
||||||
(let [sql "update projects
|
|
||||||
set name = $3
|
|
||||||
where id = $1
|
|
||||||
and user_id = $2
|
|
||||||
and deleted_at is null
|
|
||||||
returning *"]
|
|
||||||
(db/query-one db/pool [sql id user name])))
|
|
||||||
|
|
||||||
;; --- Mutation: Delete Project
|
|
||||||
|
|
||||||
(s/def ::delete-project
|
|
||||||
(s/keys :req-un [::id ::user]))
|
|
||||||
|
|
||||||
(sv/defmutation :delete-project
|
|
||||||
{:doc "Delete project"
|
|
||||||
:spec ::delete-project}
|
|
||||||
[{:keys [id user] :as params}]
|
|
||||||
(let [sql "update projects
|
|
||||||
set deleted_at = clock_timestamp()
|
|
||||||
where id = $1
|
|
||||||
and user_id = $2
|
|
||||||
and deleted_at is null
|
|
||||||
returning id"]
|
|
||||||
(-> (db/query-one db/pool [sql id user])
|
|
||||||
(p/then' sv/raise-not-found-if-nil)
|
|
||||||
(p/then' sv/constantly-nil))))
|
|
||||||
|
|
||||||
|
|
||||||
;; --- Retrieve Project by share token
|
|
||||||
|
|
||||||
;; (defn- get-project-by-share-token
|
|
||||||
;; [conn token]
|
|
||||||
;; (let [sqlv (sql/get-project-by-share-token {:token token})
|
|
||||||
;; project (some-> (db/fetch-one conn sqlv)
|
|
||||||
;; (data/normalize))]
|
|
||||||
;; (when-let [id (:id project)]
|
|
||||||
;; (let [pages (vec (pages/get-pages-for-project conn id))]
|
|
||||||
;; (assoc project :pages pages)))))
|
|
||||||
|
|
||||||
;; (defmethod core/query :retrieve-project-by-share-token
|
|
||||||
;; [{:keys [token]}]
|
|
||||||
;; (s/assert ::token token)
|
|
||||||
;; (with-open [conn (db/connection)]
|
|
||||||
;; (get-project-by-share-token conn token)))
|
|
||||||
|
|
||||||
;; --- Retrieve share tokens
|
|
||||||
|
|
||||||
;; (defn get-share-tokens-for-project
|
|
||||||
;; [conn project]
|
|
||||||
;; (s/assert ::project project)
|
|
||||||
;; (let [sqlv (sql/get-share-tokens-for-project {:project project})]
|
|
||||||
;; (db/fetch conn sqlv)))
|
|
||||||
|
|
19
backend/src/uxbox/services/queries.clj
Normal file
19
backend/src/uxbox/services/queries.clj
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
|
(ns uxbox.services.queries
|
||||||
|
(:require
|
||||||
|
[uxbox.util.dispatcher :as uds]))
|
||||||
|
|
||||||
|
(uds/defservice handle
|
||||||
|
{:dispatch-by ::type
|
||||||
|
:interceptors [uds/spec-interceptor
|
||||||
|
#_logging-interceptor
|
||||||
|
#_context-interceptor]})
|
||||||
|
|
||||||
|
(defmacro defquery
|
||||||
|
[key & rest]
|
||||||
|
`(uds/defmethod handle ~key ~@rest))
|
69
backend/src/uxbox/services/queries/icons.clj
Normal file
69
backend/src/uxbox/services/queries/icons.clj
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
|
(ns uxbox.services.queries.icons
|
||||||
|
(:require
|
||||||
|
[clojure.spec.alpha :as s]
|
||||||
|
[promesa.core :as p]
|
||||||
|
[uxbox.db :as db]
|
||||||
|
[uxbox.services.queries :as sq]
|
||||||
|
[uxbox.util.blob :as blob]
|
||||||
|
[uxbox.util.exceptions :as ex]
|
||||||
|
[uxbox.util.spec :as us]))
|
||||||
|
|
||||||
|
;; --- Helpers & Specs
|
||||||
|
|
||||||
|
(s/def ::id ::us/uuid)
|
||||||
|
(s/def ::user ::us/uuid)
|
||||||
|
(s/def ::collection-id (s/nilable ::us/uuid))
|
||||||
|
|
||||||
|
(defn decode-icon-row
|
||||||
|
[{:keys [metadata] :as row}]
|
||||||
|
(when row
|
||||||
|
(cond-> row
|
||||||
|
metadata (assoc :metadata (blob/decode metadata)))))
|
||||||
|
|
||||||
|
;; --- Query: Collections
|
||||||
|
|
||||||
|
(def ^:private icons-collections-sql
|
||||||
|
"select *,
|
||||||
|
(select count(*) from icons where collection_id = ic.id) as num_icons
|
||||||
|
from icons_collections as ic
|
||||||
|
where (ic.user_id = $1 or
|
||||||
|
ic.user_id = '00000000-0000-0000-0000-000000000000'::uuid)
|
||||||
|
and ic.deleted_at is null
|
||||||
|
order by ic.created_at desc")
|
||||||
|
|
||||||
|
(s/def ::icons-collections
|
||||||
|
(s/keys :req-un [::user]))
|
||||||
|
|
||||||
|
(sq/defquery ::icons-collections
|
||||||
|
[{:keys [user] :as params}]
|
||||||
|
(let [sqlv [icons-collections-sql user]]
|
||||||
|
(db/query db/pool sqlv)))
|
||||||
|
|
||||||
|
;; --- Icons By Collection ID
|
||||||
|
|
||||||
|
(def ^:private icons-by-collection-sql
|
||||||
|
"select *
|
||||||
|
from icons as i
|
||||||
|
where (i.user_id = $1 or
|
||||||
|
i.user_id = '00000000-0000-0000-0000-000000000000'::uuid)
|
||||||
|
and i.deleted_at is null
|
||||||
|
and case when $2::uuid is null then i.collection_id is null
|
||||||
|
else i.collection_id = $2::uuid
|
||||||
|
end
|
||||||
|
order by i.created_at desc")
|
||||||
|
|
||||||
|
(s/def ::icons-by-collection
|
||||||
|
(s/keys :req-un [::user]
|
||||||
|
:opt-un [::collection-id]))
|
||||||
|
|
||||||
|
(sq/defquery ::icons-by-collection
|
||||||
|
[{:keys [user collection-id] :as params}]
|
||||||
|
(let [sqlv [icons-by-collection-sql user collection-id]]
|
||||||
|
(-> (db/query db/pool sqlv)
|
||||||
|
(p/then' #(mapv decode-icon-row %)))))
|
109
backend/src/uxbox/services/queries/images.clj
Normal file
109
backend/src/uxbox/services/queries/images.clj
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
|
(ns uxbox.services.queries.images
|
||||||
|
(:require
|
||||||
|
[clojure.spec.alpha :as s]
|
||||||
|
[promesa.core :as p]
|
||||||
|
[promesa.exec :as px]
|
||||||
|
[uxbox.db :as db]
|
||||||
|
[uxbox.media :as media]
|
||||||
|
[uxbox.images :as images]
|
||||||
|
[uxbox.services.queries :as sq]
|
||||||
|
[uxbox.services.util :as su]
|
||||||
|
[uxbox.util.blob :as blob]
|
||||||
|
[uxbox.util.data :as data]
|
||||||
|
[uxbox.util.exceptions :as ex]
|
||||||
|
[uxbox.util.spec :as us]
|
||||||
|
[uxbox.util.uuid :as uuid]
|
||||||
|
[vertx.core :as vc]))
|
||||||
|
|
||||||
|
(def +thumbnail-options+
|
||||||
|
{:src :path
|
||||||
|
:dst :thumbnail
|
||||||
|
:width 300
|
||||||
|
:height 100
|
||||||
|
:quality 92
|
||||||
|
:format "webp"})
|
||||||
|
|
||||||
|
(defn populate-thumbnail
|
||||||
|
[row]
|
||||||
|
(let [opts +thumbnail-options+]
|
||||||
|
(-> (px/submit! #(images/populate-thumbnails row opts))
|
||||||
|
(su/handle-on-context))))
|
||||||
|
|
||||||
|
(defn populate-thumbnails
|
||||||
|
[rows]
|
||||||
|
(if (empty? rows)
|
||||||
|
rows
|
||||||
|
(p/all (map populate-thumbnail rows))))
|
||||||
|
|
||||||
|
(defn populate-urls
|
||||||
|
[row]
|
||||||
|
(images/populate-urls row media/images-storage :path :url))
|
||||||
|
|
||||||
|
(s/def ::id ::us/uuid)
|
||||||
|
(s/def ::name ::us/string)
|
||||||
|
(s/def ::user ::us/uuid)
|
||||||
|
(s/def ::collection-id (s/nilable ::us/uuid))
|
||||||
|
|
||||||
|
(def ^:private images-collections-sql
|
||||||
|
"select *,
|
||||||
|
(select count(*) from images where collection_id = ic.id) as num_images
|
||||||
|
from images_collections as ic
|
||||||
|
where (ic.user_id = $1 or
|
||||||
|
ic.user_id = '00000000-0000-0000-0000-000000000000'::uuid)
|
||||||
|
and ic.deleted_at is null
|
||||||
|
order by ic.created_at desc;")
|
||||||
|
|
||||||
|
(s/def ::images-collections
|
||||||
|
(s/keys :req-un [::user]))
|
||||||
|
|
||||||
|
(sq/defquery ::images-collections
|
||||||
|
[{:keys [user] :as params}]
|
||||||
|
(db/query db/pool [images-collections-sql user]))
|
||||||
|
|
||||||
|
;; --- Retrieve Image
|
||||||
|
|
||||||
|
(defn retrieve-image
|
||||||
|
[conn id]
|
||||||
|
(let [sql "select * from images
|
||||||
|
where id = $1
|
||||||
|
and deleted_at is null;"]
|
||||||
|
(db/query-one conn [sql id])))
|
||||||
|
|
||||||
|
;; (s/def ::retrieve-image
|
||||||
|
;; (s/keys :req-un [::user ::us/id]))
|
||||||
|
|
||||||
|
;; (defmethod core/query :retrieve-image
|
||||||
|
;; [params]
|
||||||
|
;; (s/assert ::retrieve-image params)
|
||||||
|
;; (with-open [conn (db/connection)]
|
||||||
|
;; (retrieve-image conn params)))
|
||||||
|
|
||||||
|
;; --- Query Images by Collection (id)
|
||||||
|
|
||||||
|
(def images-by-collection-sql
|
||||||
|
"select * from images
|
||||||
|
where (user_id = $1 or
|
||||||
|
user_id = '00000000-0000-0000-0000-000000000000'::uuid)
|
||||||
|
and deleted_at is null
|
||||||
|
and case when $2::uuid is null then collection_id is null
|
||||||
|
else collection_id = $2::uuid
|
||||||
|
end
|
||||||
|
order by created_at desc;")
|
||||||
|
|
||||||
|
(s/def ::images-by-collection-query
|
||||||
|
(s/keys :req-un [::user]
|
||||||
|
:opt-un [::collection-id]))
|
||||||
|
|
||||||
|
(sq/defquery ::images-by-collection
|
||||||
|
[{:keys [user collection-id] :as params}]
|
||||||
|
(let [sqlv [images-by-collection-sql user collection-id]]
|
||||||
|
(-> (db/query db/pool sqlv)
|
||||||
|
(p/then populate-thumbnails)
|
||||||
|
(p/then #(mapv populate-urls %)))))
|
||||||
|
|
92
backend/src/uxbox/services/queries/pages.clj
Normal file
92
backend/src/uxbox/services/queries/pages.clj
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
|
(ns uxbox.services.queries.pages
|
||||||
|
(:require
|
||||||
|
[clojure.spec.alpha :as s]
|
||||||
|
[promesa.core :as p]
|
||||||
|
[uxbox.db :as db]
|
||||||
|
[uxbox.services.queries :as sq]
|
||||||
|
[uxbox.util.blob :as blob]
|
||||||
|
[uxbox.util.spec :as us]
|
||||||
|
[uxbox.util.sql :as sql]))
|
||||||
|
|
||||||
|
;; --- Helpers & Specs
|
||||||
|
|
||||||
|
(declare decode-row)
|
||||||
|
|
||||||
|
(s/def ::id ::us/uuid)
|
||||||
|
(s/def ::user ::us/uuid)
|
||||||
|
(s/def ::project-id ::us/uuid)
|
||||||
|
|
||||||
|
;; --- Query: Pages by Project
|
||||||
|
|
||||||
|
(s/def ::pages-by-project
|
||||||
|
(s/keys :req-un [::user ::project-id]))
|
||||||
|
|
||||||
|
(sq/defquery ::pages-by-project
|
||||||
|
[{:keys [user project-id] :as params}]
|
||||||
|
(let [sql "select pg.*,
|
||||||
|
pg.data,
|
||||||
|
pg.metadata
|
||||||
|
from pages as pg
|
||||||
|
where pg.user_id = $2
|
||||||
|
and pg.project_id = $1
|
||||||
|
and pg.deleted_at is null
|
||||||
|
order by pg.created_at asc;"]
|
||||||
|
(-> (db/query db/pool [sql project-id user])
|
||||||
|
(p/then #(mapv decode-row %)))))
|
||||||
|
|
||||||
|
;; --- Query: Page by Id
|
||||||
|
|
||||||
|
(s/def ::page
|
||||||
|
(s/keys :req-un [::user ::id]))
|
||||||
|
|
||||||
|
(sq/defquery ::page
|
||||||
|
[{:keys [user id] :as params}]
|
||||||
|
(let [sql "select pg.*,
|
||||||
|
pg.data,
|
||||||
|
pg.metadata
|
||||||
|
from pages as pg
|
||||||
|
where pg.user_id = $2
|
||||||
|
and pg.id = $1
|
||||||
|
and pg.deleted_at is null"]
|
||||||
|
(-> (db/query-one db/pool [sql id user])
|
||||||
|
(p/then' decode-row))))
|
||||||
|
|
||||||
|
;; --- Query: Page History
|
||||||
|
|
||||||
|
(s/def ::page-id ::us/uuid)
|
||||||
|
(s/def ::max ::us/integer)
|
||||||
|
(s/def ::pinned ::us/boolean)
|
||||||
|
(s/def ::since ::us/integer)
|
||||||
|
|
||||||
|
(s/def ::page-history
|
||||||
|
(s/keys :req-un [::page-id ::user]
|
||||||
|
:opt-un [::max ::pinned ::since]))
|
||||||
|
|
||||||
|
(sq/defquery ::page-history
|
||||||
|
[{:keys [page-id user since max pinned] :or {since Long/MAX_VALUE max 10}}]
|
||||||
|
(let [sql (-> (sql/from ["pages_history" "ph"])
|
||||||
|
(sql/select "ph.*")
|
||||||
|
(sql/where ["ph.user_id = ?" user]
|
||||||
|
["ph.page_id = ?" page-id]
|
||||||
|
["ph.version < ?" since]
|
||||||
|
(when pinned
|
||||||
|
["ph.pinned = ?" true]))
|
||||||
|
(sql/order "ph.version desc")
|
||||||
|
(sql/limit max))]
|
||||||
|
(-> (db/query db/pool (sql/fmt sql))
|
||||||
|
(p/then (partial mapv decode-row)))))
|
||||||
|
|
||||||
|
;; --- Helpers
|
||||||
|
|
||||||
|
(defn decode-row
|
||||||
|
[{:keys [data metadata] :as row}]
|
||||||
|
(when row
|
||||||
|
(cond-> row
|
||||||
|
data (assoc :data (blob/decode data))
|
||||||
|
metadata (assoc :metadata (blob/decode metadata)))))
|
73
backend/src/uxbox/services/queries/profiles.clj
Normal file
73
backend/src/uxbox/services/queries/profiles.clj
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
|
(ns uxbox.services.queries.profiles
|
||||||
|
(:require
|
||||||
|
[clojure.spec.alpha :as s]
|
||||||
|
[promesa.core :as p]
|
||||||
|
[promesa.exec :as px]
|
||||||
|
[uxbox.db :as db]
|
||||||
|
[uxbox.images :as images]
|
||||||
|
[uxbox.services.queries :as sq]
|
||||||
|
[uxbox.services.util :as su]
|
||||||
|
[uxbox.util.blob :as blob]
|
||||||
|
[uxbox.util.spec :as us]))
|
||||||
|
|
||||||
|
;; --- Helpers & Specs
|
||||||
|
|
||||||
|
(declare decode-profile-row)
|
||||||
|
(declare strip-private-attrs)
|
||||||
|
|
||||||
|
(s/def ::email ::us/email)
|
||||||
|
(s/def ::fullname ::us/string)
|
||||||
|
(s/def ::metadata any?)
|
||||||
|
(s/def ::old-password ::us/string)
|
||||||
|
(s/def ::password ::us/string)
|
||||||
|
(s/def ::path ::us/string)
|
||||||
|
(s/def ::user ::us/uuid)
|
||||||
|
(s/def ::username ::us/string)
|
||||||
|
|
||||||
|
;; --- Query: Profile (own)
|
||||||
|
|
||||||
|
(defn resolve-thumbnail
|
||||||
|
[user]
|
||||||
|
(let [opts {:src :photo
|
||||||
|
:dst :photo
|
||||||
|
:size [100 100]
|
||||||
|
:quality 90
|
||||||
|
:format "jpg"}]
|
||||||
|
(-> (px/submit! #(images/populate-thumbnails user opts))
|
||||||
|
(su/handle-on-context))))
|
||||||
|
|
||||||
|
(defn get-profile
|
||||||
|
[conn id]
|
||||||
|
(let [sql "select * from users where id=$1 and deleted_at is null"]
|
||||||
|
(-> (db/query-one db/pool [sql id])
|
||||||
|
(p/then' decode-profile-row))))
|
||||||
|
|
||||||
|
(s/def ::profile
|
||||||
|
(s/keys :req-un [::user]))
|
||||||
|
|
||||||
|
(sq/defquery :profile
|
||||||
|
{:doc "Retrieve the user profile."
|
||||||
|
:spec ::profile}
|
||||||
|
[{:keys [user] :as params}]
|
||||||
|
(-> (get-profile db/pool user)
|
||||||
|
(p/then' strip-private-attrs)))
|
||||||
|
|
||||||
|
;; --- Attrs Helpers
|
||||||
|
|
||||||
|
(defn decode-profile-row
|
||||||
|
[{:keys [metadata] :as row}]
|
||||||
|
(when row
|
||||||
|
(cond-> row
|
||||||
|
metadata (assoc :metadata (blob/decode metadata)))))
|
||||||
|
|
||||||
|
(defn strip-private-attrs
|
||||||
|
"Only selects a publicy visible user attrs."
|
||||||
|
[profile]
|
||||||
|
(select-keys profile [:id :username :fullname :metadata
|
||||||
|
:email :created-at :photo]))
|
48
backend/src/uxbox/services/queries/projects.clj
Normal file
48
backend/src/uxbox/services/queries/projects.clj
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
|
(ns uxbox.services.queries.projects
|
||||||
|
(:require
|
||||||
|
[clojure.spec.alpha :as s]
|
||||||
|
[promesa.core :as p]
|
||||||
|
[uxbox.db :as db]
|
||||||
|
[uxbox.services.queries :as sq]
|
||||||
|
[uxbox.util.blob :as blob]
|
||||||
|
[uxbox.util.spec :as us]))
|
||||||
|
|
||||||
|
;; --- Helpers & Specs
|
||||||
|
|
||||||
|
(s/def ::id ::us/uuid)
|
||||||
|
(s/def ::name ::us/string)
|
||||||
|
(s/def ::token ::us/string)
|
||||||
|
(s/def ::user ::us/uuid)
|
||||||
|
|
||||||
|
;; --- Query: Projects
|
||||||
|
|
||||||
|
(def ^:private projects-sql
|
||||||
|
"select distinct on (p.id, p.created_at)
|
||||||
|
p.*,
|
||||||
|
array_agg(pg.id) over (
|
||||||
|
partition by p.id
|
||||||
|
order by pg.created_at
|
||||||
|
range between unbounded preceding and unbounded following
|
||||||
|
) as pages
|
||||||
|
from projects as p
|
||||||
|
left join pages as pg
|
||||||
|
on (pg.project_id = p.id)
|
||||||
|
where p.user_id = $1
|
||||||
|
order by p.created_at asc")
|
||||||
|
|
||||||
|
(s/def ::projects-query
|
||||||
|
(s/keys :req-un [::user]))
|
||||||
|
|
||||||
|
(sq/defquery :projects
|
||||||
|
{:doc "Query all projects"
|
||||||
|
:spec ::projects-query}
|
||||||
|
[{:keys [user] :as params}]
|
||||||
|
(-> (db/query db/pool [projects-sql user])
|
||||||
|
(p/then (fn [rows]
|
||||||
|
(mapv #(update % :pages vec) rows)))))
|
34
backend/src/uxbox/services/queries/user_storage.clj
Normal file
34
backend/src/uxbox/services/queries/user_storage.clj
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
|
(ns uxbox.services.queries.user-storage
|
||||||
|
(:require
|
||||||
|
[clojure.spec.alpha :as s]
|
||||||
|
[promesa.core :as p]
|
||||||
|
[uxbox.db :as db]
|
||||||
|
[uxbox.services.queries :as sq]
|
||||||
|
[uxbox.services.util :as su]
|
||||||
|
[uxbox.util.blob :as blob]
|
||||||
|
[uxbox.util.spec :as us]))
|
||||||
|
|
||||||
|
(defn decode-row
|
||||||
|
[{:keys [val] :as row}]
|
||||||
|
(when row
|
||||||
|
(cond-> row
|
||||||
|
val (assoc :val (blob/decode val)))))
|
||||||
|
|
||||||
|
(s/def ::user-storage-item
|
||||||
|
(s/keys :req-un [::key ::user]))
|
||||||
|
|
||||||
|
(sq/defquery ::user-storage-entry
|
||||||
|
[{:keys [key user]}]
|
||||||
|
(let [sql "select kv.*
|
||||||
|
from user_storage as kv
|
||||||
|
where kv.user_id = $2
|
||||||
|
and kv.key = $1"]
|
||||||
|
(-> (db/query-one db/pool [sql key user])
|
||||||
|
(p/then' su/raise-not-found-if-nil)
|
||||||
|
(p/then' decode-row))))
|
39
backend/src/uxbox/services/util.clj
Normal file
39
backend/src/uxbox/services/util.clj
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
|
(ns uxbox.services.util
|
||||||
|
(:require
|
||||||
|
[clojure.tools.logging :as log]
|
||||||
|
[vertx.core :as vc]
|
||||||
|
[uxbox.core :refer [system]]
|
||||||
|
[uxbox.util.uuid :as uuid]
|
||||||
|
[uxbox.util.dispatcher :as uds]
|
||||||
|
[uxbox.util.exceptions :as ex]))
|
||||||
|
|
||||||
|
;; (def logging-interceptor
|
||||||
|
;; {:enter (fn [data]
|
||||||
|
;; (let [type (get-in data [:request ::type])]
|
||||||
|
;; (assoc data ::start-time (System/nanoTime))))
|
||||||
|
;; :leave (fn [data]
|
||||||
|
;; (let [elapsed (- (System/nanoTime) (::start-time data))
|
||||||
|
;; elapsed (str (quot elapsed 1000000) "ms")
|
||||||
|
;; type (get-in data [:request ::type])]
|
||||||
|
;; (log/info "service" type "processed in" elapsed)
|
||||||
|
;; data))})
|
||||||
|
|
||||||
|
(defn raise-not-found-if-nil
|
||||||
|
[v]
|
||||||
|
(if (nil? v)
|
||||||
|
(ex/raise :type :not-found
|
||||||
|
:hint "Object doest not exists.")
|
||||||
|
v))
|
||||||
|
|
||||||
|
(def constantly-nil (constantly nil))
|
||||||
|
|
||||||
|
(defn handle-on-context
|
||||||
|
[p]
|
||||||
|
(->> (vc/get-or-create-context system)
|
||||||
|
(vc/handle-on-context p)))
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
(ns uxbox.util.migrations
|
(ns uxbox.util.migrations
|
||||||
(:require
|
(:require
|
||||||
|
[clojure.tools.logging :as log]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
|
@ -56,7 +57,7 @@
|
||||||
(-> (registered? pool modname (:name migration))
|
(-> (registered? pool modname (:name migration))
|
||||||
(p/then (fn [registered?]
|
(p/then (fn [registered?]
|
||||||
(when-not registered?
|
(when-not registered?
|
||||||
(println (str/format "applying migration - %s: %s" modname name))
|
(log/info (str/format "applying migration %s/%s" modname name))
|
||||||
(execute)))))))
|
(execute)))))))
|
||||||
|
|
||||||
(defn- impl-migrate
|
(defn- impl-migrate
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[mount.core :as mount]
|
[mount.core :as mount]
|
||||||
[datoteka.storages :as st]
|
[datoteka.storages :as st]
|
||||||
|
[uxbox.services.mutations.profiles :as profiles]
|
||||||
|
[uxbox.services.mutations.projects :as projects]
|
||||||
|
[uxbox.services.mutations.pages :as pages]
|
||||||
[uxbox.fixtures :as fixtures]
|
[uxbox.fixtures :as fixtures]
|
||||||
[uxbox.migrations]
|
[uxbox.migrations]
|
||||||
[uxbox.media]
|
[uxbox.media]
|
||||||
|
@ -59,52 +62,29 @@
|
||||||
|
|
||||||
;; --- Users creation
|
;; --- Users creation
|
||||||
|
|
||||||
(declare decode-user-row)
|
|
||||||
(declare decode-page-row)
|
|
||||||
|
|
||||||
(defn create-user
|
(defn create-user
|
||||||
[conn i]
|
[conn i]
|
||||||
(let [sql "insert into users (id, fullname, username, email, password, metadata, photo)
|
(profiles/create-profile conn {:id (mk-uuid "user" i)
|
||||||
values ($1, $2, $3, $4, $5, $6, '') returning *"]
|
:fullname (str "User " i)
|
||||||
(-> (db/query-one conn [sql
|
:username (str "user" i)
|
||||||
(mk-uuid "user" i)
|
:email (str "user" i ".test@uxbox.io")
|
||||||
(str "User " i)
|
:password "123123"
|
||||||
(str "user" i)
|
:metadata {}}))
|
||||||
(str "user" i ".test@uxbox.io")
|
|
||||||
(hashers/encrypt "123123")
|
|
||||||
(blob/encode {})])
|
|
||||||
(p/then' decode-user-row))))
|
|
||||||
|
|
||||||
(defn create-project
|
(defn create-project
|
||||||
[conn uid i]
|
[conn user-id i]
|
||||||
(let [sql "insert into projects (id, user_id, name)
|
(projects/create-project conn {:id (mk-uuid "project" i)
|
||||||
values ($1, $2, $3) returning *"
|
:user user-id
|
||||||
name (str "sample project " i)]
|
:name (str "sample project " i)}))
|
||||||
(db/query-one conn [sql (mk-uuid "project" i) uid name])))
|
|
||||||
|
|
||||||
(defn create-page
|
(defn create-page
|
||||||
[conn uid pid i]
|
[conn uid pid i]
|
||||||
(let [sql "insert into pages (id, user_id, project_id, name, data, metadata)
|
(pages/create-page conn {:id (mk-uuid "page" i)
|
||||||
values ($1, $2, $3, $4, $5, $6) returning *"
|
:user uid
|
||||||
data (blob/encode {:shapes []})
|
:project-id pid
|
||||||
mdata (blob/encode {})
|
:name (str "page" i)
|
||||||
name (str "page" i)
|
:data {:shapes []}
|
||||||
id (mk-uuid "page" i)]
|
:metadata {}}))
|
||||||
(-> (db/query-one conn [sql id uid pid name data mdata])
|
|
||||||
(p/then' decode-page-row))))
|
|
||||||
|
|
||||||
(defn- decode-page-row
|
|
||||||
[{:keys [data metadata] :as row}]
|
|
||||||
(when row
|
|
||||||
(cond-> row
|
|
||||||
data (assoc :data (blob/decode data))
|
|
||||||
metadata (assoc :metadata (blob/decode metadata)))))
|
|
||||||
|
|
||||||
(defn- decode-user-row
|
|
||||||
[{:keys [metadata] :as row}]
|
|
||||||
(when row
|
|
||||||
(cond-> row
|
|
||||||
metadata (assoc :metadata (blob/decode metadata)))))
|
|
||||||
|
|
||||||
(defn handle-error
|
(defn handle-error
|
||||||
[err]
|
[err]
|
||||||
|
@ -152,10 +132,9 @@
|
||||||
(do
|
(do
|
||||||
(println "====> START ERROR")
|
(println "====> START ERROR")
|
||||||
(if (= :spec-validation (:code error))
|
(if (= :spec-validation (:code error))
|
||||||
(do
|
(s/explain-out (:data error))
|
||||||
(s/explain-out (:data error))
|
(prn error))
|
||||||
(println "====> END ERROR"))
|
(println "====> END ERROR"))
|
||||||
(prn error)))
|
|
||||||
(do
|
(do
|
||||||
(println "====> START RESPONSE")
|
(println "====> START RESPONSE")
|
||||||
(prn result)
|
(prn result)
|
||||||
|
|
|
@ -11,14 +11,13 @@
|
||||||
[mockery.core :refer [with-mock]]
|
[mockery.core :refer [with-mock]]
|
||||||
[uxbox.db :as db]
|
[uxbox.db :as db]
|
||||||
[uxbox.emails :as emails]
|
[uxbox.emails :as emails]
|
||||||
[uxbox.services.core :as sv]
|
|
||||||
[uxbox.tests.helpers :as th]))
|
[uxbox.tests.helpers :as th]))
|
||||||
|
|
||||||
(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 register-email-rendering
|
(t/deftest register-email-rendering
|
||||||
(let [result (emails/render emails/register {:to "example@uxbox.io"})]
|
(let [result (emails/render emails/register {:to "example@uxbox.io" :name "foo"})]
|
||||||
(t/is (map? result))
|
(t/is (map? result))
|
||||||
(t/is (contains? result :subject))
|
(t/is (contains? result :subject))
|
||||||
(t/is (contains? result :body))
|
(t/is (contains? result :body))
|
||||||
|
@ -27,7 +26,7 @@
|
||||||
(t/is (vector? (:body result)))))
|
(t/is (vector? (:body result)))))
|
||||||
|
|
||||||
(t/deftest email-sending-and-sendmail-job
|
(t/deftest email-sending-and-sendmail-job
|
||||||
(let [res @(emails/send! emails/register {:to "example@uxbox.io"})]
|
(let [res @(emails/send! emails/register {:to "example@uxbox.io" :name "foo"})]
|
||||||
(t/is (nil? res)))
|
(t/is (nil? res)))
|
||||||
(with-mock mock
|
(with-mock mock
|
||||||
{:target 'uxbox.jobs.sendmail/impl-sendmail
|
{:target 'uxbox.jobs.sendmail/impl-sendmail
|
||||||
|
|
|
@ -8,35 +8,34 @@
|
||||||
(:require
|
(:require
|
||||||
[clojure.test :as t]
|
[clojure.test :as t]
|
||||||
[promesa.core :as p]
|
[promesa.core :as p]
|
||||||
[buddy.hashers :as hashers]
|
|
||||||
[uxbox.db :as db]
|
[uxbox.db :as db]
|
||||||
[uxbox.services.core :as sv]
|
[uxbox.services.mutations :as sm]
|
||||||
[uxbox.tests.helpers :as th]))
|
[uxbox.tests.helpers :as th]))
|
||||||
|
|
||||||
(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 test-failed-auth
|
(t/deftest failed-auth
|
||||||
(let [user @(th/create-user db/pool 1)
|
(let [user @(th/create-user db/pool 1)
|
||||||
event {:username "user1"
|
event {:username "user1"
|
||||||
:type :login
|
::sm/type :login
|
||||||
:password "foobar"
|
:password "foobar"
|
||||||
:metadata "1"
|
:metadata "1"
|
||||||
:scope "foobar"}
|
:scope "foobar"}
|
||||||
[err res] (th/try-on
|
out (th/try-on! (sm/handle event))]
|
||||||
(sv/mutation event))]
|
;; (th/print-result! out)
|
||||||
(t/is (nil? res))
|
(t/is (map? (:error out)))
|
||||||
(t/is (= (:type err) :validation))
|
(t/is (= (get-in out [:error :type]) :validation))
|
||||||
(t/is (= (:code err) :uxbox.services.auth/wrong-credentials))))
|
(t/is (= (get-in out [:error :code]) :uxbox.services.mutations.auth/wrong-credentials))))
|
||||||
|
|
||||||
(t/deftest test-success-auth
|
(t/deftest success-auth
|
||||||
(let [user @(th/create-user db/pool 1)
|
(let [user @(th/create-user db/pool 1)
|
||||||
event {:username "user1"
|
event {:username "user1"
|
||||||
:type :login
|
::sm/type :login
|
||||||
:password "123123"
|
:password "123123"
|
||||||
:metadata "1"
|
:metadata "1"
|
||||||
:scope "foobar"}
|
:scope "foobar"}
|
||||||
[err res] (th/try-on
|
out (th/try-on! (sm/handle event))]
|
||||||
(sv/mutation event))]
|
;; (th/print-result! out)
|
||||||
(t/is (= res (:id user)))
|
(t/is (nil? (:error out)))
|
||||||
(t/is (nil? err))))
|
(t/is (= (get-in out [:result :id]) (:id user)))))
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
(ns uxbox.tests.test-services-kvstore
|
|
||||||
(:require
|
|
||||||
[clojure.spec.alpha :as s]
|
|
||||||
[clojure.test :as t]
|
|
||||||
[promesa.core :as p]
|
|
||||||
[uxbox.db :as db]
|
|
||||||
[uxbox.http :as http]
|
|
||||||
[uxbox.services.core :as sv]
|
|
||||||
[uxbox.tests.helpers :as th]))
|
|
||||||
|
|
||||||
(t/use-fixtures :once th/state-init)
|
|
||||||
(t/use-fixtures :each th/database-reset)
|
|
||||||
|
|
||||||
(t/deftest test-mutation-upsert-kvstore
|
|
||||||
(let [{:keys [id] :as user} @(th/create-user db/pool 1)]
|
|
||||||
(let [out (th/try-on! (sv/query {::sv/type :kvstore-entry
|
|
||||||
:key "foobar"
|
|
||||||
:user id}))]
|
|
||||||
;; (th/print-result! out)
|
|
||||||
(t/is (nil? (:error out)))
|
|
||||||
(t/is (nil? (:result out))))
|
|
||||||
|
|
||||||
(let [out (th/try-on! (sv/mutation {::sv/type :upsert-kvstore
|
|
||||||
:user id
|
|
||||||
:key "foobar"
|
|
||||||
:value {:some #{:value}}}))]
|
|
||||||
;; (th/print-result! out)
|
|
||||||
(t/is (nil? (:error out)))
|
|
||||||
(t/is (nil? (:result out))))
|
|
||||||
|
|
||||||
(let [out (th/try-on! (sv/query {::sv/type :kvstore-entry
|
|
||||||
:key "foobar"
|
|
||||||
:user id}))]
|
|
||||||
;; (th/print-result! out)
|
|
||||||
(t/is (nil? (:error out)))
|
|
||||||
(t/is (= {:some #{:value}} (get-in out [:result :value])))
|
|
||||||
(t/is (= "foobar" (get-in out [:result :key]))))
|
|
||||||
|
|
||||||
(let [out (th/try-on! (sv/mutation {::sv/type :delete-kvstore
|
|
||||||
:user id
|
|
||||||
:key "foobar"}))]
|
|
||||||
;; (th/print-result! out)
|
|
||||||
(t/is (nil? (:error out)))
|
|
||||||
(t/is (nil? (:result out))))
|
|
||||||
|
|
||||||
(let [out (th/try-on! (sv/query {::sv/type :kvstore-entry
|
|
||||||
:key "foobar"
|
|
||||||
:user id}))]
|
|
||||||
;; (th/print-result! out)
|
|
||||||
(t/is (nil? (:error out)))
|
|
||||||
(t/is (nil? (:result out))))))
|
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
[promesa.core :as p]
|
[promesa.core :as p]
|
||||||
[uxbox.db :as db]
|
[uxbox.db :as db]
|
||||||
[uxbox.http :as http]
|
[uxbox.http :as http]
|
||||||
[uxbox.services.core :as sv]
|
[uxbox.services.mutations :as sm]
|
||||||
|
[uxbox.services.queries :as sq]
|
||||||
[uxbox.tests.helpers :as th]))
|
[uxbox.tests.helpers :as th]))
|
||||||
|
|
||||||
(t/use-fixtures :once th/state-init)
|
(t/use-fixtures :once th/state-init)
|
||||||
|
@ -14,13 +15,13 @@
|
||||||
(t/deftest mutation-create-page
|
(t/deftest mutation-create-page
|
||||||
(let [user @(th/create-user db/pool 1)
|
(let [user @(th/create-user db/pool 1)
|
||||||
proj @(th/create-project db/pool (:id user) 1)
|
proj @(th/create-project db/pool (:id user) 1)
|
||||||
data {::sv/type :create-page
|
data {::sm/type :create-page
|
||||||
:data {:shapes []}
|
:data {:shapes []}
|
||||||
:metadata {}
|
:metadata {}
|
||||||
:project-id (:id proj)
|
:project-id (:id proj)
|
||||||
:name "test page"
|
:name "test page"
|
||||||
:user (:id user)}
|
:user (:id user)}
|
||||||
res (th/try-on! (sv/mutation data))]
|
res (th/try-on! (sm/handle data))]
|
||||||
(t/is (nil? (:error res)))
|
(t/is (nil? (:error res)))
|
||||||
(t/is (uuid? (get-in res [:result :id])))
|
(t/is (uuid? (get-in res [:result :id])))
|
||||||
(let [rsp (:result res)]
|
(let [rsp (:result res)]
|
||||||
|
@ -33,35 +34,35 @@
|
||||||
(let [user @(th/create-user db/pool 1)
|
(let [user @(th/create-user db/pool 1)
|
||||||
proj @(th/create-project db/pool (:id user) 1)
|
proj @(th/create-project db/pool (:id user) 1)
|
||||||
page @(th/create-page db/pool (:id user) (:id proj) 1)
|
page @(th/create-page db/pool (:id user) (:id proj) 1)
|
||||||
data {::sv/type :update-page
|
data {::sm/type :update-page
|
||||||
:id (:id page)
|
:id (:id page)
|
||||||
:data {:shapes [1 2 3]}
|
:data {:shapes [1 2 3]}
|
||||||
:metadata {:foo 2}
|
:metadata {:foo 2}
|
||||||
:project-id (:id proj)
|
:project-id (:id proj)
|
||||||
:name "test page"
|
:name "test page"
|
||||||
:user (:id user)}
|
:user (:id user)}
|
||||||
res (th/try-on! (sv/mutation data))]
|
res (th/try-on! (sm/handle data))]
|
||||||
|
|
||||||
;; (th/print-result! res)
|
;; (th/print-result! res)
|
||||||
|
|
||||||
(t/is (nil? (:error res)))
|
(t/is (nil? (:error res)))
|
||||||
(t/is (= (:id data) (get-in res [:result :id])))
|
(t/is (= (:id data) (get-in res [:result :id])))
|
||||||
(t/is (= (:user data) (get-in res [:result :user-id])))
|
#_(t/is (= (:user data) (get-in res [:result :user-id])))
|
||||||
(t/is (= (:name data) (get-in res [:result :name])))
|
#_(t/is (= (:name data) (get-in res [:result :name])))
|
||||||
(t/is (= (:data data) (get-in res [:result :data])))
|
#_(t/is (= (:data data) (get-in res [:result :data])))
|
||||||
(t/is (= (:metadata data) (get-in res [:result :metadata])))))
|
#_(t/is (= (:metadata data) (get-in res [:result :metadata])))))
|
||||||
|
|
||||||
(t/deftest mutation-update-page-metadata
|
(t/deftest mutation-update-page-metadata
|
||||||
(let [user @(th/create-user db/pool 1)
|
(let [user @(th/create-user db/pool 1)
|
||||||
proj @(th/create-project db/pool (:id user) 1)
|
proj @(th/create-project db/pool (:id user) 1)
|
||||||
page @(th/create-page db/pool (:id user) (:id proj) 1)
|
page @(th/create-page db/pool (:id user) (:id proj) 1)
|
||||||
data {::sv/type :update-page-metadata
|
data {::sm/type :update-page-metadata
|
||||||
:id (:id page)
|
:id (:id page)
|
||||||
:metadata {:foo 2}
|
:metadata {:foo 2}
|
||||||
:project-id (:id proj)
|
:project-id (:id proj)
|
||||||
:name "test page"
|
:name "test page"
|
||||||
:user (:id user)}
|
:user (:id user)}
|
||||||
res (th/try-on! (sv/mutation data))]
|
res (th/try-on! (sm/handle data))]
|
||||||
|
|
||||||
;; (th/print-result! res)
|
;; (th/print-result! res)
|
||||||
(t/is (nil? (:error res)))
|
(t/is (nil? (:error res)))
|
||||||
|
@ -74,10 +75,10 @@
|
||||||
(let [user @(th/create-user db/pool 1)
|
(let [user @(th/create-user db/pool 1)
|
||||||
proj @(th/create-project db/pool (:id user) 1)
|
proj @(th/create-project db/pool (:id user) 1)
|
||||||
page @(th/create-page db/pool (:id user) (:id proj) 1)
|
page @(th/create-page db/pool (:id user) (:id proj) 1)
|
||||||
data {::sv/type :delete-page
|
data {::sm/type :delete-page
|
||||||
:id (:id page)
|
:id (:id page)
|
||||||
:user (:id user)}
|
:user (:id user)}
|
||||||
res (th/try-on! (sv/mutation data))]
|
res (th/try-on! (sm/handle data))]
|
||||||
|
|
||||||
;; (th/print-result! res)
|
;; (th/print-result! res)
|
||||||
(t/is (nil? (:error res)))
|
(t/is (nil? (:error res)))
|
||||||
|
@ -87,10 +88,10 @@
|
||||||
(let [user @(th/create-user db/pool 1)
|
(let [user @(th/create-user db/pool 1)
|
||||||
proj @(th/create-project db/pool (:id user) 1)
|
proj @(th/create-project db/pool (:id user) 1)
|
||||||
page @(th/create-page db/pool (:id user) (:id proj) 1)
|
page @(th/create-page db/pool (:id user) (:id proj) 1)
|
||||||
data {::sv/type :pages-by-project
|
data {::sq/type :pages-by-project
|
||||||
:project-id (:id proj)
|
:project-id (:id proj)
|
||||||
:user (:id user)}
|
:user (:id user)}
|
||||||
res (th/try-on! (sv/query data))]
|
res (th/try-on! (sq/handle data))]
|
||||||
|
|
||||||
;; (th/print-result! res)
|
;; (th/print-result! res)
|
||||||
(t/is (nil? (:error res)))
|
(t/is (nil? (:error res)))
|
||||||
|
|
|
@ -4,29 +4,35 @@
|
||||||
[promesa.core :as p]
|
[promesa.core :as p]
|
||||||
[uxbox.db :as db]
|
[uxbox.db :as db]
|
||||||
[uxbox.http :as http]
|
[uxbox.http :as http]
|
||||||
[uxbox.services.core :as sv]
|
[uxbox.services.mutations :as sm]
|
||||||
|
[uxbox.services.queries :as sq]
|
||||||
[uxbox.tests.helpers :as th]))
|
[uxbox.tests.helpers :as th]))
|
||||||
|
|
||||||
(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)
|
||||||
|
|
||||||
|
;; TODO: migrate from try-on to try-on!
|
||||||
|
|
||||||
(t/deftest query-project-list
|
(t/deftest query-project-list
|
||||||
(let [user @(th/create-user db/pool 1)
|
(let [user @(th/create-user db/pool 1)
|
||||||
proj @(th/create-project db/pool (:id user) 1)
|
proj @(th/create-project db/pool (:id user) 1)
|
||||||
data {::sv/type :projects
|
data {::sq/type :projects
|
||||||
:user (:id user)}
|
:user (:id user)}
|
||||||
[err rsp] (th/try-on (sv/query data))]
|
out (th/try-on! (sq/handle data))]
|
||||||
(t/is (nil? err))
|
|
||||||
(t/is (= 1 (count rsp)))
|
;; (th/print-result! out)
|
||||||
(t/is (= (:id proj) (get-in rsp [0 :id])))
|
|
||||||
(t/is (= (:name proj (get-in rsp [0 :name]))))))
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (= 1 (count (:result out))))
|
||||||
|
(t/is (= (:id proj) (get-in out [:result 0 :id])))
|
||||||
|
(t/is (= (:name proj) (get-in out [:result 0 :name])))))
|
||||||
|
|
||||||
(t/deftest mutation-create-project
|
(t/deftest mutation-create-project
|
||||||
(let [user @(th/create-user db/pool 1)
|
(let [user @(th/create-user db/pool 1)
|
||||||
data {::sv/type :create-project
|
data {::sm/type :create-project
|
||||||
:user (:id user)
|
:user (:id user)
|
||||||
:name "test project"}
|
:name "test project"}
|
||||||
[err rsp] (th/try-on (sv/mutation data))]
|
[err rsp] (th/try-on (sm/handle data))]
|
||||||
;; (prn "RESPONSE:" err rsp)
|
;; (prn "RESPONSE:" err rsp)
|
||||||
(t/is (nil? err))
|
(t/is (nil? err))
|
||||||
(t/is (= (:user data) (:user-id rsp)))
|
(t/is (= (:user data) (:user-id rsp)))
|
||||||
|
@ -35,11 +41,11 @@
|
||||||
(t/deftest mutation-update-project
|
(t/deftest mutation-update-project
|
||||||
(let [user @(th/create-user db/pool 1)
|
(let [user @(th/create-user db/pool 1)
|
||||||
proj @(th/create-project db/pool (:id user) 1)
|
proj @(th/create-project db/pool (:id user) 1)
|
||||||
data {::sv/type :update-project
|
data {::sm/type :update-project
|
||||||
:id (:id proj)
|
:id (:id proj)
|
||||||
:name "test project mod"
|
:name "test project mod"
|
||||||
:user (:id user)}
|
:user (:id user)}
|
||||||
[err rsp] (th/try-on (sv/mutation data))]
|
[err rsp] (th/try-on (sm/handle data))]
|
||||||
;; (prn "RESPONSE:" err rsp)
|
;; (prn "RESPONSE:" err rsp)
|
||||||
(t/is (nil? err))
|
(t/is (nil? err))
|
||||||
(t/is (= (:id data) (:id rsp)))
|
(t/is (= (:id data) (:id rsp)))
|
||||||
|
@ -49,10 +55,10 @@
|
||||||
(t/deftest mutation-delete-project
|
(t/deftest mutation-delete-project
|
||||||
(let [user @(th/create-user db/pool 1)
|
(let [user @(th/create-user db/pool 1)
|
||||||
proj @(th/create-project db/pool (:id user) 1)
|
proj @(th/create-project db/pool (:id user) 1)
|
||||||
data {::sv/type :delete-project
|
data {::sm/type :delete-project
|
||||||
:id (:id proj)
|
:id (:id proj)
|
||||||
:user (:id user)}
|
:user (:id user)}
|
||||||
[err rsp] (th/try-on (sv/mutation data))]
|
[err rsp] (th/try-on (sm/handle data))]
|
||||||
;; (prn "RESPONSE:" err rsp)
|
;; (prn "RESPONSE:" err rsp)
|
||||||
(t/is (nil? err))
|
(t/is (nil? err))
|
||||||
(t/is (nil? rsp))
|
(t/is (nil? rsp))
|
||||||
|
|
54
backend/test/uxbox/tests/test_services_user_storage.clj
Normal file
54
backend/test/uxbox/tests/test_services_user_storage.clj
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
(ns uxbox.tests.test-services-user-storage
|
||||||
|
(:require
|
||||||
|
[clojure.spec.alpha :as s]
|
||||||
|
[clojure.test :as t]
|
||||||
|
[promesa.core :as p]
|
||||||
|
[uxbox.db :as db]
|
||||||
|
[uxbox.http :as http]
|
||||||
|
[uxbox.services.mutations :as sm]
|
||||||
|
[uxbox.services.queries :as sq]
|
||||||
|
[uxbox.tests.helpers :as th]))
|
||||||
|
|
||||||
|
(t/use-fixtures :once th/state-init)
|
||||||
|
(t/use-fixtures :each th/database-reset)
|
||||||
|
|
||||||
|
(t/deftest test-user-storage
|
||||||
|
(let [{:keys [id] :as user} @(th/create-user db/pool 1)]
|
||||||
|
(let [out (th/try-on! (sq/handle {::sq/type :user-storage-entry
|
||||||
|
:key "foobar"
|
||||||
|
:user id}))]
|
||||||
|
(t/is (nil? (:result out)))
|
||||||
|
(t/is (map? (:error out)))
|
||||||
|
(t/is (= :not-found (get-in out [:error :type]))))
|
||||||
|
|
||||||
|
(let [out (th/try-on! (sm/handle {::sm/type :upsert-user-storage-entry
|
||||||
|
:user id
|
||||||
|
:key "foobar"
|
||||||
|
:val {:some #{:value}}}))]
|
||||||
|
;; (th/print-result! out)
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (nil? (:result out))))
|
||||||
|
|
||||||
|
(let [out (th/try-on! (sq/handle {::sq/type :user-storage-entry
|
||||||
|
:key "foobar"
|
||||||
|
:user id}))]
|
||||||
|
;; (th/print-result! out)
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (= {:some #{:value}} (get-in out [:result :val])))
|
||||||
|
(t/is (= "foobar" (get-in out [:result :key]))))
|
||||||
|
|
||||||
|
(let [out (th/try-on! (sm/handle {::sm/type :delete-user-storage-entry
|
||||||
|
:user id
|
||||||
|
:key "foobar"}))]
|
||||||
|
;; (th/print-result! out)
|
||||||
|
(t/is (nil? (:error out)))
|
||||||
|
(t/is (nil? (:result out))))
|
||||||
|
|
||||||
|
(let [out (th/try-on! (sq/handle {::sq/type :user-storage-entry
|
||||||
|
:key "foobar"
|
||||||
|
:user id}))]
|
||||||
|
;; (th/print-result! out)
|
||||||
|
(t/is (nil? (:result out)))
|
||||||
|
(t/is (map? (:error out)))
|
||||||
|
(t/is (= :not-found (get-in out [:error :type]))))))
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
[promesa.core :as p]
|
[promesa.core :as p]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[datoteka.core :as fs]
|
[datoteka.core :as fs]
|
||||||
;; [buddy.hashers :as hashers]
|
|
||||||
[vertx.core :as vc]
|
[vertx.core :as vc]
|
||||||
[uxbox.db :as db]
|
[uxbox.db :as db]
|
||||||
[uxbox.services.core :as sv]
|
[uxbox.services.mutations :as sm]
|
||||||
|
[uxbox.services.queries :as sq]
|
||||||
[uxbox.tests.helpers :as th]))
|
[uxbox.tests.helpers :as th]))
|
||||||
|
|
||||||
(t/use-fixtures :once th/state-init)
|
(t/use-fixtures :once th/state-init)
|
||||||
|
@ -16,9 +16,9 @@
|
||||||
|
|
||||||
(t/deftest test-query-profile
|
(t/deftest test-query-profile
|
||||||
(let [user @(th/create-user db/pool 1)
|
(let [user @(th/create-user db/pool 1)
|
||||||
event {::sv/type :profile
|
event {::sq/type :profile
|
||||||
:user (:id user)}
|
:user (:id user)}
|
||||||
[err rsp] (th/try-on (sv/query event))]
|
[err rsp] (th/try-on (sq/handle event))]
|
||||||
;; (println "RESPONSE:" resp)))
|
;; (println "RESPONSE:" resp)))
|
||||||
(t/is (nil? err))
|
(t/is (nil? err))
|
||||||
(t/is (= (:fullname rsp) "User 1"))
|
(t/is (= (:fullname rsp) "User 1"))
|
||||||
|
@ -30,12 +30,12 @@
|
||||||
(t/deftest test-mutation-update-profile
|
(t/deftest test-mutation-update-profile
|
||||||
(let [user @(th/create-user db/pool 1)
|
(let [user @(th/create-user db/pool 1)
|
||||||
event (assoc user
|
event (assoc user
|
||||||
::sv/type :update-profile
|
::sm/type :update-profile
|
||||||
:fullname "Full Name"
|
:fullname "Full Name"
|
||||||
:username "user222"
|
:username "user222"
|
||||||
:metadata {:foo "bar"}
|
:metadata {:foo "bar"}
|
||||||
:email "user222@uxbox.io")
|
:email "user222@uxbox.io")
|
||||||
[err data] (th/try-on (sv/mutation event))]
|
[err data] (th/try-on (sm/handle event))]
|
||||||
;; (println "RESPONSE:" err data)
|
;; (println "RESPONSE:" err data)
|
||||||
(t/is (nil? err))
|
(t/is (nil? err))
|
||||||
(t/is (= (:fullname data) "Full Name"))
|
(t/is (= (:fullname data) "Full Name"))
|
||||||
|
@ -46,13 +46,13 @@
|
||||||
|
|
||||||
(t/deftest test-mutation-update-profile-photo
|
(t/deftest test-mutation-update-profile-photo
|
||||||
(let [user @(th/create-user db/pool 1)
|
(let [user @(th/create-user db/pool 1)
|
||||||
event {::sv/type :update-profile-photo
|
event {::sm/type :update-profile-photo
|
||||||
:user (:id user)
|
:user (:id user)
|
||||||
:file {:name "sample.jpg"
|
:file {:name "sample.jpg"
|
||||||
:path (fs/path "test/uxbox/tests/_files/sample.jpg")
|
:path (fs/path "test/uxbox/tests/_files/sample.jpg")
|
||||||
:size 123123
|
:size 123123
|
||||||
:mtype "image/jpeg"}}
|
:mtype "image/jpeg"}}
|
||||||
[err rsp] (th/try-on (sv/mutation event))]
|
[err rsp] (th/try-on (sm/handle event))]
|
||||||
;; (prn "RESPONSE:" [err rsp])
|
;; (prn "RESPONSE:" [err rsp])
|
||||||
(t/is (nil? err))
|
(t/is (nil? err))
|
||||||
(t/is (= (:id user) (:id rsp)))
|
(t/is (= (:id user) (:id rsp)))
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
;; :email "user222@uxbox.io"
|
;; :email "user222@uxbox.io"
|
||||||
;; :password "user222"
|
;; :password "user222"
|
||||||
;; ::sv/type :register-profile}
|
;; ::sv/type :register-profile}
|
||||||
;; [err rsp] (th/try-on (sv/mutation data))]
|
;; [err rsp] (th/try-on (sm/handle data))]
|
||||||
;; (println "RESPONSE:" err rsp)))
|
;; (println "RESPONSE:" err rsp)))
|
||||||
|
|
||||||
;; ;; (t/deftest test-http-validate-recovery-token
|
;; ;; (t/deftest test-http-validate-recovery-token
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue