mirror of
https://github.com/penpot/penpot.git
synced 2025-05-22 23:16:10 +02:00
The frontend-only features are now ignored from files and from teams and they do not autoassigns automatically to team and file on file creation or update operations.
148 lines
5.5 KiB
Clojure
148 lines
5.5 KiB
Clojure
;; 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.files-create
|
|
(:require
|
|
[app.common.data.macros :as dm]
|
|
[app.common.features :as cfeat]
|
|
[app.common.schema :as sm]
|
|
[app.common.types.file :as ctf]
|
|
[app.config :as cf]
|
|
[app.db :as db]
|
|
[app.features.fdata :as feat.fdata]
|
|
[app.loggers.audit :as-alias audit]
|
|
[app.loggers.webhooks :as-alias webhooks]
|
|
[app.rpc :as-alias rpc]
|
|
[app.rpc.commands.projects :as projects]
|
|
[app.rpc.commands.teams :as teams]
|
|
[app.rpc.doc :as-alias doc]
|
|
[app.rpc.permissions :as perms]
|
|
[app.rpc.quotes :as quotes]
|
|
[app.util.blob :as blob]
|
|
[app.util.pointer-map :as pmap]
|
|
[app.util.services :as sv]
|
|
[app.util.time :as dt]
|
|
[clojure.set :as set]))
|
|
|
|
(defn create-file-role!
|
|
[conn {:keys [file-id profile-id role]}]
|
|
(let [params {:file-id file-id
|
|
:profile-id profile-id}]
|
|
(->> (perms/assign-role-flags params role)
|
|
(db/insert! conn :file-profile-rel))))
|
|
|
|
(defn create-file
|
|
[{:keys [::db/conn] :as cfg}
|
|
{:keys [id name project-id is-shared revn
|
|
modified-at deleted-at create-page page-id
|
|
ignore-sync-until features]
|
|
:or {is-shared false revn 0 create-page true}
|
|
:as params}]
|
|
|
|
(dm/assert!
|
|
"expected a valid connection"
|
|
(db/connection? conn))
|
|
|
|
(binding [pmap/*tracked* (pmap/create-tracked)
|
|
cfeat/*current* features]
|
|
(let [file (ctf/make-file {:id id
|
|
:project-id project-id
|
|
:name name
|
|
:revn revn
|
|
:is-shared is-shared
|
|
:features features
|
|
:ignore-sync-until ignore-sync-until
|
|
:modified-at modified-at
|
|
:deleted-at deleted-at
|
|
:create-page create-page
|
|
:page-id page-id})
|
|
|
|
file (if (contains? features "fdata/objects-map")
|
|
(feat.fdata/enable-objects-map file)
|
|
file)
|
|
|
|
file (if (contains? features "fdata/pointer-map")
|
|
(feat.fdata/enable-pointer-map file)
|
|
file)]
|
|
|
|
(db/insert! conn :file
|
|
(-> file
|
|
(update :data blob/encode)
|
|
(update :features db/encode-pgarray conn "text"))
|
|
{::db/return-keys false})
|
|
|
|
(when (contains? features "fdata/pointer-map")
|
|
(feat.fdata/persist-pointers! cfg (:id file)))
|
|
|
|
(->> (assoc params :file-id (:id file) :role :owner)
|
|
(create-file-role! conn))
|
|
|
|
(db/update! conn :project
|
|
{:modified-at (dt/now)}
|
|
{:id project-id})
|
|
|
|
file)))
|
|
|
|
(def ^:private schema:create-file
|
|
[:map {:title "create-file"}
|
|
[:name [:string {:max 250}]]
|
|
[:project-id ::sm/uuid]
|
|
[:id {:optional true} ::sm/uuid]
|
|
[:is-shared {:optional true} ::sm/boolean]
|
|
[:features {:optional true} ::cfeat/features]])
|
|
|
|
(sv/defmethod ::create-file
|
|
{::doc/added "1.17"
|
|
::doc/module :files
|
|
::webhooks/event? true
|
|
::sm/params schema:create-file
|
|
::db/transaction true}
|
|
[{:keys [::db/conn] :as cfg} {:keys [::rpc/profile-id project-id] :as params}]
|
|
(projects/check-edition-permissions! conn profile-id project-id)
|
|
(let [team (teams/get-team conn
|
|
:profile-id profile-id
|
|
:project-id project-id)
|
|
team-id (:id team)
|
|
|
|
;; When we create files, we only need to respect the team
|
|
;; features, because some features can be enabled
|
|
;; globally, but the team is still not migrated properly.
|
|
features (-> (cfeat/get-team-enabled-features cf/flags team)
|
|
(cfeat/check-client-features! (:features params))
|
|
(set/difference cfeat/frontend-only-features))
|
|
|
|
;; We also include all no migration features declared by
|
|
;; client; that enables the ability to enable a runtime
|
|
;; feature on frontend and make it permanent on file
|
|
features (-> (:features params #{})
|
|
(set/intersection cfeat/no-migration-features)
|
|
(set/difference cfeat/frontend-only-features)
|
|
(set/union features))
|
|
|
|
params (-> params
|
|
(assoc :profile-id profile-id)
|
|
(assoc :features features))]
|
|
|
|
(quotes/check! cfg {::quotes/id ::quotes/files-per-project
|
|
::quotes/team-id team-id
|
|
::quotes/profile-id profile-id
|
|
::quotes/project-id project-id})
|
|
|
|
;; FIXME: IMPORTANT: this code can have race
|
|
;; conditions, because we have no locks for updating
|
|
;; team so, creating two files concurrently can lead
|
|
;; to lost team features updating
|
|
|
|
;; When newly computed features does not match exactly with
|
|
;; the features defined on team row, we update it.
|
|
(when (not= features (:features team))
|
|
(let [features (db/create-array conn "text" features)]
|
|
(db/update! conn :team
|
|
{:features features}
|
|
{:id team-id})))
|
|
|
|
(-> (create-file cfg params)
|
|
(vary-meta assoc ::audit/props {:team-id team-id}))))
|