From 05a86581a5554c2833025ccb53f5b7436289c085 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 12 Jul 2022 20:37:01 +0200 Subject: [PATCH] :sparkles: Reorganize comments related rpc methods Mutations becomes deprecated and queries moved to commands. The old queries still maintained with deprecated flag. --- backend/src/app/rpc.clj | 1 + backend/src/app/rpc/commands/comments.clj | 203 +++++++++++++++++++++ backend/src/app/rpc/mutations/comments.clj | 17 +- backend/src/app/rpc/queries/comments.clj | 130 +++---------- backend/src/app/rpc/queries/viewer.clj | 4 +- 5 files changed, 243 insertions(+), 112 deletions(-) create mode 100644 backend/src/app/rpc/commands/comments.clj diff --git a/backend/src/app/rpc.clj b/backend/src/app/rpc.clj index 801fc5c1f..477b0a633 100644 --- a/backend/src/app/rpc.clj +++ b/backend/src/app/rpc.clj @@ -241,6 +241,7 @@ [cfg] (let [cfg (assoc cfg ::type "command" ::metrics-id :rpc-command-timing)] (->> (sv/scan-ns 'app.rpc.commands.binfile + 'app.rpc.commands.comments 'app.rpc.commands.auth 'app.rpc.commands.ldap 'app.rpc.commands.demo) diff --git a/backend/src/app/rpc/commands/comments.clj b/backend/src/app/rpc/commands/comments.clj new file mode 100644 index 000000000..b91d98810 --- /dev/null +++ b/backend/src/app/rpc/commands/comments.clj @@ -0,0 +1,203 @@ +;; 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) UXBOX Labs SL + +(ns app.rpc.commands.comments + (:require + [app.common.spec :as us] + [app.common.pages.changes :as changes] + [app.db :as db] + [app.http.doc :as doc] + [app.rpc.queries.files :as files] + [app.rpc.queries.teams :as teams] + [app.util.services :as sv] + [clojure.spec.alpha :as s])) + +(defn decode-row + [{:keys [participants position] :as row}] + (cond-> row + (db/pgpoint? position) (assoc :position (db/decode-pgpoint position)) + (db/pgobject? participants) (assoc :participants (db/decode-transit-pgobject participants)))) + +;; --- COMMAND: Get Comment Threads + +(declare retrieve-comment-threads) + +(s/def ::team-id ::us/uuid) +(s/def ::file-id ::us/uuid) +(s/def ::share-id (s/nilable ::us/uuid)) + +(s/def ::get-comment-threads + (s/and (s/keys :req-un [::profile-id] + :opt-un [::file-id ::share-id ::team-id]) + #(or (:file-id %) (:team-id %)))) + +(sv/defmethod ::get-comment-threads + [{:keys [pool] :as cfg} params] + (with-open [conn (db/open pool)] + (retrieve-comment-threads conn params))) + +(def sql:comment-threads + "select distinct on (ct.id) + ct.*, + f.name as file_name, + f.project_id as project_id, + first_value(c.content) over w as content, + (select count(1) + from comment as c + where c.thread_id = ct.id) as count_comments, + (select count(1) + from comment as c + where c.thread_id = ct.id + and c.created_at >= coalesce(cts.modified_at, ct.created_at)) as count_unread_comments + from comment_thread as ct + inner join comment as c on (c.thread_id = ct.id) + inner join file as f on (f.id = ct.file_id) + left join comment_thread_status as cts + on (cts.thread_id = ct.id and + cts.profile_id = ?) + where ct.file_id = ? + window w as (partition by c.thread_id order by c.created_at asc)") + +(defn retrieve-comment-threads + [conn {:keys [profile-id file-id share-id]}] + (files/check-comment-permissions! conn profile-id file-id share-id) + (->> (db/exec! conn [sql:comment-threads profile-id file-id]) + (into [] (map decode-row)))) + +;; --- COMMAND: Get Unread Comment Threads + +(declare retrieve-unread-comment-threads) + +(s/def ::team-id ::us/uuid) +(s/def ::get-unread-comment-threads + (s/keys :req-un [::profile-id ::team-id])) + +(sv/defmethod ::get-unread-comment-threads + [{:keys [pool] :as cfg} {:keys [profile-id team-id] :as params}] + (with-open [conn (db/open pool)] + (teams/check-read-permissions! conn profile-id team-id) + (retrieve-unread-comment-threads conn params))) + +(def sql:comment-threads-by-team + "select distinct on (ct.id) + ct.*, + f.name as file_name, + f.project_id as project_id, + first_value(c.content) over w as content, + (select count(1) + from comment as c + where c.thread_id = ct.id) as count_comments, + (select count(1) + from comment as c + where c.thread_id = ct.id + and c.created_at >= coalesce(cts.modified_at, ct.created_at)) as count_unread_comments + from comment_thread as ct + inner join comment as c on (c.thread_id = ct.id) + inner join file as f on (f.id = ct.file_id) + inner join project as p on (p.id = f.project_id) + left join comment_thread_status as cts + on (cts.thread_id = ct.id and + cts.profile_id = ?) + where p.team_id = ? + window w as (partition by c.thread_id order by c.created_at asc)") + +(def sql:unread-comment-threads-by-team + (str "with threads as (" sql:comment-threads-by-team ")" + "select * from threads where count_unread_comments > 0")) + +(defn retrieve-unread-comment-threads + [conn {:keys [profile-id team-id]}] + (->> (db/exec! conn [sql:unread-comment-threads-by-team profile-id team-id]) + (into [] (map decode-row)))) + + +;; --- COMMAND: Get Single Comment Thread + +(s/def ::id ::us/uuid) +(s/def ::share-id (s/nilable ::us/uuid)) +(s/def ::get-comment-thread + (s/keys :req-un [::profile-id ::file-id ::id] + :opt-un [::share-id])) + +(sv/defmethod ::get-comment-thread + [{:keys [pool] :as cfg} {:keys [profile-id file-id id share-id] :as params}] + (with-open [conn (db/open pool)] + (files/check-comment-permissions! conn profile-id file-id share-id) + (let [sql (str "with threads as (" sql:comment-threads ")" + "select * from threads where id = ?")] + (-> (db/exec-one! conn [sql profile-id file-id id]) + (decode-row))))) + +;; --- COMMAND: Comments + +(declare retrieve-comments) + +(s/def ::file-id ::us/uuid) +(s/def ::share-id (s/nilable ::us/uuid)) +(s/def ::thread-id ::us/uuid) +(s/def ::get-comments + (s/keys :req-un [::profile-id ::thread-id] + :opt-un [::share-id])) + +(sv/defmethod ::get-comments + [{:keys [pool] :as cfg} {:keys [profile-id thread-id share-id] :as params}] + (with-open [conn (db/open pool)] + (let [thread (db/get-by-id conn :comment-thread thread-id)] + (files/check-comment-permissions! conn profile-id (:file-id thread) share-id) + (retrieve-comments conn thread-id)))) + +(def sql:comments + "select c.* from comment as c + where c.thread_id = ? + order by c.created_at asc") + +(defn retrieve-comments + [conn thread-id] + (->> (db/exec! conn [sql:comments thread-id]) + (into [] (map decode-row)))) + +;; --- COMMAND: Get file comments users + +(declare retrieve-file-comments-users) + +(s/def ::file-id ::us/uuid) +(s/def ::share-id (s/nilable ::us/uuid)) + +(s/def ::get-profiles-for-file-comments + (s/keys :req-un [::profile-id ::file-id] + :opt-un [::share-id])) + +(sv/defmethod ::get-profiles-for-file-comments + "Retrieves a list of profiles with limited set of properties of all + participants on comment threads of the file." + {::doc/added "1.15" + ::doc/changes ["1.15" "Imported from queries and renamed."]} + [{:keys [pool] :as cfg} {:keys [profile-id file-id share-id]}] + (with-open [conn (db/open pool)] + (files/check-comment-permissions! conn profile-id file-id share-id) + (retrieve-file-comments-users conn file-id profile-id))) + +;; All the profiles that had comment the file, plus the current +;; profile. + +(def sql:file-comment-users + "WITH available_profiles AS ( + SELECT DISTINCT owner_id AS id + FROM comment + WHERE thread_id IN (SELECT id FROM comment_thread WHERE file_id=?) + ) + SELECT p.id, + p.email, + p.fullname AS name, + p.fullname AS fullname, + p.photo_id, + p.is_active + FROM profile AS p + WHERE p.id IN (SELECT id FROM available_profiles) OR p.id=?") + +(defn retrieve-file-comments-users + [conn file-id profile-id] + (db/exec! conn [sql:file-comment-users file-id profile-id])) diff --git a/backend/src/app/rpc/mutations/comments.clj b/backend/src/app/rpc/mutations/comments.clj index 45e75a626..84c1a6f64 100644 --- a/backend/src/app/rpc/mutations/comments.clj +++ b/backend/src/app/rpc/mutations/comments.clj @@ -10,6 +10,7 @@ [app.common.geom.point :as gpt] [app.common.spec :as us] [app.db :as db] + [app.http.doc :as doc] [app.rpc.queries.comments :as comments] [app.rpc.queries.files :as files] [app.rpc.retry :as retry] @@ -37,7 +38,9 @@ (sv/defmethod ::create-comment-thread {::retry/max-retries 3 - ::retry/matches retry/conflict-db-insert?} + ::retry/matches retry/conflict-db-insert? + ::doc/added "1.0" + ::doc/deprecated "1.15"} [{:keys [pool] :as cfg} {:keys [profile-id file-id share-id] :as params}] (db/with-atomic [conn pool] (files/check-comment-permissions! conn profile-id file-id share-id) @@ -101,6 +104,8 @@ :opt-un [::share-id])) (sv/defmethod ::update-comment-thread-status + {::doc/added "1.0" + ::doc/deprecated "1.15"} [{:keys [pool] :as cfg} {:keys [profile-id id share-id] :as params}] (db/with-atomic [conn pool] (let [cthr (db/get-by-id conn :comment-thread id {:for-update true})] @@ -130,6 +135,8 @@ :opt-un [::share-id])) (sv/defmethod ::update-comment-thread + {::doc/added "1.0" + ::doc/deprecated "1.15"} [{:keys [pool] :as cfg} {:keys [profile-id id is-resolved share-id] :as params}] (db/with-atomic [conn pool] (let [thread (db/get-by-id conn :comment-thread id {:for-update true})] @@ -151,6 +158,8 @@ :opt-un [::share-id])) (sv/defmethod ::add-comment + {::doc/added "1.0" + ::doc/deprecated "1.15"} [{:keys [pool] :as cfg} {:keys [profile-id thread-id content share-id] :as params}] (db/with-atomic [conn pool] (let [thread (-> (db/get-by-id conn :comment-thread thread-id {:for-update true}) @@ -209,6 +218,8 @@ :opt-un [::share-id])) (sv/defmethod ::update-comment + {::doc/added "1.0" + ::doc/deprecated "1.15"} [{:keys [pool] :as cfg} {:keys [profile-id id content share-id] :as params}] (db/with-atomic [conn pool] (let [comment (db/get-by-id conn :comment id {:for-update true}) @@ -242,6 +253,8 @@ (s/keys :req-un [::profile-id ::id])) (sv/defmethod ::delete-comment-thread + {::doc/added "1.0" + ::doc/deprecated "1.15"} [{:keys [pool] :as cfg} {:keys [profile-id id] :as params}] (db/with-atomic [conn pool] (let [thread (db/get-by-id conn :comment-thread id {:for-update true})] @@ -258,6 +271,8 @@ (s/keys :req-un [::profile-id ::id])) (sv/defmethod ::delete-comment + {::doc/added "1.0" + ::doc/deprecated "1.15"} [{:keys [pool] :as cfg} {:keys [profile-id id] :as params}] (db/with-atomic [conn pool] (let [comment (db/get-by-id conn :comment id {:for-update true})] diff --git a/backend/src/app/rpc/queries/comments.clj b/backend/src/app/rpc/queries/comments.clj index 3815ef31c..29d5a2c90 100644 --- a/backend/src/app/rpc/queries/comments.clj +++ b/backend/src/app/rpc/queries/comments.clj @@ -8,6 +8,8 @@ (:require [app.common.spec :as us] [app.db :as db] + [app.http.doc :as doc] + [app.rpc.commands.comments :as cmd.comments] [app.rpc.queries.files :as files] [app.rpc.queries.teams :as teams] [app.util.services :as sv] @@ -19,9 +21,7 @@ (db/pgpoint? position) (assoc :position (db/decode-pgpoint position)) (db/pgobject? participants) (assoc :participants (db/decode-transit-pgobject participants)))) -;; --- Query: Comment Threads - -(declare retrieve-comment-threads) +;; --- QUERY: Comment Threads (s/def ::team-id ::us/uuid) (s/def ::file-id ::us/uuid) @@ -33,87 +33,27 @@ #(or (:file-id %) (:team-id %)))) (sv/defmethod ::comment-threads + {::doc/deprecated "1.15"} [{:keys [pool] :as cfg} params] (with-open [conn (db/open pool)] - (retrieve-comment-threads conn params))) - -(def sql:comment-threads - "select distinct on (ct.id) - ct.*, - f.name as file_name, - f.project_id as project_id, - first_value(c.content) over w as content, - (select count(1) - from comment as c - where c.thread_id = ct.id) as count_comments, - (select count(1) - from comment as c - where c.thread_id = ct.id - and c.created_at >= coalesce(cts.modified_at, ct.created_at)) as count_unread_comments - from comment_thread as ct - inner join comment as c on (c.thread_id = ct.id) - inner join file as f on (f.id = ct.file_id) - left join comment_thread_status as cts - on (cts.thread_id = ct.id and - cts.profile_id = ?) - where ct.file_id = ? - window w as (partition by c.thread_id order by c.created_at asc)") - -(defn- retrieve-comment-threads - [conn {:keys [profile-id file-id share-id]}] - (files/check-comment-permissions! conn profile-id file-id share-id) - (->> (db/exec! conn [sql:comment-threads profile-id file-id]) - (into [] (map decode-row)))) + (cmd.comments/retrieve-comment-threads conn params))) -;; --- Query: Unread Comment Threads - -(declare retrieve-unread-comment-threads) +;; --- QUERY: Unread Comment Threads (s/def ::team-id ::us/uuid) (s/def ::unread-comment-threads (s/keys :req-un [::profile-id ::team-id])) (sv/defmethod ::unread-comment-threads + {::doc/added "1.0" + ::doc/deprecated "1.15"} [{:keys [pool] :as cfg} {:keys [profile-id team-id] :as params}] (with-open [conn (db/open pool)] (teams/check-read-permissions! conn profile-id team-id) - (retrieve-unread-comment-threads conn params))) + (cmd.comments/retrieve-unread-comment-threads conn params))) -(def sql:comment-threads-by-team - "select distinct on (ct.id) - ct.*, - f.name as file_name, - f.project_id as project_id, - first_value(c.content) over w as content, - (select count(1) - from comment as c - where c.thread_id = ct.id) as count_comments, - (select count(1) - from comment as c - where c.thread_id = ct.id - and c.created_at >= coalesce(cts.modified_at, ct.created_at)) as count_unread_comments - from comment_thread as ct - inner join comment as c on (c.thread_id = ct.id) - inner join file as f on (f.id = ct.file_id) - inner join project as p on (p.id = f.project_id) - left join comment_thread_status as cts - on (cts.thread_id = ct.id and - cts.profile_id = ?) - where p.team_id = ? - window w as (partition by c.thread_id order by c.created_at asc)") - -(def sql:unread-comment-threads-by-team - (str "with threads as (" sql:comment-threads-by-team ")" - "select * from threads where count_unread_comments > 0")) - -(defn retrieve-unread-comment-threads - [conn {:keys [profile-id team-id]}] - (->> (db/exec! conn [sql:unread-comment-threads-by-team profile-id team-id]) - (into [] (map decode-row)))) - - -;; --- Query: Single Comment Thread +;; --- QUERY: Single Comment Thread (s/def ::id ::us/uuid) (s/def ::share-id (s/nilable ::us/uuid)) @@ -122,17 +62,17 @@ :opt-un [::share-id])) (sv/defmethod ::comment-thread + {::doc/added "1.0" + ::doc/deprecated "1.15"} [{:keys [pool] :as cfg} {:keys [profile-id file-id id share-id] :as params}] (with-open [conn (db/open pool)] (files/check-comment-permissions! conn profile-id file-id share-id) - (let [sql (str "with threads as (" sql:comment-threads ")" + (let [sql (str "with threads as (" cmd.comments/sql:comment-threads ")" "select * from threads where id = ?")] (-> (db/exec-one! conn [sql profile-id file-id id]) (decode-row))))) -;; --- Query: Comments - -(declare retrieve-comments) +;; --- QUERY: Comments (s/def ::file-id ::us/uuid) (s/def ::share-id (s/nilable ::us/uuid)) @@ -142,25 +82,15 @@ :opt-un [::share-id])) (sv/defmethod ::comments + {::doc/added "1.0" + ::doc/deprecated "1.15"} [{:keys [pool] :as cfg} {:keys [profile-id thread-id share-id] :as params}] (with-open [conn (db/open pool)] (let [thread (db/get-by-id conn :comment-thread thread-id)] (files/check-comment-permissions! conn profile-id (:file-id thread) share-id) - (retrieve-comments conn thread-id)))) + (cmd.comments/retrieve-comments conn thread-id)))) -(def sql:comments - "select c.* from comment as c - where c.thread_id = ? - order by c.created_at asc") - -(defn- retrieve-comments - [conn thread-id] - (->> (db/exec! conn [sql:comments thread-id]) - (into [] (map decode-row)))) - -;; file-comments-users - -(declare retrieve-file-comments-users) +;; --- QUERY: Get file comments users (s/def ::file-id ::us/uuid) (s/def ::share-id (s/nilable ::us/uuid)) @@ -170,27 +100,9 @@ :opt-un [::share-id])) (sv/defmethod ::file-comments-users + {::doc/deprecated "1.15" + ::doc/added "1.13"} [{:keys [pool] :as cfg} {:keys [profile-id file-id share-id]}] (with-open [conn (db/open pool)] (files/check-comment-permissions! conn profile-id file-id share-id) - (retrieve-file-comments-users conn file-id profile-id))) - -(def sql:file-comment-users - "select p.id, - p.email, - p.fullname as name, - p.fullname as fullname, - p.photo_id, - p.is_active - from profile p - where p.id in - (select owner_id from comment - where thread_id in - (select id from comment_thread - where file_id=?)) - or p.id=? - ") ;; all the users that had comment the file, plus the current user - -(defn retrieve-file-comments-users - [conn file-id profile-id] - (db/exec! conn [sql:file-comment-users file-id profile-id])) + (cmd.comments/retrieve-file-comments-users conn file-id profile-id))) diff --git a/backend/src/app/rpc/queries/viewer.clj b/backend/src/app/rpc/queries/viewer.clj index a82e08e65..681b8ef47 100644 --- a/backend/src/app/rpc/queries/viewer.clj +++ b/backend/src/app/rpc/queries/viewer.clj @@ -9,9 +9,9 @@ [app.common.exceptions :as ex] [app.common.spec :as us] [app.db :as db] - [app.rpc.queries.comments :as comments] + [app.rpc.commands.comments :as comments] [app.rpc.queries.files :as files] - [app.rpc.queries.share-link :as slnk] + [app.rpc.queries.share-link :as slnk] [app.util.services :as sv] [clojure.spec.alpha :as s] [promesa.core :as p]))