From 3ce9c8820f2d11787a3cf09f47d69c8c82d59c4d Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 24 Feb 2020 10:57:32 +0100 Subject: [PATCH] :recycle: Rename collections to libraries. And make them team dependent. --- backend/resources/migrations/0002.users.sql | 6 + backend/resources/migrations/0005.images.sql | 57 ---- .../resources/migrations/0005.libraries.sql | 136 ++++++++++ backend/resources/migrations/0006.icons.sql | 44 --- backend/resources/migrations/0007.colors.sql | 43 --- backend/src/uxbox/migrations.clj | 19 +- .../src/uxbox/services/mutations/colors.clj | 253 ++++++++++-------- .../src/uxbox/services/mutations/icons.clj | 245 +++++++++-------- .../src/uxbox/services/mutations/images.clj | 237 ++++++++-------- .../src/uxbox/services/mutations/teams.clj | 33 ++- backend/src/uxbox/services/queries/colors.clj | 125 ++++++--- backend/src/uxbox/services/queries/icons.clj | 121 ++++++--- backend/src/uxbox/services/queries/images.clj | 157 +++++++---- backend/src/uxbox/services/queries/teams.clj | 44 +++ backend/tests/uxbox/tests/helpers.clj | 30 +-- .../uxbox/tests/test_services_colors.clj | 89 +++--- .../tests/uxbox/tests/test_services_files.clj | 6 +- .../tests/uxbox/tests/test_services_icons.clj | 92 ++++--- .../uxbox/tests/test_services_images.clj | 97 ++++--- 19 files changed, 1068 insertions(+), 766 deletions(-) delete mode 100644 backend/resources/migrations/0005.images.sql create mode 100644 backend/resources/migrations/0005.libraries.sql delete mode 100644 backend/resources/migrations/0006.icons.sql delete mode 100644 backend/resources/migrations/0007.colors.sql create mode 100644 backend/src/uxbox/services/queries/teams.clj diff --git a/backend/resources/migrations/0002.users.sql b/backend/resources/migrations/0002.users.sql index 23dc551d3..3ee6870d2 100644 --- a/backend/resources/migrations/0002.users.sql +++ b/backend/resources/migrations/0002.users.sql @@ -69,6 +69,12 @@ CREATE TRIGGER team__modified_at__tgr BEFORE UPDATE ON team FOR EACH ROW EXECUTE PROCEDURE update_modified_at(); +INSERT INTO team (id, name, photo, is_default) +VALUES ('00000000-0000-0000-0000-000000000000'::uuid, + 'System Team', + '', + true); + CREATE TABLE team_profile_rel ( diff --git a/backend/resources/migrations/0005.images.sql b/backend/resources/migrations/0005.images.sql deleted file mode 100644 index cf62f053f..000000000 --- a/backend/resources/migrations/0005.images.sql +++ /dev/null @@ -1,57 +0,0 @@ -CREATE TABLE image_collection ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - profile_id uuid NOT NULL REFERENCES profile(id) ON DELETE CASCADE, - - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - modified_at timestamptz NOT NULL DEFAULT clock_timestamp(), - deleted_at timestamptz DEFAULT NULL, - - name text NOT NULL -); - -CREATE INDEX image_collection__profile_id__idx - ON image_collection(profile_id); - -CREATE TRIGGER image_collection__modified_at__tgr -BEFORE UPDATE ON image_collection - FOR EACH ROW EXECUTE PROCEDURE update_modified_at(); - - - -CREATE TABLE image ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - profile_id uuid NOT NULL REFERENCES profile(id) ON DELETE CASCADE, - collection_id uuid NOT NULL REFERENCES image_collection(id) ON DELETE CASCADE, - - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - modified_at timestamptz NOT NULL DEFAULT clock_timestamp(), - deleted_at timestamptz DEFAULT NULL, - - name text NOT NULL, - - path text NOT NULL, - width int NOT NULL, - height int NOT NULL, - mtype text NOT NULL, - - thumb_path text NOT NULL, - thumb_width int NOT NULL, - thumb_height int NOT NULL, - thumb_quality int NOT NULL, - thumb_mtype text NOT NULL -); - -CREATE INDEX image__profile_id__idx - ON image(profile_id); - -CREATE INDEX image__collection_id__idx - ON image(collection_id); - -CREATE TRIGGER image__modified_at__tgr -BEFORE UPDATE ON image - FOR EACH ROW EXECUTE PROCEDURE update_modified_at(); - -CREATE TRIGGER image__on_delete__tgr - AFTER DELETE ON image - FOR EACH ROW EXECUTE PROCEDURE handle_delete(); - diff --git a/backend/resources/migrations/0005.libraries.sql b/backend/resources/migrations/0005.libraries.sql new file mode 100644 index 000000000..3cc838a97 --- /dev/null +++ b/backend/resources/migrations/0005.libraries.sql @@ -0,0 +1,136 @@ +CREATE TABLE image_library ( + id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), + team_id uuid NOT NULL REFERENCES team(id) ON DELETE CASCADE, + + created_at timestamptz NOT NULL DEFAULT clock_timestamp(), + modified_at timestamptz NOT NULL DEFAULT clock_timestamp(), + deleted_at timestamptz DEFAULT NULL, + + name text NOT NULL +); + +CREATE INDEX image_library__team_id__idx + ON image_library(team_id); + +CREATE TRIGGER image_library__modified_at__tgr +BEFORE UPDATE ON image_library + FOR EACH ROW EXECUTE PROCEDURE update_modified_at(); + + + +CREATE TABLE image ( + id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), + library_id uuid NOT NULL REFERENCES image_library(id) ON DELETE CASCADE, + + created_at timestamptz NOT NULL DEFAULT clock_timestamp(), + modified_at timestamptz NOT NULL DEFAULT clock_timestamp(), + deleted_at timestamptz DEFAULT NULL, + + name text NOT NULL, + + path text NOT NULL, + width int NOT NULL, + height int NOT NULL, + mtype text NOT NULL, + + thumb_path text NOT NULL, + thumb_width int NOT NULL, + thumb_height int NOT NULL, + thumb_quality int NOT NULL, + thumb_mtype text NOT NULL +); + +CREATE INDEX image__library_id__idx + ON image(library_id); + +CREATE TRIGGER image__modified_at__tgr +BEFORE UPDATE ON image + FOR EACH ROW EXECUTE PROCEDURE update_modified_at(); + +CREATE TRIGGER image__on_delete__tgr + AFTER DELETE ON image + FOR EACH ROW EXECUTE PROCEDURE handle_delete(); + + + +CREATE TABLE icon_library ( + id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), + team_id uuid NOT NULL REFERENCES team(id) ON DELETE CASCADE, + + created_at timestamptz NOT NULL DEFAULT clock_timestamp(), + modified_at timestamptz NOT NULL DEFAULT clock_timestamp(), + deleted_at timestamptz DEFAULT NULL, + + name text NOT NULL +); + +CREATE INDEX icon_colection__team_id__idx + ON icon_library (team_id); + +CREATE TRIGGER icon_library__modified_at__tgr +BEFORE UPDATE ON icon_library + FOR EACH ROW EXECUTE PROCEDURE update_modified_at(); + + + +CREATE TABLE icon ( + id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), + library_id uuid REFERENCES icon_library(id) ON DELETE CASCADE, + + created_at timestamptz NOT NULL DEFAULT clock_timestamp(), + modified_at timestamptz NOT NULL DEFAULT clock_timestamp(), + deleted_at timestamptz DEFAULT NULL, + + + name text NOT NULL, + content text NOT NULL, + metadata bytea NOT NULL +); + +CREATE INDEX icon__library_id__idx + ON icon(library_id); + +CREATE TRIGGER icon__modified_at__tgr +BEFORE UPDATE ON icon + FOR EACH ROW EXECUTE PROCEDURE update_modified_at(); + + + +CREATE TABLE color_library ( + id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), + team_id uuid NOT NULL REFERENCES team(id) ON DELETE CASCADE, + + created_at timestamptz NOT NULL DEFAULT clock_timestamp(), + modified_at timestamptz NOT NULL DEFAULT clock_timestamp(), + deleted_at timestamptz DEFAULT NULL, + + name text NOT NULL +); + +CREATE INDEX color_colection__team_id__idx + ON color_library (team_id); + +CREATE TRIGGER color_library__modified_at__tgr +BEFORE UPDATE ON color_library + FOR EACH ROW EXECUTE PROCEDURE update_modified_at(); + + + +CREATE TABLE color ( + id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), + library_id uuid REFERENCES color_library(id) ON DELETE CASCADE, + + created_at timestamptz NOT NULL DEFAULT clock_timestamp(), + modified_at timestamptz NOT NULL DEFAULT clock_timestamp(), + deleted_at timestamptz DEFAULT NULL, + + name text NOT NULL, + content text NOT NULL +); + +CREATE INDEX color__library_id__idx + ON color(library_id); + +CREATE TRIGGER color__modified_at__tgr +BEFORE UPDATE ON color + FOR EACH ROW EXECUTE PROCEDURE update_modified_at(); diff --git a/backend/resources/migrations/0006.icons.sql b/backend/resources/migrations/0006.icons.sql deleted file mode 100644 index 277f8332f..000000000 --- a/backend/resources/migrations/0006.icons.sql +++ /dev/null @@ -1,44 +0,0 @@ -CREATE TABLE icon_collection ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - profile_id uuid NOT NULL REFERENCES profile(id) ON DELETE CASCADE, - - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - modified_at timestamptz NOT NULL DEFAULT clock_timestamp(), - deleted_at timestamptz DEFAULT NULL, - - name text NOT NULL -); - -CREATE INDEX icon_colection__profile_id__idx - ON icon_collection (profile_id); - -CREATE TRIGGER icon_collection__modified_at__tgr -BEFORE UPDATE ON icon_collection - FOR EACH ROW EXECUTE PROCEDURE update_modified_at(); - - - -CREATE TABLE icon ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - profile_id uuid NOT NULL REFERENCES profile(id) ON DELETE CASCADE, - - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - modified_at timestamptz NOT NULL DEFAULT clock_timestamp(), - deleted_at timestamptz DEFAULT NULL, - - collection_id uuid REFERENCES icon_collection(id) - ON DELETE CASCADE, - - name text NOT NULL, - content text NOT NULL, - metadata bytea NOT NULL -); - -CREATE INDEX icon__profile_id__idx - ON icon(profile_id); -CREATE INDEX icon__collection_id__idx - ON icon(collection_id); - -CREATE TRIGGER icon__modified_at__tgr -BEFORE UPDATE ON icon - FOR EACH ROW EXECUTE PROCEDURE update_modified_at(); diff --git a/backend/resources/migrations/0007.colors.sql b/backend/resources/migrations/0007.colors.sql deleted file mode 100644 index d09c8dfd2..000000000 --- a/backend/resources/migrations/0007.colors.sql +++ /dev/null @@ -1,43 +0,0 @@ -CREATE TABLE color_collection ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - profile_id uuid NOT NULL REFERENCES profile(id) ON DELETE CASCADE, - - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - modified_at timestamptz NOT NULL DEFAULT clock_timestamp(), - deleted_at timestamptz DEFAULT NULL, - - name text NOT NULL -); - -CREATE INDEX color_colection__profile_id__idx - ON color_collection (profile_id); - -CREATE TRIGGER color_collection__modified_at__tgr -BEFORE UPDATE ON color_collection - FOR EACH ROW EXECUTE PROCEDURE update_modified_at(); - - - -CREATE TABLE color ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - profile_id uuid NOT NULL REFERENCES profile(id) ON DELETE CASCADE, - - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - modified_at timestamptz NOT NULL DEFAULT clock_timestamp(), - deleted_at timestamptz DEFAULT NULL, - - collection_id uuid REFERENCES color_collection(id) - ON DELETE CASCADE, - - name text NOT NULL, - content text NOT NULL -); - -CREATE INDEX color__profile_id__idx - ON color(profile_id); -CREATE INDEX color__collection_id__idx - ON color(collection_id); - -CREATE TRIGGER color__modified_at__tgr -BEFORE UPDATE ON color - FOR EACH ROW EXECUTE PROCEDURE update_modified_at(); diff --git a/backend/src/uxbox/migrations.clj b/backend/src/uxbox/migrations.clj index ae952c9b5..d4f4d5bdb 100644 --- a/backend/src/uxbox/migrations.clj +++ b/backend/src/uxbox/migrations.clj @@ -12,8 +12,6 @@ [uxbox.util.migrations :as mg] [uxbox.util.template :as tmpl])) -;; --- Migrations - (def +migrations+ {:name "uxbox-main" :steps @@ -29,20 +27,13 @@ {:desc "Initial tasks related tables" :name "0004-tasks" :fn (mg/resource "migrations/0004.tasks.sql")} - {:desc "Initial images tables" - :name "0005-images" - :fn (mg/resource "migrations/0005.images.sql")} - {:desc "Initial icons tables" - :name "0006-icons" - :fn (mg/resource "migrations/0006.icons.sql")} - {:desc "Initial colors tables" - :name "0007-colors" - :fn (mg/resource "migrations/0007.colors.sql")} - ]}) + {:desc "Initial libraries tables" + :name "0005-libraries" + :fn (mg/resource "migrations/0005.libraries.sql")}]}) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Entry point -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn migrate [] diff --git a/backend/src/uxbox/services/mutations/colors.clj b/backend/src/uxbox/services/mutations/colors.clj index 51a320db2..361db64ed 100644 --- a/backend/src/uxbox/services/mutations/colors.clj +++ b/backend/src/uxbox/services/mutations/colors.clj @@ -10,91 +10,87 @@ (ns uxbox.services.mutations.colors (:require [clojure.spec.alpha :as s] - [datoteka.core :as fs] - [datoteka.storages :as ds] [promesa.core :as p] - [promesa.exec :as px] - [uxbox.common.exceptions :as ex] [uxbox.common.spec :as us] [uxbox.config :as cfg] [uxbox.db :as db] - [uxbox.media :as media] - [uxbox.images :as images] [uxbox.tasks :as tasks] - [uxbox.services.queries.colors :refer [decode-row]] + [uxbox.services.queries.teams :as teams] [uxbox.services.mutations :as sm] [uxbox.services.util :as su] - [uxbox.util.blob :as blob] - [uxbox.util.uuid :as uuid] - [vertx.util :as vu])) + [uxbox.util.uuid :as uuid])) ;; --- Helpers & Specs (s/def ::id ::us/uuid) (s/def ::name ::us/string) (s/def ::profile-id ::us/uuid) -(s/def ::collection-id ::us/uuid) +(s/def ::team-id ::us/uuid) +(s/def ::library-id ::us/uuid) (s/def ::content ::us/string) -;; --- Mutation: Create Collection +;; --- Mutation: Create Library -(declare create-color-collection) +(declare create-library) -(s/def ::create-color-collection - (s/keys :req-un [::profile-id ::name] +(s/def ::create-color-library + (s/keys :req-un [::profile-id ::team-id ::name] :opt-un [::id])) -(sm/defmutation ::create-color-collection - [{:keys [id profile-id name] :as params}] +(sm/defmutation ::create-color-library + [{:keys [profile-id team-id] :as params}] (db/with-atomic [conn db/pool] - (create-color-collection conn params))) + (teams/check-edition-permissions! conn profile-id team-id) + (create-library conn params))) -(def ^:private sql:create-color-collection - "insert into color_collection (id, profile_id, name) +(def ^:private sql:create-library + "insert into color_library (id, team_id, name) values ($1, $2, $3) returning *;") -(defn- create-color-collection - [conn {:keys [id profile-id name] :as params}] +(defn- create-library + [conn {:keys [id team-id name]}] (let [id (or id (uuid/next))] - (db/query-one conn [sql:create-color-collection id profile-id name]))) + (db/query-one conn [sql:create-library id team-id name]))) +;; --- Mutation: Rename Library -;; --- Collection Permissions Check +(declare select-library-for-update) +(declare rename-library) -(def ^:private sql:select-collection - "select id, profile_id - from color_collection - where id=$1 and deleted_at is null - for update") - -(defn- check-collection-edition-permissions! - [conn profile-id coll-id] - (p/let [coll (-> (db/query-one conn [sql:select-collection coll-id]) - (p/then' su/raise-not-found-if-nil))] - (when (not= (:profile-id coll) profile-id) - (ex/raise :type :validation - :code :not-authorized)))) - - -;; --- Mutation: Update Collection - -(def ^:private sql:rename-collection - "update color_collection - set name = $2 - where id = $1 - returning *") - -(s/def ::rename-color-collection +(s/def ::rename-color-library (s/keys :req-un [::profile-id ::name ::id])) -(sm/defmutation ::rename-color-collection +(sm/defmutation ::rename-color-library [{:keys [id profile-id name] :as params}] (db/with-atomic [conn db/pool] - (check-collection-edition-permissions! conn profile-id id) - (db/query-one conn [sql:rename-collection id name]))) + (p/let [lib (select-library-for-update conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) + (rename-library conn id name)))) + +(def ^:private sql:select-library-for-update + "select l.* + from color_library as l + where l.id = $1 + for update") + +(def ^:private sql:rename-library + "update color_library + set name = $2 + where id = $1") + +(defn- select-library-for-update + [conn id] + (-> (db/query-one conn [sql:select-library-for-update id]) + (p/then' su/raise-not-found-if-nil))) + +(defn- rename-library + [conn id name] + (-> (db/query-one conn [sql:rename-library id name]) + (p/then' su/constantly-nil))) + ;; --- Copy Color @@ -112,34 +108,48 @@ ;; (p/then' su/raise-not-found-if-nil)))) ;; (s/def ::copy-color -;; (s/keys :req-un [:us/id ::collection-id ::profile-id])) +;; (s/keys :req-un [:us/id ::library-id ::profile-id])) ;; (sm/defmutation ::copy-color -;; [{:keys [profile-id id collection-id] :as params}] +;; [{:keys [profile-id id library-id] :as params}] ;; (db/with-atomic [conn db/pool] ;; (-> (retrieve-color conn {:profile-id profile-id :id id}) ;; (p/then (fn [color] ;; (let [color (-> (dissoc color :id) -;; (assoc :collection-id collection-id))] +;; (assoc :library-id library-id))] ;; (create-color conn color))))))) -;; --- Delete Collection -(def ^:private sql:mark-collection-deleted - "update color_collection - set deleted_at = clock_timestamp() - where id = $1 - returning id") -(s/def ::delete-color-collection +;; --- Delete Library + +(declare delete-library) + +(s/def ::delete-color-library (s/keys :req-un [::profile-id ::id])) -(sm/defmutation ::delete-color-collection - [{:keys [profile-id id] :as params}] +(sm/defmutation ::delete-color-library + [{:keys [id profile-id] :as params}] (db/with-atomic [conn db/pool] - (check-collection-edition-permissions! conn profile-id id) - (-> (db/query-one conn [sql:mark-collection-deleted id]) - (p/then' su/constantly-nil)))) + (p/let [lib (select-library-for-update conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) + + ;; Schedule object deletion + (tasks/schedule! conn {:name "delete-object" + :delay cfg/default-deletion-delay + :props {:id id :type :color-library}}) + + (delete-library conn id)))) + +(def ^:private sql:mark-library-deleted + "update color_library + set deleted_at = clock_timestamp() + where id = $1") + +(defn- delete-library + [conn id] + (-> (db/query-one conn [sql:mark-library-deleted id]) + (p/then' su/constantly-nil))) @@ -148,72 +158,93 @@ (declare create-color) (s/def ::create-color - (s/keys :req-un [::profile-id ::name ::content ::collection-id] + (s/keys :req-un [::profile-id ::name ::content ::library-id] :opt-un [::id])) (sm/defmutation ::create-color - [{:keys [profile-id collection-id] :as params}] + [{:keys [profile-id library-id] :as params}] (db/with-atomic [conn db/pool] - (check-collection-edition-permissions! conn profile-id collection-id) - (create-color conn params))) + (p/let [lib (select-library-for-update conn library-id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) + (create-color conn params)))) (def ^:private sql:create-color - "insert into color (id, profile_id, name, collection_id, content) - values ($1, $2, $3, $4, $5) returning *") + "insert into color (id, name, library_id, content) + values ($1, $2, $3, $4) returning *") (defn create-color - [conn {:keys [id profile-id name collection-id content]}] + [conn {:keys [id name library-id content]}] (let [id (or id (uuid/next))] - (-> (db/query-one conn [sql:create-color id profile-id name collection-id content]) - (p/then' decode-row)))) + (db/query-one conn [sql:create-color id name library-id content]))) -;; --- Mutation: Update Color +;; --- Mutation: Rename Color -(def ^:private sql:update-color - "update color - set name = $3, - collection_id = $4 - where id = $1 - and profile_id = $2 - returning *") +(declare select-color-for-update) +(declare rename-color) -(s/def ::update-color - (s/keys :req-un [::id ::profile-id ::name ::collection-id])) +(s/def ::rename-color + (s/keys :req-un [::id ::profile-id ::name])) -(sm/defmutation ::update-color - [{:keys [id name profile-id collection-id] :as params}] +(sm/defmutation ::rename-color + [{:keys [id profile-id name] :as params}] (db/with-atomic [conn db/pool] - (check-collection-edition-permissions! conn profile-id collection-id) - (-> (db/query-one db/pool [sql:update-color id profile-id name collection-id]) - (p/then' su/raise-not-found-if-nil)))) + (p/let [clr (select-color-for-update conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id clr)) + (rename-color conn id name)))) + +(def ^:private sql:select-color-for-update + "select c.*, + lib.team_id as team_id + from color as c + inner join color_library as lib on (lib.id = c.library_id) + where c.id = $1 + for update of c") + +(def ^:private sql:rename-color + "update color + set name = $2 + where id = $1") + +(defn- select-color-for-update + [conn id] + (-> (db/query-one conn [sql:select-color-for-update id]) + (p/then' su/raise-not-found-if-nil))) + +(defn- rename-color + [conn id name] + (-> (db/query-one conn [sql:rename-color id name]) + (p/then' su/constantly-nil))) -;; --- Mutation: Delete Color +;; --- Delete Color + +(declare delete-color) + +(s/def ::delete-color + (s/keys :req-un [::id ::profile-id])) + +(sm/defmutation ::delete-color + [{:keys [profile-id id] :as params}] + (db/with-atomic [conn db/pool] + (p/let [clr (select-color-for-update conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id clr)) + + ;; Schedule object deletion + (tasks/schedule! conn {:name "delete-object" + :delay cfg/default-deletion-delay + :props {:id id :type :color}}) + + (delete-color conn id)))) (def ^:private sql:mark-color-deleted "update color set deleted_at = clock_timestamp() - where id = $1 - and profile_id = $2 - returning id") - -(s/def ::delete-color - (s/keys :req-un [::profile-id ::id])) - -(sm/defmutation ::delete-color - [{:keys [id profile-id] :as params}] - (db/with-atomic [conn db/pool] - (-> (db/query-one conn [sql:mark-color-deleted id profile-id]) - (p/then' su/raise-not-found-if-nil)) - - ;; Schedule object deletion - (tasks/schedule! conn {:name "delete-object" - :delay cfg/default-deletion-delay - :props {:id id :type :color}}) - - nil)) - + where id = $1") +(defn- delete-color + [conn id] + (-> (db/query-one conn [sql:mark-color-deleted id]) + (p/then' su/constantly-nil))) diff --git a/backend/src/uxbox/services/mutations/icons.clj b/backend/src/uxbox/services/mutations/icons.clj index c0f30249a..80b73d458 100644 --- a/backend/src/uxbox/services/mutations/icons.clj +++ b/backend/src/uxbox/services/mutations/icons.clj @@ -5,39 +5,32 @@ ;; This Source Code Form is "Incompatible With Secondary Licenses", as ;; defined by the Mozilla Public License, v. 2.0. ;; -;; Copyright (c) 2019 Andrey Antukh +;; Copyright (c) 2019-2020 Andrey Antukh (ns uxbox.services.mutations.icons (:require [clojure.spec.alpha :as s] - [datoteka.core :as fs] - [datoteka.storages :as ds] [promesa.core :as p] - [promesa.exec :as px] - [uxbox.common.exceptions :as ex] [uxbox.common.spec :as us] [uxbox.config :as cfg] [uxbox.db :as db] - [uxbox.media :as media] - [uxbox.images :as images] - [uxbox.tasks :as tasks] - [uxbox.services.queries.icons :refer [decode-row]] [uxbox.services.mutations :as sm] + [uxbox.services.queries.icons :refer [decode-row]] + [uxbox.services.queries.teams :as teams] [uxbox.services.util :as su] + [uxbox.tasks :as tasks] [uxbox.util.blob :as blob] - [uxbox.util.data :as data] - [uxbox.util.uuid :as uuid] - [uxbox.util.storage :as ust] - [vertx.util :as vu])) + [uxbox.util.uuid :as uuid])) ;; --- Helpers & Specs +(s/def ::height ::us/integer) (s/def ::id ::us/uuid) +(s/def ::library-id ::us/uuid) (s/def ::name ::us/string) (s/def ::profile-id ::us/uuid) -(s/def ::collection-id ::us/uuid) +(s/def ::team-id ::us/uuid) (s/def ::width ::us/integer) -(s/def ::height ::us/integer) (s/def ::view-box (s/and (s/coll-of number?) @@ -52,65 +45,67 @@ -;; --- Mutation: Create Collection +;; --- Mutation: Create Library -(declare create-icon-collection) +(declare create-library) -(s/def ::create-icon-collection - (s/keys :req-un [::profile-id ::name] +(s/def ::create-icon-library + (s/keys :req-un [::profile-id ::team-id ::name] :opt-un [::id])) -(sm/defmutation ::create-icon-collection - [{:keys [id profile-id name] :as params}] +(sm/defmutation ::create-icon-library + [{:keys [profile-id team-id id name] :as params}] (db/with-atomic [conn db/pool] - (create-icon-collection conn params))) + (teams/check-edition-permissions! conn profile-id team-id) + (create-library conn params))) -(def ^:private sql:create-icon-collection - "insert into icon_collection (id, profile_id, name) +(def ^:private sql:create-library + "insert into icon_library (id, team_id, name) values ($1, $2, $3) returning *;") -(defn- create-icon-collection - [conn {:keys [id profile-id name] :as params}] +(defn- create-library + [conn {:keys [team-id id name] :as params}] (let [id (or id (uuid/next))] - (db/query-one conn [sql:create-icon-collection id profile-id name]))) + (db/query-one conn [sql:create-library id team-id name]))) -;; --- Collection Permissions Check +;; --- Mutation: Rename Library -(def ^:private sql:select-collection - "select id, profile_id - from icon_collection - where id=$1 and deleted_at is null - for update") +(declare select-library-for-update) +(declare rename-library) -(defn- check-collection-edition-permissions! - [conn profile-id coll-id] - (p/let [coll (-> (db/query-one conn [sql:select-collection coll-id]) - (p/then' su/raise-not-found-if-nil))] - (when (not= (:profile-id coll) profile-id) - (ex/raise :type :validation - :code :not-authorized)))) - - - -;; --- Mutation: Update Collection - -(def ^:private sql:rename-collection - "update icon_collection - set name = $2 - where id = $1 - returning *") - -(s/def ::rename-icon-collection +(s/def ::rename-icon-library (s/keys :req-un [::profile-id ::name ::id])) -(sm/defmutation ::rename-icon-collection +(sm/defmutation ::rename-icon-library [{:keys [id profile-id name] :as params}] (db/with-atomic [conn db/pool] - (check-collection-edition-permissions! conn profile-id id) - (db/query-one conn [sql:rename-collection id name]))) + (p/let [lib (select-library-for-update conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) + (rename-library conn id name)))) + +(def ^:private sql:select-library-for-update + "select l.* + from icon_library as l + where l.id = $1 + for update") + +(def ^:private sql:rename-library + "update icon_library + set name = $2 + where id = $1") + +(defn- select-library-for-update + [conn id] + (-> (db/query-one conn [sql:select-library-for-update id]) + (p/then' su/raise-not-found-if-nil))) + +(defn- rename-library + [conn id name] + (-> (db/query-one conn [sql:rename-library id name]) + (p/then' su/constantly-nil))) @@ -129,34 +124,48 @@ ;; (p/then' su/raise-not-found-if-nil)))) ;; (s/def ::copy-icon -;; (s/keys :req-un [:us/id ::collection-id ::profile-id])) +;; (s/keys :req-un [:us/id ::library-id ::profile-id])) ;; (sm/defmutation ::copy-icon -;; [{:keys [profile-id id collection-id] :as params}] +;; [{:keys [profile-id id library-id] :as params}] ;; (db/with-atomic [conn db/pool] ;; (-> (retrieve-icon conn {:profile-id profile-id :id id}) ;; (p/then (fn [icon] ;; (let [icon (-> (dissoc icon :id) -;; (assoc :collection-id collection-id))] +;; (assoc :library-id library-id))] ;; (create-icon conn icon))))))) -;; --- Delete Collection -(def ^:private sql:mark-collection-deleted - "update icon_collection +;; --- Mutation: Delete Library + +(declare delete-library) + +(s/def ::delete-icon-library + (s/keys :req-un [::profile-id ::id])) + +(sm/defmutation ::delete-icon-library + [{:keys [profile-id id] :as params}] + (db/with-atomic [conn db/pool] + (p/let [lib (select-library-for-update conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) + + ;; Schedule object deletion + (tasks/schedule! conn {:name "delete-object" + :delay cfg/default-deletion-delay + :props {:id id :type :icon-library}}) + + (delete-library conn id)))) + +(def ^:private sql:mark-library-deleted + "update icon_library set deleted_at = clock_timestamp() where id = $1 returning id") -(s/def ::delete-icon-collection - (s/keys :req-un [::profile-id ::id])) - -(sm/defmutation ::delete-icon-collection - [{:keys [profile-id id] :as params}] - (db/with-atomic [conn db/pool] - (check-collection-edition-permissions! conn profile-id id) - (-> (db/query-one conn [sql:mark-collection-deleted id]) - (p/then' su/constantly-nil)))) +(defn- delete-library + [conn id] + (-> (db/query-one conn [sql:mark-library-deleted id]) + (p/then' su/constantly-nil))) @@ -165,58 +174,72 @@ (declare create-icon) (s/def ::create-icon - (s/keys :req-un [::profile-id ::name ::metadata ::content ::collection-id] + (s/keys :req-un [::profile-id ::name ::metadata ::content ::library-id] :opt-un [::id])) (sm/defmutation ::create-icon - [{:keys [profile-id collection-id] :as params}] + [{:keys [profile-id library-id] :as params}] (db/with-atomic [conn db/pool] - (check-collection-edition-permissions! conn profile-id collection-id) - (create-icon conn params))) + (p/let [lib (select-library-for-update conn library-id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) + (create-icon conn params)))) (def ^:private sql:create-icon - "insert into icon (id, profile_id, name, collection_id, content, metadata) - values ($1, $2, $3, $4, $5, $6) returning *") + "insert into icon (id, name, library_id, content, metadata) + values ($1, $2, $3, $4, $5) returning *") (defn create-icon - [conn {:keys [id profile-id name collection-id metadata content]}] + [conn {:keys [id name library-id metadata content]}] (let [id (or id (uuid/next))] - (-> (db/query-one conn [sql:create-icon id profile-id name - collection-id content (blob/encode metadata)]) + (-> (db/query-one conn [sql:create-icon id name library-id + content (blob/encode metadata)]) (p/then' decode-row)))) -;; --- Mutation: Update Icon +;; --- Mutation: Rename Icon -(def ^:private sql:update-icon - "update icon - set name = $3, - collection_id = $4 - where id = $1 - and profile_id = $2 - returning *") +(declare select-icon-for-update) +(declare rename-icon) -(s/def ::update-icon - (s/keys :req-un [::id ::profile-id ::name ::collection-id])) +(s/def ::rename-icon + (s/keys :req-un [::id ::profile-id ::name])) -(sm/defmutation ::update-icon - [{:keys [id name profile-id collection-id] :as params}] +(sm/defmutation ::rename-icon + [{:keys [id profile-id name] :as params}] (db/with-atomic [conn db/pool] - (check-collection-edition-permissions! conn profile-id collection-id) - (-> (db/query-one db/pool [sql:update-icon id profile-id name collection-id]) - (p/then' su/raise-not-found-if-nil)))) + (p/let [clr (select-icon-for-update conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id clr)) + (rename-icon conn id name)))) + +(def ^:private sql:select-icon-for-update + "select i.*, + lib.team_id as team_id + from icon as i + inner join icon_library as lib on (lib.id = i.library_id) + where i.id = $1 + for update of i") + +(def ^:private sql:rename-icon + "update icon + set name = $2 + where id = $1") + +(defn- select-icon-for-update + [conn id] + (-> (db/query-one conn [sql:select-icon-for-update id]) + (p/then' su/raise-not-found-if-nil))) + +(defn- rename-icon + [conn id name] + (-> (db/query-one conn [sql:rename-icon id name]) + (p/then' su/constantly-nil))) ;; --- Mutation: Delete Icon -(def ^:private sql:mark-icon-deleted - "update icon - set deleted_at = clock_timestamp() - where id = $1 - and profile_id = $2 - returning id") +(declare delete-icon) (s/def ::delete-icon (s/keys :req-un [::profile-id ::id])) @@ -224,14 +247,22 @@ (sm/defmutation ::delete-icon [{:keys [id profile-id] :as params}] (db/with-atomic [conn db/pool] - (-> (db/query-one conn [sql:mark-icon-deleted id profile-id]) - (p/then' su/raise-not-found-if-nil)) + (p/let [icn (select-icon-for-update conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id icn)) - ;; Schedule object deletion - (tasks/schedule! conn {:name "delete-object" - :delay cfg/default-deletion-delay - :props {:id id :type :icon}}) + ;; Schedule object deletion + (tasks/schedule! conn {:name "delete-object" + :delay cfg/default-deletion-delay + :props {:id id :type :icon}}) - nil)) + (delete-icon conn id)))) +(def ^:private sql:mark-icon-deleted + "update icon + set deleted_at = clock_timestamp() + where id = $1") +(defn- delete-icon + [conn id] + (-> (db/query-one conn [sql:mark-icon-deleted id]) + (p/then' su/constantly-nil))) diff --git a/backend/src/uxbox/services/mutations/images.clj b/backend/src/uxbox/services/mutations/images.clj index 839cfa432..f317187bd 100644 --- a/backend/src/uxbox/services/mutations/images.clj +++ b/backend/src/uxbox/services/mutations/images.clj @@ -5,15 +5,13 @@ ;; This Source Code Form is "Incompatible With Secondary Licenses", as ;; defined by the Mozilla Public License, v. 2.0. ;; -;; Copyright (c) 2019 Andrey Antukh +;; Copyright (c) 2019-2020 Andrey Antukh (ns uxbox.services.mutations.images (:require [clojure.spec.alpha :as s] [datoteka.core :as fs] - [datoteka.storages :as ds] [promesa.core :as p] - [promesa.exec :as px] [uxbox.common.exceptions :as ex] [uxbox.common.spec :as us] [uxbox.config :as cfg] @@ -21,10 +19,9 @@ [uxbox.media :as media] [uxbox.images :as images] [uxbox.tasks :as tasks] + [uxbox.services.queries.teams :as teams] [uxbox.services.mutations :as sm] [uxbox.services.util :as su] - [uxbox.util.blob :as blob] - [uxbox.util.data :as data] [uxbox.util.uuid :as uuid] [uxbox.util.storage :as ust] [vertx.util :as vu])) @@ -32,102 +29,108 @@ (def thumbnail-options {:width 800 :height 800 - :quality 80 + :quality 85 :format "webp"}) (s/def ::id ::us/uuid) (s/def ::name ::us/string) (s/def ::profile-id ::us/uuid) -(s/def ::collection-id ::us/uuid) +(s/def ::library-id ::us/uuid) +(s/def ::team-id ::us/uuid) +;; --- Create Library -;; --- Create Collection +(declare create-library) -(declare create-image-collection) - -(s/def ::create-image-collection - (s/keys :req-un [::profile-id ::name] +(s/def ::create-image-library + (s/keys :req-un [::profile-id ::team-id ::name] :opt-un [::id])) -(sm/defmutation ::create-image-collection - [{:keys [id profile-id name] :as params}] +(sm/defmutation ::create-image-library + [{:keys [profile-id team-id] :as params}] (db/with-atomic [conn db/pool] - (create-image-collection conn params))) + (teams/check-edition-permissions! conn profile-id team-id) + (create-library conn params))) -(def ^:private sql:create-image-collection - "insert into image_collection (id, profile_id, name) +(def ^:private sql:create-library + "insert into image_library (id, team_id, name) values ($1, $2, $3) returning *;") -(defn- create-image-collection - [conn {:keys [id profile-id name] :as params}] +(defn- create-library + [conn {:keys [id team-id name]}] (let [id (or id (uuid/next))] - (db/query-one conn [sql:create-image-collection id profile-id name]))) + (db/query-one conn [sql:create-library id team-id name]))) +;; --- Rename Library -;; --- Collection Permissions Check +(declare select-library-for-update) +(declare rename-library) -(def ^:private sql:select-collection - "select id, profile_id - from image_collection - where id=$1 and deleted_at is null +(s/def ::rename-image-library + (s/keys :req-un [::id ::profile-id ::name])) + +(sm/defmutation ::rename-image-library + [{:keys [profile-id id name] :as params}] + (db/with-atomic [conn db/pool] + (p/let [lib (select-library-for-update conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) + (rename-library conn id name)))) + +(def ^:private sql:select-library-for-update + "select l.* + from image_library as l + where l.id = $1 for update") -(defn- check-collection-edition-permissions! - [conn profile-id coll-id] - (p/let [coll (-> (db/query-one conn [sql:select-collection coll-id]) - (p/then' su/raise-not-found-if-nil))] - (when (not= (:profile-id coll) profile-id) - (ex/raise :type :validation - :code :not-authorized)))) - - - -;; --- Rename Collection - -(def ^:private sql:rename-image-collection - "update image_collection +(def ^:private sql:rename-library + "update image_library set name = $2 - where id = $1 - returning *;") + where id = $1") -(s/def ::rename-image-collection - (s/keys :req-un [::id ::profile-id ::us/name])) +(defn- select-library-for-update + [conn id] + (-> (db/query-one conn [sql:select-library-for-update id]) + (p/then' su/raise-not-found-if-nil))) -(sm/defmutation ::rename-image-collection - [{:keys [id profile-id name] :as params}] - (db/with-atomic [conn db/pool] - (check-collection-edition-permissions! conn profile-id id) - (db/query-one conn [sql:rename-image-collection id name]))) +(defn- rename-library + [conn id name] + (-> (db/query-one conn [sql:rename-library id name]) + (p/then' su/constantly-nil))) -;; --- Delete Collection +;; --- Delete Library -(s/def ::delete-image-collection +(declare delete-library) + +(s/def ::delete-image-library (s/keys :req-un [::profile-id ::id])) -(def ^:private sql:mark-image-collection-as-deleted - "update image_collection - set deleted_at = clock_timestamp() - where id = $1 - returning id") - -(sm/defmutation ::delete-image-collection +(sm/defmutation ::delete-image-library [{:keys [id profile-id] :as params}] (db/with-atomic [conn db/pool] - (check-collection-edition-permissions! conn profile-id id) + (p/let [lib (select-library-for-update conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) - ;; Schedule object deletion - (tasks/schedule! conn {:name "delete-object" - :delay cfg/default-deletion-delay - :props {:id id :type :image-collection}}) + ;; Schedule object deletion + (tasks/schedule! conn {:name "delete-object" + :delay cfg/default-deletion-delay + :props {:id id :type :image-library}}) - (-> (db/query-one conn [sql:mark-image-collection-as-deleted id]) - (p/then' su/raise-not-found-if-nil) - (p/then' su/constantly-nil)))) + (delete-library conn id)))) + +(def ^:private sql:mark-library-deleted + "update image_library + set deleted_at = clock_timestamp() + where id = $1") + +(defn- delete-library + [conn id] + (-> (db/query-one conn [sql:mark-library-deleted id]) + (p/then' su/constantly-nil))) @@ -154,24 +157,25 @@ (s/def ::content ::upload) (s/def ::upload-image - (s/keys :req-un [::profile-id ::name ::content ::collection-id] + (s/keys :req-un [::profile-id ::name ::content ::library-id] :opt-un [::id])) (sm/defmutation ::upload-image - [{:keys [collection-id profile-id] :as params}] + [{:keys [library-id profile-id] :as params}] (db/with-atomic [conn db/pool] - (check-collection-edition-permissions! conn profile-id collection-id) - (create-image conn params))) + (p/let [lib (select-library-for-update conn library-id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) + (create-image conn params)))) (def ^:private sql:insert-image "insert into image - (id, collection_id, profile_id, name, path, width, height, mtype, + (id, library_id, name, path, width, height, mtype, thumb_path, thumb_width, thumb_height, thumb_quality, thumb_mtype) - values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) + values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) returning *") (defn create-image - [conn {:keys [id content collection-id profile-id name] :as params}] + [conn {:keys [id content library-id name]}] (when-not (valid-image-types? (:mtype content)) (ex/raise :type :validation :code :image-type-not-allowed @@ -184,8 +188,7 @@ sqlv [sql:insert-image id - collection-id - profile-id + library-id name (str image-path) (:width image-opts) @@ -202,7 +205,7 @@ (p/then' #(images/resolve-urls % :thumb-path :thumb-uri))))) (defn persist-image-on-fs - [{:keys [name path] :as upload}] + [{:keys [name path]}] (vu/blocking (let [filename (fs/name name)] (ust/save! media/media-storage filename path)))) @@ -212,48 +215,68 @@ (vu/blocking (let [input-path (ust/lookup media/media-storage input-path) thumb-data (images/generate-thumbnail input-path thumb-opts) - [filename ext] (fs/split-ext (fs/name input-path)) + [filename _] (fs/split-ext (fs/name input-path)) thumb-name (->> (images/format->extension (:format thumb-opts)) (str "thumbnail-" filename))] (ust/save! media/media-storage thumb-name thumb-data)))) -;; --- Update Image +;; --- Mutation: Rename Image -(s/def ::update-image - (s/keys :req-un [::id ::profile-id ::name ::collection-id])) +(declare select-image-for-update) +(declare rename-image) -(def ^:private sql:update-image +(s/def ::rename-image + (s/keys :req-un [::id ::profile-id ::name])) + +(sm/defmutation ::rename-image + [{:keys [id profile-id name] :as params}] + (db/with-atomic [conn db/pool] + (p/let [img (select-image-for-update conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id img)) + (rename-image conn id name)))) + +(def ^:private sql:select-image-for-update + "select img.*, + lib.team_id as team_id + from image as img + inner join image_library as lib on (lib.id = img.library_id) + where img.id = $1 + for update of img") + +(def ^:private sql:rename-image "update image - set name = $3, - collection_id = $2 - where id = $1 - and profile_id = $4 - returning *;") + set name = $2 + where id = $1") -(sm/defmutation ::update-image - [{:keys [id name profile-id collection-id] :as params}] - (-> (db/query-one db/pool [sql:update-image id - collection-id name profile-id]) +(defn- select-image-for-update + [conn id] + (-> (db/query-one conn [sql:select-image-for-update id]) (p/then' su/raise-not-found-if-nil))) +(defn- rename-image + [conn id name] + (-> (db/query-one conn [sql:rename-image id name]) + (p/then' su/constantly-nil))) + + ;; --- Copy Image ;; (declare retrieve-image) ;; (s/def ::copy-image -;; (s/keys :req-un [::id ::collection-id ::profile-id])) +;; (s/keys :req-un [::id ::library-id ::profile-id])) ;; (sm/defmutation ::copy-image -;; [{:keys [profile-id id collection-id] :as params}] +;; [{:keys [profile-id id library-id] :as params}] ;; (letfn [(copy-image [conn {:keys [path] :as image}] ;; (-> (ds/lookup media/images-storage (:path image)) ;; (p/then (fn [path] (ds/save media/images-storage (fs/name path) path))) ;; (p/then (fn [path] ;; (-> image -;; (assoc :path (str path) :collection-id collection-id) +;; (assoc :path (str path) :library-id library-id) ;; (dissoc :id)))) ;; (p/then (partial store-image-in-db conn))))] @@ -262,14 +285,10 @@ ;; (p/then su/raise-not-found-if-nil) ;; (p/then (partial copy-image conn)))))) + ;; --- Delete Image -(def ^:private sql:mark-image-deleted - "update image - set deleted_at = clock_timestamp() - where id = $1 - and profile_id = $2 - returning id") +(declare delete-image) (s/def ::delete-image (s/keys :req-un [::id ::profile-id])) @@ -277,14 +296,22 @@ (sm/defmutation ::delete-image [{:keys [profile-id id] :as params}] (db/with-atomic [conn db/pool] - (-> (db/query-one conn [sql:mark-image-deleted id profile-id]) - (p/then' su/raise-not-found-if-nil)) + (p/let [img (select-image-for-update conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id img)) - ;; Schedule object deletion - (tasks/schedule! conn {:name "delete-object" - :delay cfg/default-deletion-delay - :props {:id id :type :image}}) + ;; Schedule object deletion + (tasks/schedule! conn {:name "delete-object" + :delay cfg/default-deletion-delay + :props {:id id :type :image}}) - nil)) + (delete-image conn id)))) +(def ^:private sql:mark-image-deleted + "update image + set deleted_at = clock_timestamp() + where id = $1") +(defn- delete-image + [conn id] + (-> (db/query-one conn [sql:mark-image-deleted id]) + (p/then' su/constantly-nil))) diff --git a/backend/src/uxbox/services/mutations/teams.clj b/backend/src/uxbox/services/mutations/teams.clj index 36e69a915..0c88ca28a 100644 --- a/backend/src/uxbox/services/mutations/teams.clj +++ b/backend/src/uxbox/services/mutations/teams.clj @@ -46,20 +46,43 @@ values ($1, $2, '', $3) returning *") +(def ^:private sql:create-team-profile + "insert into team_profile_rel (team_id, profile_id, is_owner, is_admin, can_edit) + values ($1, $2, true, true, true) + returning *") + (defn create-team [conn {:keys [id profile-id name default?] :as params}] (let [id (or id (uuid/next)) default? (if (boolean? default?) default? false)] (db/query-one conn [sql:insert-team id name default?]))) -(def ^:private sql:create-team-profile - "insert into team_profile_rel (team_id, profile_id, is_owner, is_admin, can_edit) - values ($1, $2, true, true, true) - returning *") - (defn create-team-profile [conn {:keys [team-id profile-id] :as params}] (-> (db/query-one conn [sql:create-team-profile team-id profile-id]) (p/then' su/constantly-nil))) + +;; --- Mutation: Team Edition Permissions + +(def ^:private sql:team-permissions + "select tpr.is_owner, + tpr.is_admin, + tpr.can_edit + from team_profile_rel as tpr + where tpr.profile_id = $1 + and tpr.team_id = $2") + +(defn check-edition-permissions! + [conn profile-id team-id] + (-> (db/query-one conn [sql:team-permissions profile-id team-id]) + (p/then' (fn [row] + (when-not (or (:can-edit row) + (:is-admin row) + (:is-owner row)) + (ex/raise :type :validation + :code :not-authorized)))))) + + + diff --git a/backend/src/uxbox/services/queries/colors.clj b/backend/src/uxbox/services/queries/colors.clj index e1b9640e8..b1deb3dfb 100644 --- a/backend/src/uxbox/services/queries/colors.clj +++ b/backend/src/uxbox/services/queries/colors.clj @@ -17,6 +17,7 @@ [uxbox.db :as db] [uxbox.media :as media] [uxbox.images :as images] + [uxbox.services.queries.teams :as teams] [uxbox.services.queries :as sq] [uxbox.services.util :as su] [uxbox.util.blob :as blob] @@ -28,55 +29,85 @@ (s/def ::id ::us/uuid) (s/def ::profile-id ::us/uuid) -(s/def ::collection-id (s/nilable ::us/uuid)) - -(defn decode-row - [{:keys [metadata] :as row}] - (when row - (cond-> row - metadata (assoc :metadata (blob/decode metadata))))) +(s/def ::team-id ::us/uuid) +(s/def ::library-id (s/nilable ::us/uuid)) -;; --- Query: Collections +;; --- Query: Colors Librarys -(def ^:private sql:collections - "select *, - (select count(*) from color where collection_id = ic.id) as num_colors - from color_collection as ic - where (ic.profile_id = $1 or - ic.profile_id = '00000000-0000-0000-0000-000000000000'::uuid) - and ic.deleted_at is null - order by ic.created_at desc") +(def ^:private sql:libraries + "select lib.*, + (select count(*) from color where library_id = lib.id) as num_colors + from color_library as lib + where lib.team_id = $1 + and lib.deleted_at is null + order by lib.created_at desc") -(s/def ::color-collections - (s/keys :req-un [::profile-id])) +(s/def ::color-libraries + (s/keys :req-un [::profile-id ::team-id])) -(sq/defquery ::color-collections - [{:keys [profile-id] :as params}] - (let [sqlv [sql:collections profile-id]] - (db/query db/pool sqlv))) +(sq/defquery ::color-libraries + [{:keys [profile-id team-id]}] + (db/with-atomic [conn db/pool] + (teams/check-edition-permissions! conn profile-id team-id) + (db/query conn [sql:libraries team-id]))) -;; --- Colors By Collection ID +;; --- Query: Color Library -(def ^:private sql:colors - "select * - from color as i - where (i.profile_id = $1 or - i.profile_id = '00000000-0000-0000-0000-000000000000'::uuid) - and i.deleted_at is null - and i.collection_id = $2 - order by i.created_at desc") +(declare retrieve-library) + +(s/def ::color-library + (s/keys :req-un [::profile-id ::id])) + +(sq/defquery ::color-library + [{:keys [profile-id id]}] + (db/with-atomic [conn db/pool] + (p/let [lib (retrieve-library conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) + lib))) + +(def ^:private sql:single-library + "select lib.*, + (select count(*) from color where library_id = lib.id) as num_colors + from color_library as lib + where lib.deleted_at is null + and lib.id = $1") + +(defn- retrieve-library + [conn id] + (-> (db/query-one conn [sql:single-library id]) + (p/then' su/raise-not-found-if-nil))) + + + +;; --- Query: Colors (by library) + +(declare retrieve-colors) (s/def ::colors - (s/keys :req-un [::profile-id ::collection-id])) + (s/keys :req-un [::profile-id ::library-id])) (sq/defquery ::colors - [{:keys [profile-id collection-id] :as params}] - (-> (db/query db/pool [sql:colors profile-id collection-id]) - (p/then' #(mapv decode-row %)))) + [{:keys [profile-id library-id] :as params}] + (db/with-atomic [conn db/pool] + (p/let [lib (retrieve-library conn library-id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) + (retrieve-colors conn library-id)))) + +(def ^:private sql:colors + "select color.* + from color as color + inner join color_library as lib on (lib.id = color.library_id) + where color.deleted_at is null + and color.library_id = $1 + order by created_at desc") + +(defn- retrieve-colors + [conn library-id] + (db/query conn [sql:colors library-id])) @@ -89,14 +120,22 @@ (s/keys :req-un [::profile-id ::id])) (sq/defquery ::color - [{:keys [id] :as params}] - (-> (retrieve-color db/pool id) - (p/then' su/raise-not-found-if-nil))) + [{:keys [profile-id id] :as params}] + (db/with-atomic [conn db/pool] + (p/let [color (retrieve-color conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id color)) + color))) + +(def ^:private sql:single-color + "select color.*, + lib.team_id as team_id + from color as color + inner join color_library as lib on (lib.id = color.library_id) + where color.deleted_at is null + and color.id = $1 + order by created_at desc") (defn retrieve-color [conn id] - (let [sql "select * from color - where id = $1 - and deleted_at is null;"] - (-> (db/query-one conn [sql id]) - (p/then' su/raise-not-found-if-nil)))) + (-> (db/query-one conn [sql:single-color id]) + (p/then' su/raise-not-found-if-nil))) diff --git a/backend/src/uxbox/services/queries/icons.clj b/backend/src/uxbox/services/queries/icons.clj index 64e055804..08688a14c 100644 --- a/backend/src/uxbox/services/queries/icons.clj +++ b/backend/src/uxbox/services/queries/icons.clj @@ -17,6 +17,7 @@ [uxbox.db :as db] [uxbox.media :as media] [uxbox.images :as images] + [uxbox.services.queries.teams :as teams] [uxbox.services.queries :as sq] [uxbox.services.util :as su] [uxbox.util.blob :as blob] @@ -27,8 +28,9 @@ ;; --- Helpers & Specs (s/def ::id ::us/uuid) +(s/def ::name ::us/string) (s/def ::profile-id ::us/uuid) -(s/def ::collection-id (s/nilable ::us/uuid)) +(s/def ::library-id ::us/uuid) (defn decode-row [{:keys [metadata] :as row}] @@ -38,45 +40,82 @@ -;; --- Query: Collections +;; --- Query: Icons Librarys -(def ^:private sql:collections - "select *, - (select count(*) from icon where collection_id = ic.id) as num_icons - from icon_collection as ic - where (ic.profile_id = $1 or - ic.profile_id = '00000000-0000-0000-0000-000000000000'::uuid) - and ic.deleted_at is null - order by ic.created_at desc") +(def ^:private sql:libraries + "select lib.*, + (select count(*) from icon where library_id = lib.id) as num_icons + from icon_library as lib + where lib.team_id = $1 + and lib.deleted_at is null + order by lib.created_at desc") -(s/def ::icon-collections - (s/keys :req-un [::profile-id])) +(s/def ::icon-libraries + (s/keys :req-un [::profile-id ::team-id])) -(sq/defquery ::icon-collections - [{:keys [profile-id] :as params}] - (let [sqlv [sql:collections profile-id]] - (db/query db/pool sqlv))) +(sq/defquery ::icon-libraries + [{:keys [profile-id team-id]}] + (db/with-atomic [conn db/pool] + (teams/check-edition-permissions! conn profile-id team-id) + (db/query conn [sql:libraries team-id]))) -;; --- Icons By Collection ID +;; --- Query: Icon Library -(def ^:private sql:icons - "select * - from icon as i - where (i.profile_id = $1 or - i.profile_id = '00000000-0000-0000-0000-000000000000'::uuid) - and i.deleted_at is null - and i.collection_id = $2 - order by i.created_at desc") +(declare retrieve-library) + +(s/def ::icon-library + (s/keys :req-un [::profile-id ::id])) + +(sq/defquery ::icon-library + [{:keys [profile-id id]}] + (db/with-atomic [conn db/pool] + (p/let [lib (retrieve-library conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) + lib))) + +(def ^:private sql:single-library + "select lib.*, + (select count(*) from icon where library_id = lib.id) as num_icons + from icon_library as lib + where lib.deleted_at is null + and lib.id = $1") + +(defn- retrieve-library + [conn id] + (-> (db/query-one conn [sql:single-library id]) + (p/then' su/raise-not-found-if-nil))) + + + +;; --- Query: Icons (by library) + +(declare retrieve-icons) (s/def ::icons - (s/keys :req-un [::profile-id ::collection-id])) + (s/keys :req-un [::profile-id ::library-id])) (sq/defquery ::icons - [{:keys [profile-id collection-id] :as params}] - (-> (db/query db/pool [sql:icons profile-id collection-id]) - (p/then' #(mapv decode-row %)))) + [{:keys [profile-id library-id] :as params}] + (db/with-atomic [conn db/pool] + (p/let [lib (retrieve-library conn library-id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) + (-> (retrieve-icons conn library-id) + (p/then' (fn [rows] (mapv decode-row rows))))))) + +(def ^:private sql:icons + "select icon.* + from icon as icon + inner join icon_library as lib on (lib.id = icon.library_id) + where icon.deleted_at is null + and icon.library_id = $1 + order by created_at desc") + +(defn- retrieve-icons + [conn library-id] + (db/query conn [sql:icons library-id])) + ;; --- Query: Icon (by ID) @@ -88,15 +127,23 @@ (s/keys :req-un [::profile-id ::id])) (sq/defquery ::icon - [{:keys [id] :as params}] - (-> (retrieve-icon db/pool id) - (p/then' su/raise-not-found-if-nil))) + [{:keys [profile-id id] :as params}] + (db/with-atomic [conn db/pool] + (p/let [icon (retrieve-icon conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id icon)) + (decode-row icon)))) + +(def ^:private sql:single-icon + "select icon.*, + lib.team_id as team_id + from icon as icon + inner join icon_library as lib on (lib.id = icon.library_id) + where icon.deleted_at is null + and icon.id = $1 + order by created_at desc") (defn retrieve-icon [conn id] - (let [sql "select * from icon - where id = $1 - and deleted_at is null;"] - (-> (db/query-one conn [sql id]) - (p/then' su/raise-not-found-if-nil)))) + (-> (db/query-one conn [sql:single-icon id]) + (p/then' su/raise-not-found-if-nil))) diff --git a/backend/src/uxbox/services/queries/images.clj b/backend/src/uxbox/services/queries/images.clj index 60e08d452..1243bf8d0 100644 --- a/backend/src/uxbox/services/queries/images.clj +++ b/backend/src/uxbox/services/queries/images.clj @@ -5,47 +5,105 @@ ;; This Source Code Form is "Incompatible With Secondary Licenses", as ;; defined by the Mozilla Public License, v. 2.0. ;; -;; Copyright (c) 2019 Andrey Antukh +;; Copyright (c) 2019-2020 Andrey Antukh (ns uxbox.services.queries.images (:require [clojure.spec.alpha :as s] [promesa.core :as p] - [promesa.exec :as px] - [uxbox.common.exceptions :as ex] [uxbox.common.spec :as us] [uxbox.db :as db] - [uxbox.media :as media] [uxbox.images :as images] + [uxbox.services.queries.teams :as teams] [uxbox.services.queries :as sq] - [uxbox.services.util :as su] - [uxbox.util.blob :as blob] - [uxbox.util.data :as data] - [uxbox.util.uuid :as uuid] - [vertx.core :as vc])) + [uxbox.services.util :as su])) (s/def ::id ::us/uuid) (s/def ::name ::us/string) (s/def ::profile-id ::us/uuid) -(s/def ::collection-id (s/nilable ::us/uuid)) +(s/def ::library-id ::us/uuid) -;; --- Query: Image Collections +;; --- Query: Image Librarys -(def ^:private sql:collections - "select *, - (select count(*) from image where collection_id = ic.id) as num_images - from image_collection as ic - where (ic.profile_id = $1 or - ic.profile_id = '00000000-0000-0000-0000-000000000000'::uuid) - and ic.deleted_at is null - order by ic.created_at desc;") +(def ^:private sql:libraries + "select lib.*, + (select count(*) from image where library_id = lib.id) as num_images + from image_library as lib + where lib.team_id = $1 + and lib.deleted_at is null + order by lib.created_at desc") -(s/def ::image-collections - (s/keys :req-un [::profile-id])) +(s/def ::image-libraries + (s/keys :req-un [::profile-id ::team-id])) -(sq/defquery ::image-collections - [{:keys [profile-id] :as params}] - (db/query db/pool [sql:collections profile-id])) +(sq/defquery ::image-libraries + [{:keys [profile-id team-id]}] + (db/with-atomic [conn db/pool] + (teams/check-edition-permissions! conn profile-id team-id) + (db/query conn [sql:libraries team-id]))) + + +;; --- Query: Image Library + +(declare retrieve-library) + +(s/def ::image-library + (s/keys :req-un [::profile-id ::id])) + +(sq/defquery ::image-library + [{:keys [profile-id id]}] + (db/with-atomic [conn db/pool] + (p/let [lib (retrieve-library conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) + lib))) + +(def ^:private sql:single-library + "select lib.*, + (select count(*) from image where library_id = lib.id) as num_images + from image_library as lib + where lib.deleted_at is null + and lib.id = $1") + +(defn- retrieve-library + [conn id] + (-> (db/query-one conn [sql:single-library id]) + (p/then' su/raise-not-found-if-nil))) + + + +;; --- Query: Images (by library) + +(declare retrieve-images) + +(s/def ::images + (s/keys :req-un [::profile-id ::library-id])) + +;; TODO: check if we can resolve url with transducer for reduce +;; garbage generation for each request + +(sq/defquery ::images + [{:keys [profile-id library-id] :as params}] + (db/with-atomic [conn db/pool] + (p/let [lib (retrieve-library conn library-id)] + (teams/check-edition-permissions! conn profile-id (:team-id lib)) + (-> (retrieve-images conn library-id) + (p/then' (fn [rows] + (->> rows + (mapv #(images/resolve-urls % :path :uri)) + (mapv #(images/resolve-urls % :thumb-path :thumb-uri))))))))) + + +(def ^:private sql:images + "select img.* + from image as img + inner join image_library as lib on (lib.id = img.library_id) + where img.deleted_at is null + and img.library_id = $1 + order by created_at desc") + +(defn- retrieve-images + [conn library-id] + (db/query conn [sql:images library-id])) @@ -58,42 +116,27 @@ (s/keys :req-un [::profile-id ::id])) (sq/defquery ::image - [{:keys [id] :as params}] - (-> (retrieve-image db/pool id) - (p/then' #(images/resolve-urls % :path :uri)) - (p/then' #(images/resolve-urls % :thumb-path :thumb-uri)))) + [{:keys [profile-id id] :as params}] + (db/with-atomic [conn db/pool] + (p/let [img (retrieve-image conn id)] + (teams/check-edition-permissions! conn profile-id (:team-id img)) + (-> img + (images/resolve-urls :path :uri) + (images/resolve-urls :thumb-path :thumb-uri))))) + +(def ^:private sql:single-image + "select img.*, + lib.team_id as team_id + from image as img + inner join image_library as lib on (lib.id = img.library_id) + where img.deleted_at is null + and img.id = $1 + order by created_at desc") (defn retrieve-image [conn id] - (let [sql "select * from image - where id = $1 - and deleted_at is null;"] - (-> (db/query-one conn [sql id]) - (p/then' su/raise-not-found-if-nil)))) + (-> (db/query-one conn [sql:single-image id]) + (p/then' su/raise-not-found-if-nil))) -;; --- Query: Images (by collection) - -(def ^:private sql:images - "select * - from image - where (profile_id = $1 or - profile_id = '00000000-0000-0000-0000-000000000000'::uuid) - and deleted_at is null - and collection_id = $2 - order by created_at desc") - -(s/def ::images - (s/keys :req-un [::profile-id ::collection-id])) - -;; TODO: check if we can resolve url with transducer for reduce -;; garbage generation for each request - -(sq/defquery ::images - [{:keys [profile-id collection-id] :as params}] - (-> (db/query db/pool [sql:images profile-id collection-id]) - (p/then' (fn [rows] - (->> rows - (mapv #(images/resolve-urls % :path :uri)) - (mapv #(images/resolve-urls % :thumb-path :thumb-uri))))))) diff --git a/backend/src/uxbox/services/queries/teams.clj b/backend/src/uxbox/services/queries/teams.clj new file mode 100644 index 000000000..efce8203a --- /dev/null +++ b/backend/src/uxbox/services/queries/teams.clj @@ -0,0 +1,44 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 Andrey Antukh + +(ns uxbox.services.queries.teams + (:require + [clojure.spec.alpha :as s] + [promesa.core :as p] + [uxbox.db :as db] + [uxbox.common.exceptions :as ex] + [uxbox.common.spec :as us] + [uxbox.services.queries :as sq] + [uxbox.services.util :as su] + [uxbox.util.blob :as blob] + [uxbox.util.uuid :as uuid])) + + +;; --- Team Edition Permissions + +(def ^:private sql:team-permissions + "select tpr.is_owner, + tpr.is_admin, + tpr.can_edit + from team_profile_rel as tpr + where tpr.profile_id = $1 + and tpr.team_id = $2") + +(defn check-edition-permissions! + [conn profile-id team-id] + (-> (db/query-one conn [sql:team-permissions profile-id team-id]) + (p/then' (fn [row] + (when-not (or (:can-edit row) + (:is-admin row) + (:is-owner row)) + (ex/raise :type :validation + :code :not-authorized)))))) + + + diff --git a/backend/tests/uxbox/tests/helpers.clj b/backend/tests/uxbox/tests/helpers.clj index cbf238e44..9447e5386 100644 --- a/backend/tests/uxbox/tests/helpers.clj +++ b/backend/tests/uxbox/tests/helpers.clj @@ -111,22 +111,22 @@ :shapes-by-id {}}})) -(defn create-image-collection - [conn profile-id i] - (#'images/create-image-collection conn {:id (mk-uuid "imgcoll" i) - :profile-id profile-id - :name (str "image collection " i)})) +(defn create-image-library + [conn team-id i] + (#'images/create-library conn {:id (mk-uuid "imgcoll" i) + :team-id team-id + :name (str "image library " i)})) -(defn create-icon-collection - [conn profile-id i] - (#'icons/create-icon-collection conn {:id (mk-uuid "imgcoll" i) - :profile-id profile-id - :name (str "icon collection " i)})) -(defn create-color-collection - [conn profile-id i] - (#'colors/create-color-collection conn {:id (mk-uuid "imgcoll" i) - :profile-id profile-id - :name (str "color collection " i)})) +(defn create-icon-library + [conn team-id i] + (#'icons/create-library conn {:id (mk-uuid "imgcoll" i) + :team-id team-id + :name (str "icon library " i)})) +(defn create-color-library + [conn team-id i] + (#'colors/create-library conn {:id (mk-uuid "imgcoll" i) + :team-id team-id + :name (str "color library " i)})) (defn handle-error [^Throwable err] diff --git a/backend/tests/uxbox/tests/test_services_colors.clj b/backend/tests/uxbox/tests/test_services_colors.clj index bdfbb47fa..fabb421be 100644 --- a/backend/tests/uxbox/tests/test_services_colors.clj +++ b/backend/tests/uxbox/tests/test_services_colors.clj @@ -16,14 +16,16 @@ (t/use-fixtures :once th/state-init) (t/use-fixtures :each th/database-reset) -(t/deftest color-collections-crud - (let [id (uuid/next) - profile @(th/create-profile db/pool 2)] +(t/deftest color-libraries-crud + (let [id (uuid/next) + prof @(th/create-profile db/pool 2) + team (:default-team prof)] - (t/testing "create collection" - (let [data {::sm/type :create-color-collection - :name "sample collection" - :profile-id (:id profile) + (t/testing "create library" + (let [data {::sm/type :create-color-library + :name "sample library" + :profile-id (:id prof) + :team-id (:id team) :id id} out (th/try-on! (sm/handle data))] @@ -31,38 +33,38 @@ (t/is (nil? (:error out))) (let [result (:result out)] - (t/is (= (:id profile) (:profile-id result))) + (t/is (= id (:id result))) + (t/is (= (:id team) (:team-id result))) (t/is (= (:name data) (:name result)))))) - (t/testing "update collection" - (let [data {::sm/type :rename-color-collection - :name "sample collection renamed" - :profile-id (:id profile) + (t/testing "update library" + (let [data {::sm/type :rename-color-library + :name "renamed" + :profile-id (:id prof) :id id} out (th/try-on! (sm/handle data))] ;; (th/print-result! out) (t/is (nil? (:error out))) + (t/is (nil? (:result out))))) - (t/is (= id (get-in out [:result :id]))) - (t/is (= (:id profile) (get-in out [:result :profile-id]))) - (t/is (= (:name data) (get-in out [:result :name]))))) - - (t/testing "query collections" - (let [data {::sq/type :color-collections - :profile-id (:id profile)} + (t/testing "query libraries" + (let [data {::sq/type :color-libraries + :profile-id (:id prof) + :team-id (:id team)} out (th/try-on! (sq/handle data))] ;; (th/print-result! out) (t/is (nil? (:error out))) - (t/is (= 1 (count (:result out)))) - (t/is (= (:id profile) (get-in out [:result 0 :profile-id]))) - (t/is (= id (get-in out [:result 0 :id]))))) + (let [result (:result out)] + (t/is (= 1 (count result))) + (t/is (= (:id team) (get-in result [0 :team-id]))) + (t/is (= "renamed" (get-in result [0 :name])))))) - (t/testing "delete collection" - (let [data {::sm/type :delete-color-collection - :profile-id (:id profile) + (t/testing "delete library" + (let [data {::sm/type :delete-color-library + :profile-id (:id prof) :id id} out (th/try-on! (sm/handle data))] @@ -71,26 +73,29 @@ (t/is (nil? (:error out))) (t/is (nil? (:result out))))) - (t/testing "query collections after delete" - (let [data {::sq/type :color-collections - :profile-id (:id profile)} + (t/testing "query libraries after delete" + (let [data {::sq/type :color-libraries + :profile-id (:id prof) + :team-id (:id team)} out (th/try-on! (sq/handle data))] ;; (th/print-result! out) (t/is (nil? (:error out))) - (t/is (= 0 (count (:result out)))))) + (let [result (:result out)] + (t/is (= 0 (count result)))))) )) (t/deftest colors-crud - (let [profile @(th/create-profile db/pool 1) - coll @(th/create-color-collection db/pool (:id profile) 1) + (let [prof @(th/create-profile db/pool 1) + team (:default-team prof) + coll @(th/create-color-library db/pool (:id team) 1) color-id (uuid/next)] - (t/testing "upload color to collection" + (t/testing "upload color to library" (let [data {::sm/type :create-color :id color-id - :profile-id (:id profile) - :collection-id (:id coll) + :profile-id (:id prof) + :library-id (:id coll) :name "testfile" :content "#222222"} out (th/try-on! (sm/handle data))] @@ -103,10 +108,10 @@ (t/is (= (:name data) (:name result))) (t/is (= (:content data) (:content result)))))) - (t/testing "list colors by collection" + (t/testing "list colors by library" (let [data {::sq/type :colors - :profile-id (:id profile) - :collection-id (:id coll)} + :profile-id (:id prof) + :library-id (:id coll)} out (th/try-on! (sq/handle data))] ;; (th/print-result! out) @@ -115,7 +120,7 @@ (t/testing "single color" (let [data {::sq/type :color - :profile-id (:id profile) + :profile-id (:id prof) :id color-id} out (th/try-on! (sq/handle data))] ;; (th/print-result! out) @@ -125,7 +130,7 @@ (t/testing "delete colors" (let [data {::sm/type :delete-color - :profile-id (:id profile) + :profile-id (:id prof) :id color-id} out (th/try-on! (sm/handle data))] @@ -135,7 +140,7 @@ (t/testing "query color after delete" (let [data {::sq/type :color - :profile-id (:id profile) + :profile-id (:id prof) :id color-id} out (th/try-on! (sq/handle data))] @@ -150,8 +155,8 @@ (t/testing "query colors after delete" (let [data {::sq/type :colors - :profile-id (:id profile) - :collection-id (:id coll)} + :profile-id (:id prof) + :library-id (:id coll)} out (th/try-on! (sq/handle data))] ;; (th/print-result! out) (let [result (:result out)] diff --git a/backend/tests/uxbox/tests/test_services_files.clj b/backend/tests/uxbox/tests/test_services_files.clj index 42cd609d1..442dbdb8a 100644 --- a/backend/tests/uxbox/tests/test_services_files.clj +++ b/backend/tests/uxbox/tests/test_services_files.clj @@ -173,8 +173,8 @@ (t/is (string? (:thumb-path result))) (t/is (string? (:thumb-uri result)))))) - (t/testing "import from collection" - (let [coll @(th/create-image-collection db/pool (:id prof) 1) + (t/testing "import from library" + (let [lib @(th/create-image-library db/pool (:id team) 1) image-id (uuid/next) content {:name "sample.jpg" @@ -185,7 +185,7 @@ data {::sm/type :upload-image :id image-id :profile-id (:id prof) - :collection-id (:id coll) + :library-id (:id lib) :name "testfile" :content content} out1 (th/try-on! (sm/handle data))] diff --git a/backend/tests/uxbox/tests/test_services_icons.clj b/backend/tests/uxbox/tests/test_services_icons.clj index ca374d6ef..9a3b49e7a 100644 --- a/backend/tests/uxbox/tests/test_services_icons.clj +++ b/backend/tests/uxbox/tests/test_services_icons.clj @@ -16,14 +16,16 @@ (t/use-fixtures :once th/state-init) (t/use-fixtures :each th/database-reset) -(t/deftest icon-collections-crud +(t/deftest icon-libraries-crud (let [id (uuid/next) - profile @(th/create-profile db/pool 2)] + prof @(th/create-profile db/pool 2) + team (:default-team prof)] - (t/testing "create collection" - (let [data {::sm/type :create-icon-collection - :name "sample collection" - :profile-id (:id profile) + (t/testing "create library" + (let [data {::sm/type :create-icon-library + :name "sample library" + :profile-id (:id prof) + :team-id (:id team) :id id} out (th/try-on! (sm/handle data))] @@ -31,38 +33,39 @@ (t/is (nil? (:error out))) (let [result (:result out)] - (t/is (= (:id profile) (:profile-id result))) + (t/is (= id (:id result))) + (t/is (= (:id team) (:team-id result))) (t/is (= (:name data) (:name result)))))) - (t/testing "update collection" - (let [data {::sm/type :rename-icon-collection - :name "sample collection renamed" - :profile-id (:id profile) + (t/testing "rename library" + (let [data {::sm/type :rename-icon-library + :name "renamed" + :profile-id (:id prof) + :team-id (:id team) :id id} out (th/try-on! (sm/handle data))] ;; (th/print-result! out) (t/is (nil? (:error out))) + (t/is (nil? (:result out))))) - (t/is (= id (get-in out [:result :id]))) - (t/is (= (:id profile) (get-in out [:result :profile-id]))) - (t/is (= (:name data) (get-in out [:result :name]))))) - - (t/testing "query collections" - (let [data {::sq/type :icon-collections - :profile-id (:id profile)} + (t/testing "query libraries" + (let [data {::sq/type :icon-libraries + :profile-id (:id prof) + :team-id (:id team)} out (th/try-on! (sq/handle data))] ;; (th/print-result! out) (t/is (nil? (:error out))) - (t/is (= 1 (count (:result out)))) - (t/is (= (:id profile) (get-in out [:result 0 :profile-id]))) - (t/is (= id (get-in out [:result 0 :id]))))) + (let [result (:result out)] + (t/is (= 1 (count result))) + (t/is (= id (get-in result [0 :id]))) + (t/is (= "renamed" (get-in result [0 :name])))))) - (t/testing "delete collection" - (let [data {::sm/type :delete-icon-collection - :profile-id (:id profile) + (t/testing "delete library" + (let [data {::sm/type :delete-icon-library + :profile-id (:id prof) :id id} out (th/try-on! (sm/handle data))] @@ -71,26 +74,30 @@ (t/is (nil? (:error out))) (t/is (nil? (:result out))))) - (t/testing "query collections after delete" - (let [data {::sq/type :icon-collections - :profile-id (:id profile)} + (t/testing "query libraries after delete" + (let [data {::sq/type :icon-libraries + :profile-id (:id prof) + :team-id (:id team)} out (th/try-on! (sq/handle data))] ;; (th/print-result! out) (t/is (nil? (:error out))) - (t/is (= 0 (count (:result out)))))) + + (let [result (:result out)] + (t/is (= 0 (count result)))))) )) (t/deftest icons-crud - (let [profile @(th/create-profile db/pool 1) - coll @(th/create-icon-collection db/pool (:id profile) 1) + (let [prof @(th/create-profile db/pool 1) + team (:default-team prof) + coll @(th/create-icon-library db/pool (:id team) 1) icon-id (uuid/next)] - (t/testing "upload icon to collection" + (t/testing "upload icon to library" (let [data {::sm/type :create-icon :id icon-id - :profile-id (:id profile) - :collection-id (:id coll) + :profile-id (:id prof) + :library-id (:id coll) :name "testfile" :content "" :metadata {:width 100 @@ -107,10 +114,10 @@ (t/is (= (:name data) (:name result))) (t/is (= (:content data) (:content result)))))) - (t/testing "list icons by collection" + (t/testing "list icons by library" (let [data {::sq/type :icons - :profile-id (:id profile) - :collection-id (:id coll)} + :profile-id (:id prof) + :library-id (:id coll)} out (th/try-on! (sq/handle data))] ;; (th/print-result! out) @@ -119,7 +126,7 @@ (t/testing "single icon" (let [data {::sq/type :icon - :profile-id (:id profile) + :profile-id (:id prof) :id icon-id} out (th/try-on! (sq/handle data))] ;; (th/print-result! out) @@ -129,17 +136,17 @@ (t/testing "delete icons" (let [data {::sm/type :delete-icon - :profile-id (:id profile) + :profile-id (:id prof) :id icon-id} out (th/try-on! (sm/handle data))] ;; (th/print-result! out) (t/is (nil? (:error out))) - (t/is (nil? (get-in out [:result]))))) + (t/is (nil? (:result out))))) (t/testing "query icon after delete" (let [data {::sq/type :icon - :profile-id (:id profile) + :profile-id (:id prof) :id icon-id} out (th/try-on! (sq/handle data))] @@ -154,9 +161,10 @@ (t/testing "query icons after delete" (let [data {::sq/type :icons - :profile-id (:id profile) - :collection-id (:id coll)} + :profile-id (:id prof) + :library-id (:id coll)} out (th/try-on! (sq/handle data))] + ;; (th/print-result! out) (let [result (:result out)] (t/is (= 0 (count result)))))) diff --git a/backend/tests/uxbox/tests/test_services_images.clj b/backend/tests/uxbox/tests/test_services_images.clj index 576c90188..57e96fc24 100644 --- a/backend/tests/uxbox/tests/test_services_images.clj +++ b/backend/tests/uxbox/tests/test_services_images.clj @@ -16,14 +16,16 @@ (t/use-fixtures :once th/state-init) (t/use-fixtures :each th/database-reset) -(t/deftest image-collections-crud +(t/deftest image-libraries-crud (let [id (uuid/next) - profile @(th/create-profile db/pool 2)] + prof @(th/create-profile db/pool 2) + team (:default-team prof)] - (t/testing "create collection" - (let [data {::sm/type :create-image-collection - :name "sample collection" - :profile-id (:id profile) + (t/testing "create library" + (let [data {::sm/type :create-image-library + :name "sample library" + :profile-id (:id prof) + :team-id (:id team) :id id} out (th/try-on! (sm/handle data))] @@ -31,38 +33,49 @@ (t/is (nil? (:error out))) (let [result (:result out)] - (t/is (= (:id profile) (:profile-id result))) + (t/is (= (:id team) (:team-id result))) (t/is (= (:name data) (:name result)))))) - (t/testing "update collection" - (let [data {::sm/type :rename-image-collection - :name "sample collection renamed" - :profile-id (:id profile) + (t/testing "rename library" + (let [data {::sm/type :rename-image-library + :name "renamed" + :profile-id (:id prof) :id id} out (th/try-on! (sm/handle data))] ;; (th/print-result! out) (t/is (nil? (:error out))) + (t/is (nil? (:result out))))) - (t/is (= id (get-in out [:result :id]))) - (t/is (= (:id profile) (get-in out [:result :profile-id]))) - (t/is (= (:name data) (get-in out [:result :name]))))) - - (t/testing "query collections" - (let [data {::sq/type :image-collections - :profile-id (:id profile)} + (t/testing "query single library" + (let [data {::sq/type :image-library + :profile-id (:id prof) + :id id} out (th/try-on! (sq/handle data))] ;; (th/print-result! out) (t/is (nil? (:error out))) - (t/is (= 1 (count (:result out)))) - (t/is (= (:id profile) (get-in out [:result 0 :profile-id]))) - (t/is (= id (get-in out [:result 0 :id]))))) + (let [result (:result out)] + (t/is (= id (:id result))) + (t/is (= "renamed" (:name result)))))) - (t/testing "delete collection" - (let [data {::sm/type :delete-image-collection - :profile-id (:id profile) + (t/testing "query libraries" + (let [data {::sq/type :image-libraries + :team-id (:id team) + :profile-id (:id prof)} + out (th/try-on! (sq/handle data))] + + ;; (th/print-result! out) + (t/is (nil? (:error out))) + + (let [result (:result out)] + (t/is (= 1 (count result))) + (t/is (= id (get-in result [0 :id])))))) + + (t/testing "delete library" + (let [data {::sm/type :delete-image-library + :profile-id (:id prof) :id id} out (th/try-on! (sm/handle data))] @@ -71,9 +84,10 @@ (t/is (nil? (:error out))) (t/is (nil? (:result out))))) - (t/testing "query collections after delete" - (let [data {::sq/type :image-collections - :profile-id (:id profile)} + (t/testing "query libraries after delete" + (let [data {::sq/type :image-libraries + :profile-id (:id prof) + :team-id (:id team)} out (th/try-on! (sq/handle data))] ;; (th/print-result! out) @@ -82,19 +96,20 @@ )) (t/deftest images-crud - (let [profile @(th/create-profile db/pool 1) - coll @(th/create-image-collection db/pool (:id profile) 1) + (let [prof @(th/create-profile db/pool 1) + team (:default-team prof) + lib @(th/create-image-library db/pool (:id team) 1) image-id (uuid/next)] - (t/testing "upload image to collection" + (t/testing "upload image to library" (let [content {:name "sample.jpg" :path "tests/uxbox/tests/_files/sample.jpg" :mtype "image/jpeg" :size 312043} data {::sm/type :upload-image :id image-id - :profile-id (:id profile) - :collection-id (:id coll) + :profile-id (:id prof) + :library-id (:id lib) :name "testfile" :content content} out (th/try-on! (sm/handle data))] @@ -114,10 +129,10 @@ (t/is (string? (get-in out [:result :uri]))) (t/is (string? (get-in out [:result :thumb-uri]))))) - (t/testing "list images by collection" + (t/testing "list images by library" (let [data {::sq/type :images - :profile-id (:id profile) - :collection-id (:id coll)} + :profile-id (:id prof) + :library-id (:id lib)} out (th/try-on! (sq/handle data))] ;; (th/print-result! out) @@ -135,7 +150,7 @@ (t/testing "single image" (let [data {::sq/type :image - :profile-id (:id profile) + :profile-id (:id prof) :id image-id} out (th/try-on! (sq/handle data))] ;; (th/print-result! out) @@ -154,17 +169,17 @@ (t/testing "delete images" (let [data {::sm/type :delete-image - :profile-id (:id profile) + :profile-id (:id prof) :id image-id} out (th/try-on! (sm/handle data))] ;; (th/print-result! out) (t/is (nil? (:error out))) - (t/is (nil? (get-in out [:result]))))) + (t/is (nil? (:result out))))) (t/testing "query image after delete" (let [data {::sq/type :image - :profile-id (:id profile) + :profile-id (:id prof) :id image-id} out (th/try-on! (sq/handle data))] @@ -179,8 +194,8 @@ (t/testing "query images after delete" (let [data {::sq/type :images - :profile-id (:id profile) - :collection-id (:id coll)} + :profile-id (:id prof) + :library-id (:id lib)} out (th/try-on! (sq/handle data))] ;; (th/print-result! out) (let [result (:result out)]