In view mode allow comment/inspect to non-team users (by shared link permissions)

This commit is contained in:
Pablo Alba 2022-06-22 18:16:34 +02:00
parent 0f04398e61
commit 115314e97c
23 changed files with 254 additions and 132 deletions

View file

@ -228,13 +228,13 @@
:fn (mg/resource "app/migrations/sql/0072-mod-file-object-thumbnail-table.sql")}
{:name "0073-mod-file-media-object-constraints"
:fn (mg/resource "app/migrations/sql/0073-mod-file-media-object-constraints.sql")}
{:name "0073-mod-share-link-table"
:fn (mg/resource "app/migrations/sql/0073-mod-share-link-table.sql")}
:fn (mg/resource "app/migrations/sql/0073-mod-file-media-object-constraints.sql")}
{:name "0074-mod-file-library-rel-constraints"
:fn (mg/resource "app/migrations/sql/0074-mod-file-library-rel-constraints.sql")}
{:name "0075-mod-share-link-table"
:fn (mg/resource "app/migrations/sql/0075-mod-share-link-table.sql")}
])

View file

@ -26,19 +26,21 @@
(s/def ::page-id ::us/uuid)
(s/def ::file-id ::us/uuid)
(s/def ::share-id (s/nilable ::us/uuid))
(s/def ::profile-id ::us/uuid)
(s/def ::position ::gpt/point)
(s/def ::content ::us/string)
(s/def ::create-comment-thread
(s/keys :req-un [::profile-id ::file-id ::position ::content ::page-id]))
(s/keys :req-un [::profile-id ::file-id ::position ::content ::page-id]
:opt-un [::share-id]))
(sv/defmethod ::create-comment-thread
{::retry/max-retries 3
::retry/matches retry/conflict-db-insert?}
[{:keys [pool] :as cfg} {:keys [profile-id file-id] :as params}]
[{:keys [pool] :as cfg} {:keys [profile-id file-id share-id] :as params}]
(db/with-atomic [conn pool]
(files/check-read-permissions! conn profile-id file-id)
(files/check-comment-permissions! conn profile-id file-id share-id)
(create-comment-thread conn params)))
(defn- retrieve-next-seqn
@ -92,18 +94,20 @@
;; --- Mutation: Update Comment Thread Status
(s/def ::id ::us/uuid)
(s/def ::share-id (s/nilable ::us/uuid))
(s/def ::update-comment-thread-status
(s/keys :req-un [::profile-id ::id]))
(s/keys :req-un [::profile-id ::id]
:opt-un [::share-id]))
(sv/defmethod ::update-comment-thread-status
[{:keys [pool] :as cfg} {:keys [profile-id id] :as params}]
[{: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})]
(when-not cthr
(ex/raise :type :not-found))
(files/check-read-permissions! conn profile-id (:file-id cthr))
(files/check-comment-permissions! conn profile-id (:file-id cthr) share-id)
(upsert-comment-thread-status! conn profile-id (:id cthr)))))
(def sql:upsert-comment-thread-status
@ -122,16 +126,17 @@
(s/def ::is-resolved ::us/boolean)
(s/def ::update-comment-thread
(s/keys :req-un [::profile-id ::id ::is-resolved]))
(s/keys :req-un [::profile-id ::id ::is-resolved]
:opt-un [::share-id]))
(sv/defmethod ::update-comment-thread
[{:keys [pool] :as cfg} {:keys [profile-id id is-resolved] :as params}]
[{: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})]
(when-not thread
(ex/raise :type :not-found))
(files/check-read-permissions! conn profile-id (:file-id thread))
(files/check-comment-permissions! conn profile-id (:file-id thread) share-id)
(db/update! conn :comment-thread
{:is-resolved is-resolved}
@ -142,10 +147,11 @@
;; --- Mutation: Add Comment
(s/def ::add-comment
(s/keys :req-un [::profile-id ::thread-id ::content]))
(s/keys :req-un [::profile-id ::thread-id ::content]
:opt-un [::share-id]))
(sv/defmethod ::add-comment
[{:keys [pool] :as cfg} {:keys [profile-id thread-id content] :as params}]
[{: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})
(comments/decode-row))
@ -155,7 +161,7 @@
(when-not thread (ex/raise :type :not-found))
;; Permission Checks
(files/check-read-permissions! conn profile-id (:file-id thread))
(files/check-comment-permissions! conn profile-id (:file-id thread) share-id)
;; Update the page-name cachedattribute on comment thread table.
(when (not= pname (:page-name thread))
@ -199,10 +205,11 @@
;; --- Mutation: Update Comment
(s/def ::update-comment
(s/keys :req-un [::profile-id ::id ::content]))
(s/keys :req-un [::profile-id ::id ::content]
:opt-un [::share-id]))
(sv/defmethod ::update-comment
[{:keys [pool] :as cfg} {:keys [profile-id id content] :as params}]
[{: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})
_ (when-not comment (ex/raise :type :not-found))
@ -210,7 +217,7 @@
_ (when-not thread (ex/raise :type :not-found))
pname (retrieve-page-name conn thread)]
(files/check-read-permissions! conn profile-id (:file-id thread))
(files/check-comment-permissions! conn profile-id (:file-id thread) share-id)
;; Don't allow edit comments to not owners
(when-not (= (:owner-id thread) profile-id)

View file

@ -53,6 +53,16 @@
([perms] (:can-read perms))
([conn & args] (check (apply qfn conn args)))))
(defn make-comment-predicate-fn
"A simple factory for comment permission predicate functions."
[qfn]
(us/assert fn? qfn)
(fn check
([perms]
(and (:is-logged perms) (= (:who-comment perms) "all")))
([conn & args]
(check (apply qfn conn args)))))
(defn make-check-fn
"Helper that converts a predicate permission function to a check
function (function that raises an exception)."

View file

@ -25,16 +25,16 @@
(s/def ::team-id ::us/uuid)
(s/def ::file-id ::us/uuid)
(s/def ::share-id (s/nilable ::us/uuid))
(s/def ::comment-threads
(s/and (s/keys :req-un [::profile-id]
:opt-un [::file-id ::team-id])
:opt-un [::file-id ::share-id ::team-id])
#(or (:file-id %) (:team-id %))))
(sv/defmethod ::comment-threads
[{:keys [pool] :as cfg} {:keys [profile-id file-id] :as params}]
[{:keys [pool] :as cfg} params]
(with-open [conn (db/open pool)]
(files/check-read-permissions! conn profile-id file-id)
(retrieve-comment-threads conn params)))
(def sql:comment-threads
@ -60,8 +60,8 @@
window w as (partition by c.thread_id order by c.created_at asc)")
(defn- retrieve-comment-threads
[conn {:keys [profile-id file-id]}]
(files/check-read-permissions! conn profile-id file-id)
[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))))
@ -116,13 +116,15 @@
;; --- Query: Single Comment Thread
(s/def ::id ::us/uuid)
(s/def ::share-id (s/nilable ::us/uuid))
(s/def ::comment-thread
(s/keys :req-un [::profile-id ::file-id ::id]))
(s/keys :req-un [::profile-id ::file-id ::id]
:opt-un [::share-id]))
(sv/defmethod ::comment-thread
[{:keys [pool] :as cfg} {:keys [profile-id file-id id] :as params}]
[{:keys [pool] :as cfg} {:keys [profile-id file-id id share-id] :as params}]
(with-open [conn (db/open pool)]
(files/check-read-permissions! conn profile-id file-id)
(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])
@ -133,15 +135,17 @@
(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 ::comments
(s/keys :req-un [::profile-id ::thread-id]))
(s/keys :req-un [::profile-id ::thread-id]
:opt-un [::share-id]))
(sv/defmethod ::comments
[{:keys [pool] :as cfg} {:keys [profile-id thread-id] :as params}]
[{: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-read-permissions! conn profile-id (:file-id thread))
(files/check-comment-permissions! conn profile-id (:file-id thread) share-id)
(retrieve-comments conn thread-id))))
(def sql:comments
@ -153,3 +157,40 @@
[conn thread-id]
(->> (db/exec! conn [sql:comments thread-id])
(into [] (map decode-row))))
;; file-comments-users
(declare retrieve-file-comments-users)
(s/def ::file-id ::us/uuid)
(s/def ::share-id (s/nilable ::us/uuid))
(s/def ::file-comments-users
(s/keys :req-un [::profile-id ::file-id]
:opt-un [::share-id]))
(sv/defmethod ::file-comments-users
[{: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]))

View file

@ -98,7 +98,9 @@
(some? perms) perms
(some? ldata) {:type :share-link
:can-read true
:flags (:flags ldata)}))))
:is-logged (some? profile-id)
:who-comment (:who-comment ldata)
:who-inspect (:who-inspect ldata)}))))
(def has-edit-permissions?
(perms/make-edition-predicate-fn get-permissions))
@ -106,12 +108,26 @@
(def has-read-permissions?
(perms/make-read-predicate-fn get-permissions))
(def has-comment-permissions?
(perms/make-comment-predicate-fn get-permissions))
(def check-edition-permissions!
(perms/make-check-fn has-edit-permissions?))
(def check-read-permissions!
(perms/make-check-fn has-read-permissions?))
;; A user has comment permissions if she has read permissions, or comment permissions
(defn check-comment-permissions!
[conn profile-id file-id share-id]
(let [can-read (has-read-permissions? conn profile-id file-id)
can-comment (has-comment-permissions? conn profile-id file-id share-id)
]
(when-not (or can-read can-comment)
(ex/raise :type :not-found
:code :object-not-found
:hint "not found"))))
;; --- Query: Files search
;; TODO: this query need to a good refactor

View file

@ -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.queries.files :as files]
[app.rpc.queries.share-link :as slnk]
[app.rpc.queries.teams :as teams]
[app.rpc.queries.share-link :as slnk]
[app.util.services :as sv]
[clojure.spec.alpha :as s]
[promesa.core :as p]))
@ -23,11 +23,11 @@
(db/get-by-id pool :project id {:columns [:id :name :team-id]}))
(defn- retrieve-bundle
[{:keys [pool] :as cfg} file-id]
[{:keys [pool] :as cfg} file-id profile-id]
(p/let [file (files/retrieve-file cfg file-id)
project (retrieve-project pool (:project-id file))
libs (files/retrieve-file-libraries cfg false file-id)
users (teams/retrieve-users pool (:team-id project))
users (comments/retrieve-file-comments-users pool file-id profile-id)
links (->> (db/query pool :share-link {:file-id file-id})
(mapv slnk/decode-share-link-row))
@ -54,7 +54,7 @@
(p/let [slink (slnk/retrieve-share-link pool file-id share-id)
perms (files/get-permissions pool profile-id file-id share-id)
thumbs (files/retrieve-object-thumbnails cfg file-id)
bundle (p/-> (retrieve-bundle cfg file-id)
bundle (p/-> (retrieve-bundle cfg file-id profile-id)
(assoc :permissions perms)
(assoc-in [:file :thumbnails] thumbs))]