mirror of
https://github.com/penpot/penpot.git
synced 2025-04-01 01:21:21 -05:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
025034cb71
21 changed files with 190 additions and 155 deletions
|
@ -12,9 +12,16 @@
|
||||||
|
|
||||||
## 2.1.1
|
## 2.1.1
|
||||||
|
|
||||||
|
### :sparkles: New features
|
||||||
|
|
||||||
|
- Consolidate templates new order and naming [Taiga #8392](https://tree.taiga.io/project/penpot/task/8392)
|
||||||
|
|
||||||
### :bug: Bugs fixed
|
### :bug: Bugs fixed
|
||||||
|
|
||||||
|
- Fix the “search” label in translations [Taiga #8402](https://tree.taiga.io/project/penpot/issue/8402)
|
||||||
- Fix pencil loader [Taiga #8348](https://tree.taiga.io/project/penpot/issue/8348)
|
- Fix pencil loader [Taiga #8348](https://tree.taiga.io/project/penpot/issue/8348)
|
||||||
|
- Fix several issues on the OIDC.
|
||||||
|
- Fix regression on the `email-verification` flag [Taiga #8398](https://tree.taiga.io/project/penpot/issue/8398)
|
||||||
|
|
||||||
## 2.1.0 - Things can only get better!
|
## 2.1.0 - Things can only get better!
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
[{:id "tutorial-for-beginners"
|
[{:id "wireframing-kit"
|
||||||
|
:name "Wireframe library"
|
||||||
|
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/wireframing-kit.penpot"}
|
||||||
|
{:id "prototype-examples"
|
||||||
|
:name "Prototipe template"
|
||||||
|
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/prototype-examples.penpot"}
|
||||||
|
{:id "plants-app"
|
||||||
|
:name "UI mockup example"
|
||||||
|
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Plants-app.penpot"}
|
||||||
|
{:id "penpot-design-system"
|
||||||
|
:name "Design system example"
|
||||||
|
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Penpot-Design-system.penpot"}
|
||||||
|
{:id "tutorial-for-beginners"
|
||||||
:name "Tutorial for beginners"
|
:name "Tutorial for beginners"
|
||||||
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/tutorial-for-beginners.penpot"}
|
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/tutorial-for-beginners.penpot"}
|
||||||
{:id "lucide-icons"
|
{:id "lucide-icons"
|
||||||
|
@ -7,12 +19,6 @@
|
||||||
{:id "font-awesome"
|
{:id "font-awesome"
|
||||||
:name "Font Awesome"
|
:name "Font Awesome"
|
||||||
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Font-Awesome.penpot"}
|
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Font-Awesome.penpot"}
|
||||||
{:id "plants-app"
|
|
||||||
:name "Plants app"
|
|
||||||
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Plants-app.penpot"}
|
|
||||||
{:id "wireframing-kit"
|
|
||||||
:name "Wireframing Kit"
|
|
||||||
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/wireframing-kit.penpot"}
|
|
||||||
{:id "black-white-mobile-templates"
|
{:id "black-white-mobile-templates"
|
||||||
:name "Black & White Mobile Templates"
|
:name "Black & White Mobile Templates"
|
||||||
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Black-White-Mobile-Templates.penpot"}
|
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Black-White-Mobile-Templates.penpot"}
|
||||||
|
@ -30,10 +36,4 @@
|
||||||
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Open-Color-Scheme.penpot"}
|
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Open-Color-Scheme.penpot"}
|
||||||
{:id "flex-layout-playground"
|
{:id "flex-layout-playground"
|
||||||
:name "Flex Layout Playground"
|
:name "Flex Layout Playground"
|
||||||
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Flex-Layout-Playground.penpot"}
|
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Flex-Layout-Playground.penpot"}]
|
||||||
{:id "prototype-examples"
|
|
||||||
:name "Prototipe template"
|
|
||||||
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/prototype-examples.penpot"}
|
|
||||||
{:id "penpot-design-system"
|
|
||||||
:name "Design system example"
|
|
||||||
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Penpot-Design-system.penpot"}]
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
[app.rpc.commands.profile :as profile]
|
[app.rpc.commands.profile :as profile]
|
||||||
[app.setup :as-alias setup]
|
[app.setup :as-alias setup]
|
||||||
[app.tokens :as tokens]
|
[app.tokens :as tokens]
|
||||||
|
[app.util.inet :as inet]
|
||||||
[app.util.json :as json]
|
[app.util.json :as json]
|
||||||
[app.util.time :as dt]
|
[app.util.time :as dt]
|
||||||
[buddy.sign.jwk :as jwk]
|
[buddy.sign.jwk :as jwk]
|
||||||
|
@ -571,10 +572,10 @@
|
||||||
props (audit/profile->props profile)
|
props (audit/profile->props profile)
|
||||||
context (d/without-nils {:external-session-id (:external-session-id info)})]
|
context (d/without-nils {:external-session-id (:external-session-id info)})]
|
||||||
|
|
||||||
(audit/submit! cfg {::audit/type "command"
|
(audit/submit! cfg {::audit/type "action"
|
||||||
::audit/name "login-with-oidc"
|
::audit/name "login-with-oidc"
|
||||||
::audit/profile-id (:id profile)
|
::audit/profile-id (:id profile)
|
||||||
::audit/ip-addr (audit/parse-client-ip request)
|
::audit/ip-addr (inet/parse-request request)
|
||||||
::audit/props props
|
::audit/props props
|
||||||
::audit/context context})
|
::audit/context context})
|
||||||
|
|
||||||
|
|
|
@ -21,28 +21,18 @@
|
||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.rpc.retry :as rtry]
|
[app.rpc.retry :as rtry]
|
||||||
[app.setup :as-alias setup]
|
[app.setup :as-alias setup]
|
||||||
|
[app.util.inet :as inet]
|
||||||
[app.util.services :as-alias sv]
|
[app.util.services :as-alias sv]
|
||||||
[app.util.time :as dt]
|
[app.util.time :as dt]
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[integrant.core :as ig]
|
[integrant.core :as ig]))
|
||||||
[ring.request :as rreq]))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; HELPERS
|
;; HELPERS
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(defn parse-client-ip
|
|
||||||
[request]
|
|
||||||
(let [ip-addr (or (some-> (rreq/get-header request "x-forwarded-for") (str/split ",") first)
|
|
||||||
(rreq/get-header request "x-real-ip")
|
|
||||||
(some-> (rreq/remote-addr request) str))
|
|
||||||
ip-addr (-> ip-addr
|
|
||||||
(str/split ":" 2)
|
|
||||||
(first))]
|
|
||||||
ip-addr))
|
|
||||||
|
|
||||||
(defn extract-utm-params
|
(defn extract-utm-params
|
||||||
"Extracts additional data from params and namespace them under
|
"Extracts additional data from params and namespace them under
|
||||||
`penpot` ns."
|
`penpot` ns."
|
||||||
|
@ -90,17 +80,20 @@
|
||||||
(remove #(contains? reserved-props (key %))))
|
(remove #(contains? reserved-props (key %))))
|
||||||
props))
|
props))
|
||||||
|
|
||||||
(defn params->context
|
(defn event-from-rpc-params
|
||||||
"Extract default context properties from RPC params object"
|
"Create a base event skeleton with pre-filled some important
|
||||||
|
data that can be extracted from RPC params object"
|
||||||
[params]
|
[params]
|
||||||
(d/without-nils
|
(let [context {:external-session-id (::rpc/external-session-id params)
|
||||||
{:external-session-id (::rpc/external-session-id params)
|
:external-event-origin (::rpc/external-event-origin params)
|
||||||
:event-origin (::rpc/external-event-origin params)
|
:triggered-by (::rpc/handler-name params)}]
|
||||||
:triggered-by (::rpc/handler-name params)}))
|
{::type "action"
|
||||||
|
::profile-id (::rpc/profile-id params)
|
||||||
|
::ip-addr (::rpc/ip-addr params)
|
||||||
|
::context (d/without-nils context)}))
|
||||||
|
|
||||||
;; --- SPECS
|
;; --- SPECS
|
||||||
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; COLLECTOR
|
;; COLLECTOR
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -167,14 +160,16 @@
|
||||||
(assoc :external-session-id session-id)
|
(assoc :external-session-id session-id)
|
||||||
(assoc :external-event-origin event-origin)
|
(assoc :external-event-origin event-origin)
|
||||||
(assoc :access-token-id (some-> token-id str))
|
(assoc :access-token-id (some-> token-id str))
|
||||||
(d/without-nils))]
|
(d/without-nils))
|
||||||
|
|
||||||
|
ip-addr (inet/parse-request request)]
|
||||||
|
|
||||||
{::type (or (::type resultm)
|
{::type (or (::type resultm)
|
||||||
(::rpc/type cfg))
|
(::rpc/type cfg))
|
||||||
::name (or (::name resultm)
|
::name (or (::name resultm)
|
||||||
(::sv/name mdata))
|
(::sv/name mdata))
|
||||||
::profile-id profile-id
|
::profile-id profile-id
|
||||||
::ip-addr (some-> request parse-client-ip)
|
::ip-addr ip-addr
|
||||||
::props props
|
::props props
|
||||||
::context context
|
::context context
|
||||||
|
|
||||||
|
@ -202,7 +197,7 @@
|
||||||
:name (::name event)
|
:name (::name event)
|
||||||
:type (::type event)
|
:type (::type event)
|
||||||
:profile-id (::profile-id event)
|
:profile-id (::profile-id event)
|
||||||
:ip-addr (::ip-addr event "0.0.0.0")
|
:ip-addr (::ip-addr event)
|
||||||
:context (::context event {})
|
:context (::context event {})
|
||||||
:props (::props event {})
|
:props (::props event {})
|
||||||
:source "backend"}
|
:source "backend"}
|
||||||
|
@ -246,8 +241,7 @@
|
||||||
(assoc :created-at tnow)
|
(assoc :created-at tnow)
|
||||||
(update :tracked-at #(or % tnow))
|
(update :tracked-at #(or % tnow))
|
||||||
(assoc :props {})
|
(assoc :props {})
|
||||||
(assoc :context {})
|
(assoc :context {}))]
|
||||||
(assoc :ip-addr "0.0.0.0"))]
|
|
||||||
(append-audit-entry! cfg params)))
|
(append-audit-entry! cfg params)))
|
||||||
|
|
||||||
(when (and (contains? cf/flags :webhooks)
|
(when (and (contains? cf/flags :webhooks)
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
[app.rpc.rlimit :as rlimit]
|
[app.rpc.rlimit :as rlimit]
|
||||||
[app.setup :as-alias setup]
|
[app.setup :as-alias setup]
|
||||||
[app.storage :as-alias sto]
|
[app.storage :as-alias sto]
|
||||||
|
[app.util.inet :as inet]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]
|
[app.util.time :as dt]
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
|
@ -81,7 +82,9 @@
|
||||||
(defn- get-external-event-origin
|
(defn- get-external-event-origin
|
||||||
[request]
|
[request]
|
||||||
(when-let [origin (rreq/get-header request "x-event-origin")]
|
(when-let [origin (rreq/get-header request "x-event-origin")]
|
||||||
(when-not (> (count origin) 256)
|
(when-not (or (> (count origin) 256)
|
||||||
|
(= origin "null")
|
||||||
|
(str/blank? origin))
|
||||||
origin)))
|
origin)))
|
||||||
|
|
||||||
(defn- rpc-handler
|
(defn- rpc-handler
|
||||||
|
@ -93,11 +96,13 @@
|
||||||
profile-id (or (::session/profile-id request)
|
profile-id (or (::session/profile-id request)
|
||||||
(::actoken/profile-id request))
|
(::actoken/profile-id request))
|
||||||
|
|
||||||
|
ip-addr (inet/parse-request request)
|
||||||
session-id (get-external-session-id request)
|
session-id (get-external-session-id request)
|
||||||
event-origin (get-external-event-origin request)
|
event-origin (get-external-event-origin request)
|
||||||
|
|
||||||
data (-> params
|
data (-> params
|
||||||
(assoc ::handler-name handler-name)
|
(assoc ::handler-name handler-name)
|
||||||
|
(assoc ::ip-addr ip-addr)
|
||||||
(assoc ::request-at (dt/now))
|
(assoc ::request-at (dt/now))
|
||||||
(assoc ::external-session-id session-id)
|
(assoc ::external-session-id session-id)
|
||||||
(assoc ::external-event-origin event-origin)
|
(assoc ::external-event-origin event-origin)
|
||||||
|
|
|
@ -14,11 +14,12 @@
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.db :as db]
|
[app.db :as db]
|
||||||
[app.http :as-alias http]
|
[app.http :as-alias http]
|
||||||
[app.loggers.audit :as audit]
|
[app.loggers.audit :as-alias audit]
|
||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.rpc.climit :as-alias climit]
|
[app.rpc.climit :as-alias climit]
|
||||||
[app.rpc.doc :as-alias doc]
|
[app.rpc.doc :as-alias doc]
|
||||||
[app.rpc.helpers :as rph]
|
[app.rpc.helpers :as rph]
|
||||||
|
[app.util.inet :as inet]
|
||||||
[app.util.services :as sv]
|
[app.util.services :as sv]
|
||||||
[app.util.time :as dt]))
|
[app.util.time :as dt]))
|
||||||
|
|
||||||
|
@ -61,7 +62,7 @@
|
||||||
(defn- handle-events
|
(defn- handle-events
|
||||||
[{:keys [::db/pool]} {:keys [::rpc/profile-id events] :as params}]
|
[{:keys [::db/pool]} {:keys [::rpc/profile-id events] :as params}]
|
||||||
(let [request (-> params meta ::http/request)
|
(let [request (-> params meta ::http/request)
|
||||||
ip-addr (audit/parse-client-ip request)
|
ip-addr (inet/parse-request request)
|
||||||
tnow (dt/now)
|
tnow (dt/now)
|
||||||
xform (comp
|
xform (comp
|
||||||
(map (fn [event]
|
(map (fn [event]
|
||||||
|
|
|
@ -340,7 +340,7 @@
|
||||||
|
|
||||||
profile (if-let [profile-id (:profile-id claims)]
|
profile (if-let [profile-id (:profile-id claims)]
|
||||||
(profile/get-profile conn profile-id)
|
(profile/get-profile conn profile-id)
|
||||||
(let [is-active (or (boolean (:is-active params))
|
(let [is-active (or (boolean (:is-active claims))
|
||||||
(not (contains? cf/flags :email-verification)))
|
(not (contains? cf/flags :email-verification)))
|
||||||
params (-> params
|
params (-> params
|
||||||
(assoc :is-active is-active)
|
(assoc :is-active is-active)
|
||||||
|
@ -348,6 +348,9 @@
|
||||||
(->> (create-profile! conn params)
|
(->> (create-profile! conn params)
|
||||||
(create-profile-rels! conn))))
|
(create-profile-rels! conn))))
|
||||||
|
|
||||||
|
;; When no profile-id comes on claims means a new register
|
||||||
|
created? (not (:profile-id claims))
|
||||||
|
|
||||||
invitation (when-let [token (:invitation-token params)]
|
invitation (when-let [token (:invitation-token params)]
|
||||||
(tokens/verify (::setup/props cfg) {:token token :iss :team-invitation}))
|
(tokens/verify (::setup/props cfg) {:token token :iss :team-invitation}))
|
||||||
|
|
||||||
|
@ -385,8 +388,8 @@
|
||||||
;; When a new user is created and it is already activated by
|
;; When a new user is created and it is already activated by
|
||||||
;; configuration or specified by OIDC, we just mark the profile
|
;; configuration or specified by OIDC, we just mark the profile
|
||||||
;; as logged-in
|
;; as logged-in
|
||||||
(not (:profile-id claims))
|
created?
|
||||||
(if (:is-active claims)
|
(if (:is-active profile)
|
||||||
(-> (profile/strip-private-attrs profile)
|
(-> (profile/strip-private-attrs profile)
|
||||||
(rph/with-transform (session/create-fn cfg (:id profile)))
|
(rph/with-transform (session/create-fn cfg (:id profile)))
|
||||||
(rph/with-meta
|
(rph/with-meta
|
||||||
|
|
|
@ -413,15 +413,13 @@
|
||||||
{:modified-at (dt/now)}
|
{:modified-at (dt/now)}
|
||||||
{:id project-id})
|
{:id project-id})
|
||||||
|
|
||||||
(let [props (audit/clean-props params)
|
(let [props (audit/clean-props params)]
|
||||||
context (audit/params->context params)]
|
|
||||||
(doseq [file-id result]
|
(doseq [file-id result]
|
||||||
(audit/submit! cfg
|
(let [props (assoc props :id file-id)
|
||||||
{::audit/type "action"
|
event (-> (audit/event-from-rpc-params params)
|
||||||
::audit/name "create-file"
|
(assoc ::audit/name "create-file")
|
||||||
::audit/profile-id profile-id
|
(assoc ::audit/props props))]
|
||||||
::audit/props (assoc props :id file-id)
|
(audit/submit! cfg event))))
|
||||||
::audit/context context})))
|
|
||||||
|
|
||||||
result))))
|
result))))
|
||||||
|
|
||||||
|
|
|
@ -787,18 +787,15 @@
|
||||||
(l/info :hint "invitation token" :token itoken))
|
(l/info :hint "invitation token" :token itoken))
|
||||||
|
|
||||||
|
|
||||||
(let [props (-> (dissoc tprops :profile-id)
|
(let [props (-> (dissoc tprops :profile-id)
|
||||||
(audit/clean-props))
|
(audit/clean-props))
|
||||||
context (audit/params->context params)]
|
evname (if updated?
|
||||||
|
"update-team-invitation"
|
||||||
(audit/submit! cfg
|
"create-team-invitation")
|
||||||
{::audit/type "action"
|
event (-> (audit/event-from-rpc-params params)
|
||||||
::audit/name (if updated?
|
(assoc ::audit/name evname)
|
||||||
"update-team-invitation"
|
(assoc ::audit/props props))]
|
||||||
"create-team-invitation")
|
(audit/submit! cfg event))
|
||||||
::audit/profile-id (:id profile)
|
|
||||||
::audit/props props
|
|
||||||
::audit/context context}))
|
|
||||||
|
|
||||||
(eml/send! {::eml/conn conn
|
(eml/send! {::eml/conn conn
|
||||||
::eml/factory eml/invite-to-team
|
::eml/factory eml/invite-to-team
|
||||||
|
@ -882,62 +879,51 @@
|
||||||
(sv/defmethod ::create-team-with-invitations
|
(sv/defmethod ::create-team-with-invitations
|
||||||
{::doc/added "1.17"
|
{::doc/added "1.17"
|
||||||
::sm/params schema:create-team-with-invitations}
|
::sm/params schema:create-team-with-invitations}
|
||||||
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id emails role name] :as params}]
|
[cfg {:keys [::rpc/profile-id emails role name] :as params}]
|
||||||
(db/with-atomic [conn pool]
|
|
||||||
|
|
||||||
(let [features (-> (cfeat/get-enabled-features cf/flags)
|
(db/tx-run! cfg
|
||||||
(cfeat/check-client-features! (:features params)))
|
(fn [{:keys [::db/conn] :as cfg}]
|
||||||
|
(let [features (-> (cfeat/get-enabled-features cf/flags)
|
||||||
|
(cfeat/check-client-features! (:features params)))
|
||||||
|
|
||||||
params (-> params
|
params (-> params
|
||||||
(assoc :profile-id profile-id)
|
(assoc :profile-id profile-id)
|
||||||
(assoc :features features))
|
(assoc :features features))
|
||||||
|
|
||||||
cfg (assoc cfg ::db/conn conn)
|
cfg (assoc cfg ::db/conn conn)
|
||||||
team (create-team cfg params)
|
team (create-team cfg params)
|
||||||
profile (db/get-by-id conn :profile profile-id)
|
profile (db/get-by-id conn :profile profile-id)
|
||||||
emails (into #{} (map profile/clean-email) emails)
|
emails (into #{} (map profile/clean-email) emails)]
|
||||||
context (audit/params->context params)]
|
|
||||||
|
|
||||||
;; Create invitations for all provided emails.
|
(let [props {:name name :features features}
|
||||||
(->> emails
|
event (-> (audit/event-from-rpc-params params)
|
||||||
(map (fn [email]
|
(assoc ::audit/name "create-team")
|
||||||
(-> params
|
(assoc ::audit/props props))]
|
||||||
(assoc :team team)
|
(audit/submit! cfg event))
|
||||||
(assoc :profile profile)
|
|
||||||
(assoc :email email)
|
|
||||||
(assoc :role role))))
|
|
||||||
(run! (partial create-invitation cfg)))
|
|
||||||
|
|
||||||
(run! (partial quotes/check-quote! conn)
|
;; Create invitations for all provided emails.
|
||||||
(list {::quotes/id ::quotes/teams-per-profile
|
(->> emails
|
||||||
::quotes/profile-id profile-id}
|
(map (fn [email]
|
||||||
{::quotes/id ::quotes/invitations-per-team
|
(-> params
|
||||||
::quotes/profile-id profile-id
|
(assoc :team team)
|
||||||
::quotes/team-id (:id team)
|
(assoc :profile profile)
|
||||||
::quotes/incr (count emails)}
|
(assoc :email email)
|
||||||
{::quotes/id ::quotes/profiles-per-team
|
(assoc :role role))))
|
||||||
::quotes/profile-id profile-id
|
(run! (partial create-invitation cfg)))
|
||||||
::quotes/team-id (:id team)
|
|
||||||
::quotes/incr (count emails)}))
|
|
||||||
|
|
||||||
(audit/submit! cfg
|
(run! (partial quotes/check-quote! conn)
|
||||||
{::audit/type "action"
|
(list {::quotes/id ::quotes/teams-per-profile
|
||||||
::audit/name "create-team"
|
::quotes/profile-id profile-id}
|
||||||
::audit/profile-id profile-id
|
{::quotes/id ::quotes/invitations-per-team
|
||||||
::audit/props {:name name
|
::quotes/profile-id profile-id
|
||||||
:features features}
|
::quotes/team-id (:id team)
|
||||||
::audit/context context})
|
::quotes/incr (count emails)}
|
||||||
|
{::quotes/id ::quotes/profiles-per-team
|
||||||
|
::quotes/profile-id profile-id
|
||||||
|
::quotes/team-id (:id team)
|
||||||
|
::quotes/incr (count emails)}))
|
||||||
|
|
||||||
(audit/submit! cfg
|
(vary-meta team assoc ::audit/props {:invitations (count emails)})))))
|
||||||
{::audit/type "command"
|
|
||||||
::audit/name "create-team-invitations"
|
|
||||||
::audit/profile-id profile-id
|
|
||||||
::audit/props {:emails emails
|
|
||||||
:role role
|
|
||||||
:profile-id profile-id
|
|
||||||
:invitations (count emails)}})
|
|
||||||
|
|
||||||
(vary-meta team assoc ::audit/props {:invitations (count emails)}))))
|
|
||||||
|
|
||||||
;; --- Query: get-team-invitation-token
|
;; --- Query: get-team-invitation-token
|
||||||
|
|
||||||
|
|
|
@ -169,19 +169,15 @@
|
||||||
;; if we have logged-in user and it matches the invitation we proceed
|
;; if we have logged-in user and it matches the invitation we proceed
|
||||||
;; with accepting the invitation and joining the current profile to the
|
;; with accepting the invitation and joining the current profile to the
|
||||||
;; invited team.
|
;; invited team.
|
||||||
(let [context (audit/params->context params)
|
(let [props {:team-id (:team-id claims)
|
||||||
props {:team-id (:team-id claims)
|
:role (:role claims)
|
||||||
:role (:role claims)
|
:invitation-id (:id invitation)}
|
||||||
:invitation-id (:id invitation)}]
|
event (-> (audit/event-from-rpc-params params)
|
||||||
|
(assoc ::audit/name "accept-team-invitation")
|
||||||
|
(assoc ::audit/props props))]
|
||||||
|
|
||||||
(accept-invitation cfg claims invitation profile)
|
(accept-invitation cfg claims invitation profile)
|
||||||
(audit/submit! cfg
|
(audit/submit! cfg event)
|
||||||
{::audit/type "action"
|
|
||||||
::audit/name "accept-team-invitation"
|
|
||||||
::audit/profile-id profile-id
|
|
||||||
::audit/props props
|
|
||||||
::audit/context context})
|
|
||||||
|
|
||||||
(assoc claims :state :created))
|
(assoc claims :state :created))
|
||||||
|
|
||||||
(ex/raise :type :validation
|
(ex/raise :type :validation
|
||||||
|
|
|
@ -51,12 +51,12 @@
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.http :as-alias http]
|
[app.http :as-alias http]
|
||||||
[app.loggers.audit :refer [parse-client-ip]]
|
|
||||||
[app.redis :as rds]
|
[app.redis :as rds]
|
||||||
[app.redis.script :as-alias rscript]
|
[app.redis.script :as-alias rscript]
|
||||||
[app.rpc :as-alias rpc]
|
[app.rpc :as-alias rpc]
|
||||||
[app.rpc.helpers :as rph]
|
[app.rpc.helpers :as rph]
|
||||||
[app.rpc.rlimit.result :as-alias lresult]
|
[app.rpc.rlimit.result :as-alias lresult]
|
||||||
|
[app.util.inet :as inet]
|
||||||
[app.util.services :as-alias sv]
|
[app.util.services :as-alias sv]
|
||||||
[app.util.time :as dt]
|
[app.util.time :as dt]
|
||||||
[app.worker :as wrk]
|
[app.worker :as wrk]
|
||||||
|
@ -215,7 +215,7 @@
|
||||||
[{:keys [::rpc/profile-id] :as params}]
|
[{:keys [::rpc/profile-id] :as params}]
|
||||||
(let [request (-> params meta ::http/request)]
|
(let [request (-> params meta ::http/request)]
|
||||||
(or profile-id
|
(or profile-id
|
||||||
(some-> request parse-client-ip)
|
(some-> request inet/parse-request)
|
||||||
uuid/zero)))
|
uuid/zero)))
|
||||||
|
|
||||||
(defn process-request!
|
(defn process-request!
|
||||||
|
|
37
backend/src/app/util/inet.clj
Normal file
37
backend/src/app/util/inet.clj
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
;; 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.util.inet
|
||||||
|
"INET addr parsing and validation helpers"
|
||||||
|
(:require
|
||||||
|
[cuerdas.core :as str]
|
||||||
|
[ring.request :as rreq])
|
||||||
|
(:import
|
||||||
|
com.google.common.net.InetAddresses
|
||||||
|
java.net.InetAddress))
|
||||||
|
|
||||||
|
(defn valid?
|
||||||
|
[s]
|
||||||
|
(InetAddresses/isInetAddress s))
|
||||||
|
|
||||||
|
(defn normalize
|
||||||
|
[s]
|
||||||
|
(try
|
||||||
|
(let [addr (InetAddresses/forString s)]
|
||||||
|
(.getHostAddress ^InetAddress addr))
|
||||||
|
(catch Throwable _cause
|
||||||
|
nil)))
|
||||||
|
|
||||||
|
(defn parse-request
|
||||||
|
[request]
|
||||||
|
(or (some-> (rreq/get-header request "x-real-ip")
|
||||||
|
(normalize))
|
||||||
|
(some-> (rreq/get-header request "x-forwarded-for")
|
||||||
|
(str/split #"\s*,\s*")
|
||||||
|
(first)
|
||||||
|
(normalize))
|
||||||
|
(some-> (rreq/remote-addr request)
|
||||||
|
(normalize))))
|
|
@ -11,7 +11,7 @@
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.loggers.audit :refer [parse-client-ip]]
|
[app.util.inet :as inet]
|
||||||
[app.util.time :as dt]
|
[app.util.time :as dt]
|
||||||
[promesa.exec :as px]
|
[promesa.exec :as px]
|
||||||
[promesa.exec.csp :as sp]
|
[promesa.exec.csp :as sp]
|
||||||
|
@ -84,7 +84,7 @@
|
||||||
output-ch (sp/chan :buf output-buff-size)
|
output-ch (sp/chan :buf output-buff-size)
|
||||||
hbeat-ch (sp/chan :buf (sp/sliding-buffer 6))
|
hbeat-ch (sp/chan :buf (sp/sliding-buffer 6))
|
||||||
close-ch (sp/chan)
|
close-ch (sp/chan)
|
||||||
ip-addr (parse-client-ip request)
|
ip-addr (inet/parse-request request)
|
||||||
uagent (rreq/get-header request "user-agent")
|
uagent (rreq/get-header request "user-agent")
|
||||||
id (uuid/next)
|
id (uuid/next)
|
||||||
state (atom {})
|
state (atom {})
|
||||||
|
|
|
@ -28,7 +28,8 @@
|
||||||
ring.request/Request
|
ring.request/Request
|
||||||
(get-header [_ name]
|
(get-header [_ name]
|
||||||
(case name
|
(case name
|
||||||
"x-forwarded-for" "127.0.0.44"))))
|
"x-forwarded-for" "127.0.0.44"
|
||||||
|
"x-real-ip" "127.0.0.43"))))
|
||||||
|
|
||||||
(t/deftest push-events-1
|
(t/deftest push-events-1
|
||||||
(with-redefs [app.config/flags #{:audit-log}]
|
(with-redefs [app.config/flags #{:audit-log}]
|
||||||
|
@ -46,6 +47,7 @@
|
||||||
:profile-id (:id prof)
|
:profile-id (:id prof)
|
||||||
:timestamp (dt/now)
|
:timestamp (dt/now)
|
||||||
:type "action"}]}
|
:type "action"}]}
|
||||||
|
|
||||||
params (with-meta params
|
params (with-meta params
|
||||||
{:app.http/request http-request})
|
{:app.http/request http-request})
|
||||||
|
|
||||||
|
|
|
@ -6,4 +6,4 @@
|
||||||
|
|
||||||
(ns app.common.files.defaults)
|
(ns app.common.files.defaults)
|
||||||
|
|
||||||
(def version 50)
|
(def version 51)
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.svg :as csvg]
|
[app.common.svg :as csvg]
|
||||||
[app.common.text :as txt]
|
[app.common.text :as txt]
|
||||||
|
[app.common.types.color :as ctc]
|
||||||
[app.common.types.component :as ctk]
|
[app.common.types.component :as ctk]
|
||||||
[app.common.types.file :as ctf]
|
[app.common.types.file :as ctf]
|
||||||
[app.common.types.shape :as cts]
|
[app.common.types.shape :as cts]
|
||||||
|
@ -1004,6 +1005,17 @@
|
||||||
(update :pages-index update-vals update-container)
|
(update :pages-index update-vals update-container)
|
||||||
(update :components update-vals update-container))))
|
(update :components update-vals update-container))))
|
||||||
|
|
||||||
|
(def ^:private valid-color?
|
||||||
|
(sm/lazy-validator ::ctc/color))
|
||||||
|
|
||||||
|
(defn migrate-up-51
|
||||||
|
"This migration fixes library invalid colors"
|
||||||
|
|
||||||
|
[data]
|
||||||
|
(let [update-colors
|
||||||
|
(fn [colors]
|
||||||
|
(into {} (filter #(-> % val valid-color?) colors)))]
|
||||||
|
(update data :colors update-colors)))
|
||||||
|
|
||||||
(def migrations
|
(def migrations
|
||||||
"A vector of all applicable migrations"
|
"A vector of all applicable migrations"
|
||||||
|
@ -1046,4 +1058,5 @@
|
||||||
{:id 47 :migrate-up migrate-up-47}
|
{:id 47 :migrate-up migrate-up-47}
|
||||||
{:id 48 :migrate-up migrate-up-48}
|
{:id 48 :migrate-up migrate-up-48}
|
||||||
{:id 49 :migrate-up migrate-up-49}
|
{:id 49 :migrate-up migrate-up-49}
|
||||||
{:id 50 :migrate-up migrate-up-50}])
|
{:id 50 :migrate-up migrate-up-50}
|
||||||
|
{:id 51 :migrate-up migrate-up-51}])
|
||||||
|
|
|
@ -299,19 +299,7 @@
|
||||||
(ptk/reify ::libraries-fetched
|
(ptk/reify ::libraries-fetched
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [templates-a-b-test? (cf/external-feature-flag "dashboard-01" "test")
|
(assoc state :builtin-templates libraries))))
|
||||||
remove-ids (if templates-a-b-test?
|
|
||||||
#{"wireframing-kit" "prototype-examples" "plants-app" "penpot-design-system"}
|
|
||||||
#{"prototype-examples" "penpot-design-system"})
|
|
||||||
libraries (cond->> libraries
|
|
||||||
:always
|
|
||||||
(remove #(contains? remove-ids (:id %)))
|
|
||||||
templates-a-b-test?
|
|
||||||
(concat [{:id "wireframing-kit", :name "Wireframe library"}
|
|
||||||
{:id "prototype-examples", :name "Prototype template"}
|
|
||||||
{:id "plants-app", :name "UI mockup example"}
|
|
||||||
{:id "penpot-design-system", :name "Design system example"}]))]
|
|
||||||
(assoc state :builtin-templates libraries)))))
|
|
||||||
|
|
||||||
(defn fetch-builtin-templates
|
(defn fetch-builtin-templates
|
||||||
[]
|
[]
|
||||||
|
|
|
@ -403,9 +403,9 @@
|
||||||
(mf/with-memo []
|
(mf/with-memo []
|
||||||
(-> (shuffle [{:label (tr "labels.youtube") :value "youtube"}
|
(-> (shuffle [{:label (tr "labels.youtube") :value "youtube"}
|
||||||
{:label (tr "labels.event") :value "event"}
|
{:label (tr "labels.event") :value "event"}
|
||||||
{:label (tr "labels.search") :value "search"}
|
{:label (tr "onboarding.questions.referer.search") :value "search"}
|
||||||
{:label (tr "labels.social") :value "social"}
|
{:label (tr "onboarding.questions.referer.social") :value "social"}
|
||||||
{:label (tr "labels.article") :value "article"}])
|
{:label (tr "onboarding.questions.referer.article") :value "article"}])
|
||||||
(conj {:label (tr "labels.other-short") :value "other"})))
|
(conj {:label (tr "labels.other-short") :value "other"})))
|
||||||
|
|
||||||
current-referer
|
current-referer
|
||||||
|
|
|
@ -264,8 +264,10 @@
|
||||||
multi-colors? multi-assets? on-asset-click on-assets-delete
|
multi-colors? multi-assets? on-asset-click on-assets-delete
|
||||||
on-clear-selection on-group on-rename-group on-ungroup colors
|
on-clear-selection on-group on-rename-group on-ungroup colors
|
||||||
selected-full]}]
|
selected-full]}]
|
||||||
(let [group-open? (or ^boolean force-open?
|
(let [group-open? (if (false? (get open-groups prefix)) ;; if the user has closed it specifically, respect that
|
||||||
^boolean (get open-groups prefix (if (= prefix "") true false)))
|
false
|
||||||
|
(or ^boolean force-open?
|
||||||
|
^boolean (get open-groups prefix (if (= prefix "") true false))))
|
||||||
dragging* (mf/use-state false)
|
dragging* (mf/use-state false)
|
||||||
dragging? (deref dragging*)
|
dragging? (deref dragging*)
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,9 @@
|
||||||
[{:keys [file-id prefix groups open-groups force-open? file local? selected local-data
|
[{:keys [file-id prefix groups open-groups force-open? file local? selected local-data
|
||||||
editing-id renaming-id on-asset-click handle-change apply-typography on-rename-group
|
editing-id renaming-id on-asset-click handle-change apply-typography on-rename-group
|
||||||
on-ungroup on-context-menu selected-full]}]
|
on-ungroup on-context-menu selected-full]}]
|
||||||
(let [group-open? (get open-groups prefix true)
|
(let [group-open? (if (false? (get open-groups prefix)) ;; if the user has closed it specifically, respect that
|
||||||
|
false
|
||||||
|
(get open-groups prefix true))
|
||||||
dragging* (mf/use-state false)
|
dragging* (mf/use-state false)
|
||||||
dragging? (deref dragging*)
|
dragging? (deref dragging*)
|
||||||
selected-paths (mf/with-memo [selected-full]
|
selected-paths (mf/with-memo [selected-full]
|
||||||
|
|
|
@ -2581,15 +2581,15 @@ msgid "labels.event"
|
||||||
msgstr "Event"
|
msgstr "Event"
|
||||||
|
|
||||||
#: src/app/main/ui/onboarding/questions.cljs
|
#: src/app/main/ui/onboarding/questions.cljs
|
||||||
msgid "labels.search"
|
msgid "onboarding.questions.referer.search"
|
||||||
msgstr "Search Engine (Google, Yahoo, Bing)"
|
msgstr "Search Engine (Google, Yahoo, Bing)"
|
||||||
|
|
||||||
#: src/app/main/ui/onboarding/questions.cljs
|
#: src/app/main/ui/onboarding/questions.cljs
|
||||||
msgid "labels.social"
|
msgid "onboarding.questions.referer.social"
|
||||||
msgstr "Social Media (X, Linkedin, FB, etc)"
|
msgstr "Social Media (X, Linkedin, FB, etc)"
|
||||||
|
|
||||||
#: src/app/main/ui/onboarding/questions.cljs
|
#: src/app/main/ui/onboarding/questions.cljs
|
||||||
msgid "labels.article"
|
msgid "onboarding.questions.referer.article"
|
||||||
msgstr "Article (Blog, Post, Newsletter)"
|
msgstr "Article (Blog, Post, Newsletter)"
|
||||||
|
|
||||||
#: src/app/main/ui/onboarding/questions.cljs
|
#: src/app/main/ui/onboarding/questions.cljs
|
||||||
|
|
Loading…
Add table
Reference in a new issue