mirror of
https://github.com/penpot/penpot.git
synced 2025-05-17 20:26:10 +02:00
✨ Move projects queries and mutations to commands
This commit is contained in:
parent
dc77c6b655
commit
dba7a9d424
14 changed files with 311 additions and 137 deletions
|
@ -339,6 +339,7 @@
|
||||||
'app.rpc.commands.management
|
'app.rpc.commands.management
|
||||||
'app.rpc.commands.media
|
'app.rpc.commands.media
|
||||||
'app.rpc.commands.profile
|
'app.rpc.commands.profile
|
||||||
|
'app.rpc.commands.projects
|
||||||
'app.rpc.commands.search
|
'app.rpc.commands.search
|
||||||
'app.rpc.commands.teams
|
'app.rpc.commands.teams
|
||||||
'app.rpc.commands.verify-token
|
'app.rpc.commands.verify-token
|
||||||
|
@ -356,8 +357,7 @@
|
||||||
::sto/storage
|
::sto/storage
|
||||||
::mtx/metrics
|
::mtx/metrics
|
||||||
::main/props
|
::main/props
|
||||||
::wrk/executor
|
::wrk/executor]
|
||||||
]
|
|
||||||
:opt [::climit
|
:opt [::climit
|
||||||
::rlimit]
|
::rlimit]
|
||||||
:req-un [::db/pool]))
|
:req-un [::db/pool]))
|
||||||
|
|
|
@ -21,9 +21,9 @@
|
||||||
[app.media :as media]
|
[app.media :as media]
|
||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.rpc.commands.files :as files]
|
[app.rpc.commands.files :as files]
|
||||||
|
[app.rpc.commands.projects :as projects]
|
||||||
[app.rpc.doc :as-alias doc]
|
[app.rpc.doc :as-alias doc]
|
||||||
[app.rpc.helpers :as rph]
|
[app.rpc.helpers :as rph]
|
||||||
[app.rpc.queries.projects :as projects]
|
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.storage.tmp :as tmp]
|
[app.storage.tmp :as tmp]
|
||||||
[app.tasks.file-gc]
|
[app.tasks.file-gc]
|
||||||
|
|
|
@ -22,12 +22,12 @@
|
||||||
[app.loggers.webhooks :as-alias webhooks]
|
[app.loggers.webhooks :as-alias webhooks]
|
||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.rpc.commands.files.thumbnails :as-alias thumbs]
|
[app.rpc.commands.files.thumbnails :as-alias thumbs]
|
||||||
|
[app.rpc.commands.projects :as projects]
|
||||||
[app.rpc.commands.teams :as teams]
|
[app.rpc.commands.teams :as teams]
|
||||||
[app.rpc.cond :as-alias cond]
|
[app.rpc.cond :as-alias cond]
|
||||||
[app.rpc.doc :as-alias doc]
|
[app.rpc.doc :as-alias doc]
|
||||||
[app.rpc.helpers :as rph]
|
[app.rpc.helpers :as rph]
|
||||||
[app.rpc.permissions :as perms]
|
[app.rpc.permissions :as perms]
|
||||||
[app.rpc.queries.projects :as projects]
|
|
||||||
[app.rpc.queries.share-link :refer [retrieve-share-link]]
|
[app.rpc.queries.share-link :refer [retrieve-share-link]]
|
||||||
[app.util.blob :as blob]
|
[app.util.blob :as blob]
|
||||||
[app.util.pointer-map :as pmap]
|
[app.util.pointer-map :as pmap]
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
[app.loggers.webhooks :as-alias webhooks]
|
[app.loggers.webhooks :as-alias webhooks]
|
||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.rpc.commands.files :as files]
|
[app.rpc.commands.files :as files]
|
||||||
|
[app.rpc.commands.projects :as projects]
|
||||||
[app.rpc.doc :as-alias doc]
|
[app.rpc.doc :as-alias doc]
|
||||||
[app.rpc.permissions :as perms]
|
[app.rpc.permissions :as perms]
|
||||||
[app.rpc.queries.projects :as proj]
|
|
||||||
[app.rpc.quotes :as quotes]
|
[app.rpc.quotes :as quotes]
|
||||||
[app.util.blob :as blob]
|
[app.util.blob :as blob]
|
||||||
[app.util.objects-map :as omap]
|
[app.util.objects-map :as omap]
|
||||||
|
@ -82,7 +82,7 @@
|
||||||
::webhooks/event? true}
|
::webhooks/event? true}
|
||||||
[{:keys [pool] :as cfg} {:keys [::rpc/profile-id project-id] :as params}]
|
[{:keys [pool] :as cfg} {:keys [::rpc/profile-id project-id] :as params}]
|
||||||
(db/with-atomic [conn pool]
|
(db/with-atomic [conn pool]
|
||||||
(proj/check-edition-permissions! conn profile-id project-id)
|
(projects/check-edition-permissions! conn profile-id project-id)
|
||||||
(let [team-id (files/get-team-id conn project-id)
|
(let [team-id (files/get-team-id conn project-id)
|
||||||
params (assoc params :profile-id profile-id)]
|
params (assoc params :profile-id profile-id)]
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
[app.rpc.commands.files :as files]
|
[app.rpc.commands.files :as files]
|
||||||
[app.rpc.commands.files-create :refer [create-file]]
|
[app.rpc.commands.files-create :refer [create-file]]
|
||||||
[app.rpc.commands.files-update :as-alias files.update]
|
[app.rpc.commands.files-update :as-alias files.update]
|
||||||
|
[app.rpc.commands.projects :as projects]
|
||||||
[app.rpc.doc :as-alias doc]
|
[app.rpc.doc :as-alias doc]
|
||||||
[app.rpc.queries.projects :as proj]
|
|
||||||
[app.util.blob :as blob]
|
[app.util.blob :as blob]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
[app.util.time :as dt]
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
{::doc/added "1.17"}
|
{::doc/added "1.17"}
|
||||||
[{:keys [pool] :as cfg} {:keys [::rpc/profile-id project-id] :as params}]
|
[{:keys [pool] :as cfg} {:keys [::rpc/profile-id project-id] :as params}]
|
||||||
(db/with-atomic [conn pool]
|
(db/with-atomic [conn pool]
|
||||||
(proj/check-edition-permissions! conn profile-id project-id)
|
(projects/check-edition-permissions! conn profile-id project-id)
|
||||||
(create-file conn (assoc params :profile-id profile-id :deleted-at (dt/in-future {:days 1})))))
|
(create-file conn (assoc params :profile-id profile-id :deleted-at (dt/in-future {:days 1})))))
|
||||||
|
|
||||||
;; --- MUTATION COMMAND: update-temp-file
|
;; --- MUTATION COMMAND: update-temp-file
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.rpc.commands.binfile :as binfile]
|
[app.rpc.commands.binfile :as binfile]
|
||||||
[app.rpc.commands.files :as files]
|
[app.rpc.commands.files :as files]
|
||||||
|
[app.rpc.commands.projects :as proj]
|
||||||
[app.rpc.commands.teams :as teams :refer [create-project-role create-project]]
|
[app.rpc.commands.teams :as teams :refer [create-project-role create-project]]
|
||||||
[app.rpc.doc :as-alias doc]
|
[app.rpc.doc :as-alias doc]
|
||||||
[app.rpc.queries.projects :as proj]
|
|
||||||
[app.util.blob :as blob]
|
[app.util.blob :as blob]
|
||||||
[app.util.pointer-map :as pmap]
|
[app.util.pointer-map :as pmap]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
|
|
268
backend/src/app/rpc/commands/projects.clj
Normal file
268
backend/src/app/rpc/commands/projects.clj
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
;; 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) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.rpc.commands.projects
|
||||||
|
(:require
|
||||||
|
[app.common.spec :as us]
|
||||||
|
[app.db :as db]
|
||||||
|
[app.loggers.audit :as-alias audit]
|
||||||
|
[app.loggers.webhooks :as webhooks]
|
||||||
|
[app.rpc :as-alias rpc]
|
||||||
|
[app.rpc.commands.teams :as teams]
|
||||||
|
[app.rpc.doc :as-alias doc]
|
||||||
|
[app.rpc.helpers :as rph]
|
||||||
|
[app.rpc.permissions :as perms]
|
||||||
|
[app.rpc.quotes :as quotes]
|
||||||
|
[app.util.services :as sv]
|
||||||
|
[app.util.time :as dt]
|
||||||
|
[clojure.spec.alpha :as s]))
|
||||||
|
|
||||||
|
(s/def ::id ::us/uuid)
|
||||||
|
(s/def ::name ::us/string)
|
||||||
|
|
||||||
|
;; --- Check Project Permissions
|
||||||
|
|
||||||
|
(def ^:private sql:project-permissions
|
||||||
|
"select tpr.is_owner,
|
||||||
|
tpr.is_admin,
|
||||||
|
tpr.can_edit
|
||||||
|
from team_profile_rel as tpr
|
||||||
|
inner join project as p on (p.team_id = tpr.team_id)
|
||||||
|
where p.id = ?
|
||||||
|
and tpr.profile_id = ?
|
||||||
|
union all
|
||||||
|
select ppr.is_owner,
|
||||||
|
ppr.is_admin,
|
||||||
|
ppr.can_edit
|
||||||
|
from project_profile_rel as ppr
|
||||||
|
where ppr.project_id = ?
|
||||||
|
and ppr.profile_id = ?")
|
||||||
|
|
||||||
|
(defn- get-permissions
|
||||||
|
[conn profile-id project-id]
|
||||||
|
(let [rows (db/exec! conn [sql:project-permissions
|
||||||
|
project-id profile-id
|
||||||
|
project-id profile-id])
|
||||||
|
is-owner (boolean (some :is-owner rows))
|
||||||
|
is-admin (boolean (some :is-admin rows))
|
||||||
|
can-edit (boolean (some :can-edit rows))]
|
||||||
|
(when (seq rows)
|
||||||
|
{:is-owner is-owner
|
||||||
|
:is-admin (or is-owner is-admin)
|
||||||
|
:can-edit (or is-owner is-admin can-edit)
|
||||||
|
:can-read true})))
|
||||||
|
|
||||||
|
(def has-edit-permissions?
|
||||||
|
(perms/make-edition-predicate-fn get-permissions))
|
||||||
|
|
||||||
|
(def has-read-permissions?
|
||||||
|
(perms/make-read-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?))
|
||||||
|
|
||||||
|
;; --- QUERY: Get projects
|
||||||
|
|
||||||
|
(declare get-projects)
|
||||||
|
|
||||||
|
(s/def ::team-id ::us/uuid)
|
||||||
|
(s/def ::get-projects
|
||||||
|
(s/keys :req [::rpc/profile-id]
|
||||||
|
:req-un [::team-id]))
|
||||||
|
|
||||||
|
(sv/defmethod ::get-projects
|
||||||
|
{::doc/added "1.18"}
|
||||||
|
[{:keys [::db/pool]} {:keys [::rpc/profile-id team-id]}]
|
||||||
|
(with-open [conn (db/open pool)]
|
||||||
|
(teams/check-read-permissions! conn profile-id team-id)
|
||||||
|
(get-projects conn profile-id team-id)))
|
||||||
|
|
||||||
|
(def sql:projects
|
||||||
|
"select p.*,
|
||||||
|
coalesce(tpp.is_pinned, false) as is_pinned,
|
||||||
|
(select count(*) from file as f
|
||||||
|
where f.project_id = p.id
|
||||||
|
and deleted_at is null) as count
|
||||||
|
from project as p
|
||||||
|
inner join team as t on (t.id = p.team_id)
|
||||||
|
left join team_project_profile_rel as tpp
|
||||||
|
on (tpp.project_id = p.id and
|
||||||
|
tpp.team_id = p.team_id and
|
||||||
|
tpp.profile_id = ?)
|
||||||
|
where p.team_id = ?
|
||||||
|
and p.deleted_at is null
|
||||||
|
and t.deleted_at is null
|
||||||
|
order by p.modified_at desc")
|
||||||
|
|
||||||
|
(defn get-projects
|
||||||
|
[conn profile-id team-id]
|
||||||
|
(db/exec! conn [sql:projects profile-id team-id]))
|
||||||
|
|
||||||
|
;; --- QUERY: Get all projects
|
||||||
|
|
||||||
|
(declare get-all-projects)
|
||||||
|
|
||||||
|
(s/def ::get-all-projects
|
||||||
|
(s/keys :req [::rpc/profile-id]))
|
||||||
|
|
||||||
|
(sv/defmethod ::get-all-projects
|
||||||
|
{::doc/added "1.18"}
|
||||||
|
[{:keys [::db/pool]} {:keys [::rpc/profile-id]}]
|
||||||
|
(with-open [conn (db/open pool)]
|
||||||
|
(get-all-projects conn profile-id)))
|
||||||
|
|
||||||
|
(def sql:all-projects
|
||||||
|
"select p1.*, t.name as team_name, t.is_default as is_default_team
|
||||||
|
from project as p1
|
||||||
|
inner join team as t on (t.id = p1.team_id)
|
||||||
|
where t.id in (select team_id
|
||||||
|
from team_profile_rel as tpr
|
||||||
|
where tpr.profile_id = ?
|
||||||
|
and (tpr.can_edit = true or
|
||||||
|
tpr.is_owner = true or
|
||||||
|
tpr.is_admin = true))
|
||||||
|
and t.deleted_at is null
|
||||||
|
and p1.deleted_at is null
|
||||||
|
union
|
||||||
|
select p2.*, t.name as team_name, t.is_default as is_default_team
|
||||||
|
from project as p2
|
||||||
|
inner join team as t on (t.id = p2.team_id)
|
||||||
|
where p2.id in (select project_id
|
||||||
|
from project_profile_rel as ppr
|
||||||
|
where ppr.profile_id = ?
|
||||||
|
and (ppr.can_edit = true or
|
||||||
|
ppr.is_owner = true or
|
||||||
|
ppr.is_admin = true))
|
||||||
|
and t.deleted_at is null
|
||||||
|
and p2.deleted_at is null
|
||||||
|
order by team_name, name;")
|
||||||
|
|
||||||
|
(defn get-all-projects
|
||||||
|
[conn profile-id]
|
||||||
|
(db/exec! conn [sql:all-projects profile-id profile-id]))
|
||||||
|
|
||||||
|
|
||||||
|
;; --- QUERY: Get project
|
||||||
|
|
||||||
|
(s/def ::get-project
|
||||||
|
(s/keys :req [::rpc/profile-id]
|
||||||
|
:req-un [::id]))
|
||||||
|
|
||||||
|
(sv/defmethod ::get-project
|
||||||
|
{::doc/added "1.18"}
|
||||||
|
[{:keys [::db/pool]} {:keys [::rpc/profile-id id]}]
|
||||||
|
(with-open [conn (db/open pool)]
|
||||||
|
(let [project (db/get-by-id conn :project id)]
|
||||||
|
(check-read-permissions! conn profile-id id)
|
||||||
|
project)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;; --- MUTATION: Create Project
|
||||||
|
|
||||||
|
(s/def ::create-project
|
||||||
|
(s/keys :req [::rpc/profile-id]
|
||||||
|
:req-un [::team-id ::name]
|
||||||
|
:opt-un [::id]))
|
||||||
|
|
||||||
|
(sv/defmethod ::create-project
|
||||||
|
{::doc/added "1.18"
|
||||||
|
::webhooks/event? true}
|
||||||
|
[{:keys [pool] :as cfg} {:keys [::rpc/profile-id team-id] :as params}]
|
||||||
|
(db/with-atomic [conn pool]
|
||||||
|
(teams/check-edition-permissions! conn profile-id team-id)
|
||||||
|
(quotes/check-quote! conn {::quotes/id ::quotes/projects-per-team
|
||||||
|
::quotes/profile-id profile-id
|
||||||
|
::quotes/team-id team-id})
|
||||||
|
|
||||||
|
(let [params (assoc params :profile-id profile-id)
|
||||||
|
project (teams/create-project conn params)]
|
||||||
|
(teams/create-project-role conn profile-id (:id project) :owner)
|
||||||
|
(db/insert! conn :team-project-profile-rel
|
||||||
|
{:project-id (:id project)
|
||||||
|
:profile-id profile-id
|
||||||
|
:team-id team-id
|
||||||
|
:is-pinned true})
|
||||||
|
(assoc project :is-pinned true))))
|
||||||
|
|
||||||
|
|
||||||
|
;; --- MUTATION: Toggle Project Pin
|
||||||
|
|
||||||
|
(def ^:private
|
||||||
|
sql:update-project-pin
|
||||||
|
"insert into team_project_profile_rel (team_id, project_id, profile_id, is_pinned)
|
||||||
|
values (?, ?, ?, ?)
|
||||||
|
on conflict (team_id, project_id, profile_id)
|
||||||
|
do update set is_pinned=?")
|
||||||
|
|
||||||
|
(s/def ::is-pinned ::us/boolean)
|
||||||
|
(s/def ::project-id ::us/uuid)
|
||||||
|
(s/def ::update-project-pin
|
||||||
|
(s/keys :req [::rpc/profile-id]
|
||||||
|
:req-un [::id ::team-id ::is-pinned]))
|
||||||
|
|
||||||
|
(sv/defmethod ::update-project-pin
|
||||||
|
{::doc/added "1.18"
|
||||||
|
::webhooks/batch-timeout (dt/duration "5s")
|
||||||
|
::webhooks/batch-key (webhooks/key-fn ::rpc/profile-id :id)
|
||||||
|
::webhooks/event? true}
|
||||||
|
[{:keys [pool] :as cfg} {:keys [::rpc/profile-id id team-id is-pinned] :as params}]
|
||||||
|
(db/with-atomic [conn pool]
|
||||||
|
(check-edition-permissions! conn profile-id id)
|
||||||
|
(db/exec-one! conn [sql:update-project-pin team-id id profile-id is-pinned is-pinned])
|
||||||
|
nil))
|
||||||
|
|
||||||
|
;; --- MUTATION: Rename Project
|
||||||
|
|
||||||
|
(declare rename-project)
|
||||||
|
|
||||||
|
(s/def ::rename-project
|
||||||
|
(s/keys :req [::rpc/profile-id]
|
||||||
|
:req-un [::name ::id]))
|
||||||
|
|
||||||
|
(sv/defmethod ::rename-project
|
||||||
|
{::doc/added "1.18"
|
||||||
|
::webhooks/event? true}
|
||||||
|
[{:keys [pool] :as cfg} {:keys [::rpc/profile-id id name] :as params}]
|
||||||
|
(db/with-atomic [conn pool]
|
||||||
|
(check-edition-permissions! conn profile-id id)
|
||||||
|
(let [project (db/get-by-id conn :project id ::db/for-update? true)]
|
||||||
|
(db/update! conn :project
|
||||||
|
{:name name}
|
||||||
|
{:id id})
|
||||||
|
(rph/with-meta (rph/wrap)
|
||||||
|
{::audit/props {:team-id (:team-id project)
|
||||||
|
:prev-name (:name project)}}))))
|
||||||
|
|
||||||
|
;; --- MUTATION: Delete Project
|
||||||
|
|
||||||
|
(s/def ::delete-project
|
||||||
|
(s/keys :req [::rpc/profile-id]
|
||||||
|
:req-un [::id]))
|
||||||
|
|
||||||
|
;; TODO: right now, we just don't allow delete default projects, in a
|
||||||
|
;; future we need to ensure raise a correct exception signaling that
|
||||||
|
;; this is not allowed.
|
||||||
|
|
||||||
|
(sv/defmethod ::delete-project
|
||||||
|
{::doc/added "1.18"
|
||||||
|
::webhooks/event? true}
|
||||||
|
[{:keys [pool] :as cfg} {:keys [::rpc/profile-id id] :as params}]
|
||||||
|
(db/with-atomic [conn pool]
|
||||||
|
(check-edition-permissions! conn profile-id id)
|
||||||
|
(let [project (db/update! conn :project
|
||||||
|
{:deleted-at (dt/now)}
|
||||||
|
{:id id :is-default false})]
|
||||||
|
(rph/with-meta (rph/wrap)
|
||||||
|
{::audit/props {:team-id (:team-id project)
|
||||||
|
:name (:name project)
|
||||||
|
:created-at (:created-at project)
|
||||||
|
:modified-at (:modified-at project)}}))))
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,10 @@
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.loggers.audit :as-alias audit]
|
[app.loggers.audit :as-alias audit]
|
||||||
[app.loggers.webhooks :as-alias webhooks]
|
[app.loggers.webhooks :as-alias webhooks]
|
||||||
|
[app.rpc.commands.projects :as projects]
|
||||||
[app.rpc.commands.teams :as teams]
|
[app.rpc.commands.teams :as teams]
|
||||||
[app.rpc.doc :as-alias doc]
|
[app.rpc.doc :as-alias doc]
|
||||||
[app.rpc.helpers :as rph]
|
[app.rpc.helpers :as rph]
|
||||||
[app.rpc.queries.projects :as proj]
|
|
||||||
[app.rpc.quotes :as quotes]
|
[app.rpc.quotes :as quotes]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
[app.util.time :as dt]
|
||||||
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
(sv/defmethod ::create-project
|
(sv/defmethod ::create-project
|
||||||
{::doc/added "1.0"
|
{::doc/added "1.0"
|
||||||
|
::doc/deprecated "1.18"
|
||||||
::webhooks/event? true}
|
::webhooks/event? true}
|
||||||
[{:keys [pool] :as cfg} {:keys [profile-id team-id] :as params}]
|
[{:keys [pool] :as cfg} {:keys [profile-id team-id] :as params}]
|
||||||
(db/with-atomic [conn pool]
|
(db/with-atomic [conn pool]
|
||||||
|
@ -70,12 +71,13 @@
|
||||||
|
|
||||||
(sv/defmethod ::update-project-pin
|
(sv/defmethod ::update-project-pin
|
||||||
{::doc/added "1.0"
|
{::doc/added "1.0"
|
||||||
|
::doc/deprecated "1.18"
|
||||||
::webhooks/batch-timeout (dt/duration "5s")
|
::webhooks/batch-timeout (dt/duration "5s")
|
||||||
::webhooks/batch-key :id
|
::webhooks/batch-key :id
|
||||||
::webhooks/event? true}
|
::webhooks/event? true}
|
||||||
[{:keys [pool] :as cfg} {:keys [id profile-id team-id is-pinned] :as params}]
|
[{:keys [pool] :as cfg} {:keys [id profile-id team-id is-pinned] :as params}]
|
||||||
(db/with-atomic [conn pool]
|
(db/with-atomic [conn pool]
|
||||||
(proj/check-edition-permissions! conn profile-id id)
|
(projects/check-edition-permissions! conn profile-id id)
|
||||||
(db/exec-one! conn [sql:update-project-pin team-id id profile-id is-pinned is-pinned])
|
(db/exec-one! conn [sql:update-project-pin team-id id profile-id is-pinned is-pinned])
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
|
@ -88,10 +90,11 @@
|
||||||
|
|
||||||
(sv/defmethod ::rename-project
|
(sv/defmethod ::rename-project
|
||||||
{::doc/added "1.0"
|
{::doc/added "1.0"
|
||||||
|
::doc/deprecated "1.18"
|
||||||
::webhooks/event? true}
|
::webhooks/event? true}
|
||||||
[{:keys [pool] :as cfg} {:keys [id profile-id name] :as params}]
|
[{:keys [pool] :as cfg} {:keys [id profile-id name] :as params}]
|
||||||
(db/with-atomic [conn pool]
|
(db/with-atomic [conn pool]
|
||||||
(proj/check-edition-permissions! conn profile-id id)
|
(projects/check-edition-permissions! conn profile-id id)
|
||||||
(let [project (db/get-by-id conn :project id)]
|
(let [project (db/get-by-id conn :project id)]
|
||||||
(db/update! conn :project
|
(db/update! conn :project
|
||||||
{:name name}
|
{:name name}
|
||||||
|
@ -112,10 +115,11 @@
|
||||||
|
|
||||||
(sv/defmethod ::delete-project
|
(sv/defmethod ::delete-project
|
||||||
{::doc/added "1.0"
|
{::doc/added "1.0"
|
||||||
|
::doc/deprecated "1.18"
|
||||||
::webhooks/event? true}
|
::webhooks/event? true}
|
||||||
[{:keys [pool] :as cfg} {:keys [id profile-id] :as params}]
|
[{:keys [pool] :as cfg} {:keys [id profile-id] :as params}]
|
||||||
(db/with-atomic [conn pool]
|
(db/with-atomic [conn pool]
|
||||||
(proj/check-edition-permissions! conn profile-id id)
|
(projects/check-edition-permissions! conn profile-id id)
|
||||||
(let [project (db/update! conn :project
|
(let [project (db/update! conn :project
|
||||||
{:deleted-at (dt/now)}
|
{:deleted-at (dt/now)}
|
||||||
{:id id :is-default false})]
|
{:id id :is-default false})]
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.rpc.commands.files :as files]
|
[app.rpc.commands.files :as files]
|
||||||
|
[app.rpc.commands.projects :as projects]
|
||||||
[app.rpc.commands.teams :as teams]
|
[app.rpc.commands.teams :as teams]
|
||||||
[app.rpc.doc :as-alias doc]
|
[app.rpc.doc :as-alias doc]
|
||||||
[app.rpc.queries.projects :as projects]
|
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[clojure.spec.alpha :as s]))
|
[clojure.spec.alpha :as s]))
|
||||||
|
|
||||||
|
|
|
@ -8,135 +8,39 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
|
[app.rpc.commands.projects :as projects]
|
||||||
[app.rpc.commands.teams :as teams]
|
[app.rpc.commands.teams :as teams]
|
||||||
[app.rpc.permissions :as perms]
|
[app.rpc.doc :as-alias doc]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[clojure.spec.alpha :as s]))
|
[clojure.spec.alpha :as s]))
|
||||||
|
|
||||||
;; --- Check Project Permissions
|
|
||||||
|
|
||||||
(def ^:private sql:project-permissions
|
|
||||||
"select tpr.is_owner,
|
|
||||||
tpr.is_admin,
|
|
||||||
tpr.can_edit
|
|
||||||
from team_profile_rel as tpr
|
|
||||||
inner join project as p on (p.team_id = tpr.team_id)
|
|
||||||
where p.id = ?
|
|
||||||
and tpr.profile_id = ?
|
|
||||||
union all
|
|
||||||
select ppr.is_owner,
|
|
||||||
ppr.is_admin,
|
|
||||||
ppr.can_edit
|
|
||||||
from project_profile_rel as ppr
|
|
||||||
where ppr.project_id = ?
|
|
||||||
and ppr.profile_id = ?")
|
|
||||||
|
|
||||||
(defn- get-permissions
|
|
||||||
[conn profile-id project-id]
|
|
||||||
(let [rows (db/exec! conn [sql:project-permissions
|
|
||||||
project-id profile-id
|
|
||||||
project-id profile-id])
|
|
||||||
is-owner (boolean (some :is-owner rows))
|
|
||||||
is-admin (boolean (some :is-admin rows))
|
|
||||||
can-edit (boolean (some :can-edit rows))]
|
|
||||||
(when (seq rows)
|
|
||||||
{:is-owner is-owner
|
|
||||||
:is-admin (or is-owner is-admin)
|
|
||||||
:can-edit (or is-owner is-admin can-edit)
|
|
||||||
:can-read true})))
|
|
||||||
|
|
||||||
(def has-edit-permissions?
|
|
||||||
(perms/make-edition-predicate-fn get-permissions))
|
|
||||||
|
|
||||||
(def has-read-permissions?
|
|
||||||
(perms/make-read-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?))
|
|
||||||
|
|
||||||
;; --- Query: Projects
|
;; --- Query: Projects
|
||||||
|
|
||||||
(declare retrieve-projects)
|
|
||||||
|
|
||||||
(s/def ::team-id ::us/uuid)
|
(s/def ::team-id ::us/uuid)
|
||||||
(s/def ::profile-id ::us/uuid)
|
(s/def ::profile-id ::us/uuid)
|
||||||
(s/def ::projects
|
(s/def ::projects
|
||||||
(s/keys :req-un [::profile-id ::team-id]))
|
(s/keys :req-un [::profile-id ::team-id]))
|
||||||
|
|
||||||
(sv/defmethod ::projects
|
(sv/defmethod ::projects
|
||||||
|
{::doc/added "1.0"
|
||||||
|
::doc/deprecated "1.18"}
|
||||||
[{:keys [pool]} {:keys [profile-id team-id]}]
|
[{:keys [pool]} {:keys [profile-id team-id]}]
|
||||||
(with-open [conn (db/open pool)]
|
(with-open [conn (db/open pool)]
|
||||||
(teams/check-read-permissions! conn profile-id team-id)
|
(teams/check-read-permissions! conn profile-id team-id)
|
||||||
(retrieve-projects conn profile-id team-id)))
|
(projects/get-projects conn profile-id team-id)))
|
||||||
|
|
||||||
(def sql:projects
|
|
||||||
"select p.*,
|
|
||||||
coalesce(tpp.is_pinned, false) as is_pinned,
|
|
||||||
(select count(*) from file as f
|
|
||||||
where f.project_id = p.id
|
|
||||||
and deleted_at is null) as count
|
|
||||||
from project as p
|
|
||||||
inner join team as t on (t.id = p.team_id)
|
|
||||||
left join team_project_profile_rel as tpp
|
|
||||||
on (tpp.project_id = p.id and
|
|
||||||
tpp.team_id = p.team_id and
|
|
||||||
tpp.profile_id = ?)
|
|
||||||
where p.team_id = ?
|
|
||||||
and p.deleted_at is null
|
|
||||||
and t.deleted_at is null
|
|
||||||
order by p.modified_at desc")
|
|
||||||
|
|
||||||
(defn retrieve-projects
|
|
||||||
[conn profile-id team-id]
|
|
||||||
(db/exec! conn [sql:projects profile-id team-id]))
|
|
||||||
|
|
||||||
|
|
||||||
;; --- Query: All projects
|
;; --- Query: All projects
|
||||||
|
|
||||||
(declare retrieve-all-projects)
|
|
||||||
|
|
||||||
(s/def ::profile-id ::us/uuid)
|
(s/def ::profile-id ::us/uuid)
|
||||||
(s/def ::all-projects
|
(s/def ::all-projects
|
||||||
(s/keys :req-un [::profile-id]))
|
(s/keys :req-un [::profile-id]))
|
||||||
|
|
||||||
(sv/defmethod ::all-projects
|
(sv/defmethod ::all-projects
|
||||||
|
{::doc/added "1.0"
|
||||||
|
::doc/deprecated "1.18"}
|
||||||
[{:keys [pool]} {:keys [profile-id]}]
|
[{:keys [pool]} {:keys [profile-id]}]
|
||||||
(with-open [conn (db/open pool)]
|
(with-open [conn (db/open pool)]
|
||||||
(retrieve-all-projects conn profile-id)))
|
(projects/get-all-projects conn profile-id)))
|
||||||
|
|
||||||
(def sql:all-projects
|
|
||||||
"select p1.*, t.name as team_name, t.is_default as is_default_team
|
|
||||||
from project as p1
|
|
||||||
inner join team as t on (t.id = p1.team_id)
|
|
||||||
where t.id in (select team_id
|
|
||||||
from team_profile_rel as tpr
|
|
||||||
where tpr.profile_id = ?
|
|
||||||
and (tpr.can_edit = true or
|
|
||||||
tpr.is_owner = true or
|
|
||||||
tpr.is_admin = true))
|
|
||||||
and t.deleted_at is null
|
|
||||||
and p1.deleted_at is null
|
|
||||||
union
|
|
||||||
select p2.*, t.name as team_name, t.is_default as is_default_team
|
|
||||||
from project as p2
|
|
||||||
inner join team as t on (t.id = p2.team_id)
|
|
||||||
where p2.id in (select project_id
|
|
||||||
from project_profile_rel as ppr
|
|
||||||
where ppr.profile_id = ?
|
|
||||||
and (ppr.can_edit = true or
|
|
||||||
ppr.is_owner = true or
|
|
||||||
ppr.is_admin = true))
|
|
||||||
and t.deleted_at is null
|
|
||||||
and p2.deleted_at is null
|
|
||||||
order by team_name, name;")
|
|
||||||
|
|
||||||
(defn retrieve-all-projects
|
|
||||||
[conn profile-id]
|
|
||||||
(db/exec! conn [sql:all-projects profile-id profile-id]))
|
|
||||||
|
|
||||||
|
|
||||||
;; --- Query: Project
|
;; --- Query: Project
|
||||||
|
|
||||||
|
@ -145,9 +49,11 @@
|
||||||
(s/keys :req-un [::profile-id ::id]))
|
(s/keys :req-un [::profile-id ::id]))
|
||||||
|
|
||||||
(sv/defmethod ::project
|
(sv/defmethod ::project
|
||||||
|
{::doc/added "1.0"
|
||||||
|
::doc/deprecated "1.18"}
|
||||||
[{:keys [pool]} {:keys [profile-id id]}]
|
[{:keys [pool]} {:keys [profile-id id]}]
|
||||||
(with-open [conn (db/open pool)]
|
(with-open [conn (db/open pool)]
|
||||||
(let [project (db/get-by-id conn :project id)]
|
(let [project (db/get-by-id conn :project id)]
|
||||||
(check-read-permissions! conn profile-id id)
|
(projects/check-read-permissions! conn profile-id id)
|
||||||
project)))
|
project)))
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.http :as http]
|
[app.http :as http]
|
||||||
|
[app.rpc :as-alias rpc]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[backend-tests.helpers :as th]
|
[backend-tests.helpers :as th]
|
||||||
[clojure.test :as t]
|
[clojure.test :as t]
|
||||||
|
@ -31,14 +32,14 @@
|
||||||
io/read-as-bytes)
|
io/read-as-bytes)
|
||||||
|
|
||||||
params {::th/type :create-font-variant
|
params {::th/type :create-font-variant
|
||||||
:profile-id (:id prof)
|
::rpc/profile-id (:id prof)
|
||||||
:team-id team-id
|
:team-id team-id
|
||||||
:font-id font-id
|
:font-id font-id
|
||||||
:font-family "somefont"
|
:font-family "somefont"
|
||||||
:font-weight 400
|
:font-weight 400
|
||||||
:font-style "normal"
|
:font-style "normal"
|
||||||
:data {"font/ttf" ttfdata}}
|
:data {"font/ttf" ttfdata}}
|
||||||
out (th/mutation! params)]
|
out (th/command! params)]
|
||||||
|
|
||||||
(t/is (= 1 (:call-count @mock)))
|
(t/is (= 1 (:call-count @mock)))
|
||||||
|
|
||||||
|
@ -68,14 +69,14 @@
|
||||||
io/read-as-bytes)
|
io/read-as-bytes)
|
||||||
|
|
||||||
params {::th/type :create-font-variant
|
params {::th/type :create-font-variant
|
||||||
:profile-id (:id prof)
|
::rpc/profile-id (:id prof)
|
||||||
:team-id team-id
|
:team-id team-id
|
||||||
:font-id font-id
|
:font-id font-id
|
||||||
:font-family "somefont"
|
:font-family "somefont"
|
||||||
:font-weight 400
|
:font-weight 400
|
||||||
:font-style "normal"
|
:font-style "normal"
|
||||||
:data {"font/woff" data}}
|
:data {"font/woff" data}}
|
||||||
out (th/mutation! params)]
|
out (th/command! params)]
|
||||||
|
|
||||||
;; (th/print-result! out)
|
;; (th/print-result! out)
|
||||||
(t/is (nil? (:error out)))
|
(t/is (nil? (:error out)))
|
||||||
|
@ -91,8 +92,3 @@
|
||||||
:font-family
|
:font-family
|
||||||
:font-weight
|
:font-weight
|
||||||
:font-style))))
|
:font-style))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -185,7 +185,7 @@
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [team-id (:current-team-id state)]
|
(let [team-id (:current-team-id state)]
|
||||||
(->> (rp/query! :projects {:team-id team-id})
|
(->> (rp/cmd! :get-projects {:team-id team-id})
|
||||||
(rx/map projects-fetched))))))
|
(rx/map projects-fetched))))))
|
||||||
|
|
||||||
;; --- EVENT: search
|
;; --- EVENT: search
|
||||||
|
@ -671,7 +671,7 @@
|
||||||
{:keys [on-success on-error]
|
{:keys [on-success on-error]
|
||||||
:or {on-success identity
|
:or {on-success identity
|
||||||
on-error rx/throw}} (meta params)]
|
on-error rx/throw}} (meta params)]
|
||||||
(->> (rp/mutation! :create-project params)
|
(->> (rp/cmd! :create-project params)
|
||||||
(rx/tap on-success)
|
(rx/tap on-success)
|
||||||
(rx/map project-created)
|
(rx/map project-created)
|
||||||
(rx/catch on-error))))))
|
(rx/catch on-error))))))
|
||||||
|
@ -733,7 +733,7 @@
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [project (get-in state [:dashboard-projects id])
|
(let [project (get-in state [:dashboard-projects id])
|
||||||
params (select-keys project [:id :is-pinned :team-id])]
|
params (select-keys project [:id :is-pinned :team-id])]
|
||||||
(->> (rp/mutation :update-project-pin params)
|
(->> (rp/cmd! :update-project-pin params)
|
||||||
(rx/ignore))))))
|
(rx/ignore))))))
|
||||||
|
|
||||||
;; --- EVENT: rename-project
|
;; --- EVENT: rename-project
|
||||||
|
@ -751,7 +751,7 @@
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(let [params {:id id :name name}]
|
(let [params {:id id :name name}]
|
||||||
(->> (rp/mutation :rename-project params)
|
(->> (rp/cmd! :rename-project params)
|
||||||
(rx/ignore))))))
|
(rx/ignore))))))
|
||||||
|
|
||||||
;; --- EVENT: delete-project
|
;; --- EVENT: delete-project
|
||||||
|
@ -766,7 +766,7 @@
|
||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(->> (rp/mutation :delete-project {:id id})
|
(->> (rp/cmd! :delete-project {:id id})
|
||||||
(rx/ignore)))))
|
(rx/ignore)))))
|
||||||
|
|
||||||
;; --- EVENT: delete-file
|
;; --- EVENT: delete-file
|
||||||
|
@ -1077,7 +1077,7 @@
|
||||||
action-name (if in-project? :create-file :create-project)
|
action-name (if in-project? :create-file :create-project)
|
||||||
action (if in-project? file-created project-created)]
|
action (if in-project? file-created project-created)]
|
||||||
|
|
||||||
(->> (rp/mutation! action-name params)
|
(->> (rp/cmd! action-name params)
|
||||||
(rx/map action))))))
|
(rx/map action))))))
|
||||||
|
|
||||||
(defn open-selected-file
|
(defn open-selected-file
|
||||||
|
|
|
@ -267,7 +267,7 @@
|
||||||
|
|
||||||
(->> (rx/zip (rp/cmd! :get-file {:id file-id :features features})
|
(->> (rx/zip (rp/cmd! :get-file {:id file-id :features features})
|
||||||
(rp/cmd! :get-file-object-thumbnails {:file-id file-id})
|
(rp/cmd! :get-file-object-thumbnails {:file-id file-id})
|
||||||
(rp/query! :project {:id project-id})
|
(rp/cmd! :get-project {:id project-id})
|
||||||
(rp/cmd! :get-team-users {:file-id file-id})
|
(rp/cmd! :get-team-users {:file-id file-id})
|
||||||
(rp/cmd! :get-profiles-for-file-comments {:file-id file-id :share-id share-id}))
|
(rp/cmd! :get-profiles-for-file-comments {:file-id file-id :share-id share-id}))
|
||||||
(rx/take 1)
|
(rx/take 1)
|
||||||
|
@ -1564,7 +1564,7 @@
|
||||||
(into (d/ordered-set)))
|
(into (d/ordered-set)))
|
||||||
undo-id (js/Symbol)]
|
undo-id (js/Symbol)]
|
||||||
|
|
||||||
(rx/of (dwu/start-undo-transaction undo-id)
|
(rx/of (dwu/start-undo-transaction undo-id)
|
||||||
(dch/commit-changes changes)
|
(dch/commit-changes changes)
|
||||||
(dws/select-shapes selected)
|
(dws/select-shapes selected)
|
||||||
(ptk/data-event :layout/update [frame-id])
|
(ptk/data-event :layout/update [frame-id])
|
||||||
|
|
|
@ -207,7 +207,7 @@
|
||||||
(mf/deps show?)
|
(mf/deps show?)
|
||||||
(fn []
|
(fn []
|
||||||
(when show?
|
(when show?
|
||||||
(->> (rp/query! :all-projects)
|
(->> (rp/cmd! :get-all-projects)
|
||||||
(rx/map group-by-team)
|
(rx/map group-by-team)
|
||||||
(rx/subs #(when (mf/ref-val mounted-ref)
|
(rx/subs #(when (mf/ref-val mounted-ref)
|
||||||
(reset! teams %)))))))
|
(reset! teams %)))))))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue