diff --git a/backend/src/app/auth/oidc.clj b/backend/src/app/auth/oidc.clj index 252f7e3cb..005a06959 100644 --- a/backend/src/app/auth/oidc.clj +++ b/backend/src/app/auth/oidc.clj @@ -12,6 +12,7 @@ [app.common.data.macros :as dm] [app.common.exceptions :as ex] [app.common.logging :as l] + [app.common.schema :as sm] [app.common.spec :as us] [app.common.uri :as u] [app.config :as cf] @@ -607,17 +608,30 @@ nil session-id)))) +(def ^:private schema:auth-params + [:map {:title "auth-params"} + [:invitation-token {:optional true} :string] + [:create-welcome-file {:optional true} :boolean]]) + +;; FIXME: this should be changed, on develop sm/default-transformer +;; becomes sm/json-transformer and :boolean schema type should be +;; replaced with ::sm/boolean for proper and more flexible decoding +;; mechanism. +(def ^:private decode-auth-params + (sm/decoder schema:auth-params sm/default-transformer)) + (defn- auth-handler [cfg {:keys [params] :as request}] (let [props (audit/extract-utm-params params) + params (decode-auth-params params) esid (rpc/get-external-session-id request) - params {:iss :oauth + claims {:iss :oauth :invitation-token (:invitation-token params) + :create-welcome-file (:create-welcome-file params) :external-session-id esid :props props :exp (dt/in-future "4h")} - state (tokens/generate (::setup/props cfg) - (d/without-nils params)) + state (tokens/generate (::setup/props cfg) (d/without-nils claims)) uri (build-auth-uri cfg state)] {::rres/status 200 ::rres/body {:redirect-uri uri}})) diff --git a/backend/src/app/rpc/commands/auth.clj b/backend/src/app/rpc/commands/auth.clj index c8bf3dbd1..b8428a093 100644 --- a/backend/src/app/rpc/commands/auth.clj +++ b/backend/src/app/rpc/commands/auth.clj @@ -27,11 +27,11 @@ [app.rpc.doc :as-alias doc] [app.rpc.helpers :as rph] [app.setup :as-alias setup] - [app.setup.welcome-file :as welcome-file] + [app.setup.welcome-file :refer [create-welcome-file]] [app.tokens :as tokens] [app.util.services :as sv] [app.util.time :as dt] - [app.worker :as-alias wrk] + [app.worker :as wrk] [cuerdas.core :as str])) (def schema:password @@ -243,6 +243,7 @@ params (d/without-nils params) token (tokens/generate (::setup/props cfg) params)] + (with-meta {:token token} {::audit/profile-id uuid/zero}))) @@ -352,7 +353,7 @@ :extra-data ptoken}))) (defn register-profile - [{:keys [::db/conn] :as cfg} {:keys [token fullname theme welcome-file] :as params}] + [{:keys [::db/conn ::wrk/executor] :as cfg} {:keys [token fullname theme] :as params}] (let [theme (when (= theme "light") theme) claims (tokens/verify (::setup/props cfg) {:token token :iss :prepared-register}) params (-> claims @@ -385,8 +386,10 @@ props (audit/profile->props profile) create-welcome-file-when-needed - (when (some? welcome-file) - (partial welcome-file/create-welcome-file cfg profile))] + (fn [] + (when (:create-welcome-file params) + (let [cfg (dissoc cfg ::db/conn)] + (wrk/submit! executor (partial create-welcome-file cfg profile)))))] (cond ;; When profile is blocked, we just ignore it and return plain data @@ -424,21 +427,22 @@ (if (:is-active profile) (-> (profile/strip-private-attrs profile) (rph/with-transform (session/create-fn cfg (:id profile))) + (rph/with-defer create-welcome-file-when-needed) (rph/with-meta {::audit/replace-props props ::audit/context {:action "login"} - ::audit/profile-id (:id profile) - ::before-complete-fns [create-welcome-file-when-needed]})) + ::audit/profile-id (:id profile)})) (do (when-not (eml/has-reports? conn (:email profile)) (send-email-verification! cfg profile)) - (rph/with-meta {:email (:email profile)} - {::audit/replace-props props - ::audit/context {:action "email-verification"} - ::audit/profile-id (:id profile) - ::rpc/before-complete-fns [create-welcome-file-when-needed]}))) + (-> {:email (:email profile)} + (rph/with-defer create-welcome-file-when-needed) + (rph/with-meta + {::audit/replace-props props + ::audit/context {:action "email-verification"} + ::audit/profile-id (:id profile)})))) :else (let [elapsed? (elapsed-verify-threshold? profile) @@ -471,7 +475,7 @@ [:token schema:token] [:fullname [::sm/word-string {:max 100}]] [:theme {:optional true} [:string {:max 10}]] - [:welcome-file {:optional true} [:boolean]]]) + [:create-welcome-file {:optional true} :boolean]]) (sv/defmethod ::register-profile {::rpc/auth false @@ -554,5 +558,3 @@ ::sm/params schema:request-profile-recovery} [cfg params] (db/tx-run! cfg request-profile-recovery params)) - - diff --git a/backend/src/app/setup/welcome_file.clj b/backend/src/app/setup/welcome_file.clj index 4ca71008a..408a916e9 100644 --- a/backend/src/app/setup/welcome_file.clj +++ b/backend/src/app/setup/welcome_file.clj @@ -7,60 +7,26 @@ (ns app.setup.welcome-file (:require [app.common.logging :as l] - [app.common.types.pages-list :as ctpl] [app.db :as db] - [app.features.fdata :as feat.fdata] - [app.rpc :as-alias rpc] - [app.rpc.climit :as-alias climit] + [app.rpc.commands.files-update :as fupdate] [app.rpc.commands.management :as management] [app.rpc.commands.profile :as profile] - [app.rpc.doc :as-alias doc] - [app.setup :as-alias setup] - [app.setup.templates :as tmpl] - [app.util.blob :as blob] - [app.util.pointer-map :as pmap] - [app.worker :as-alias wrk])) + [app.setup.templates :as tmpl])) -(defn- decode-row - "A generic decode row helper" - [{:keys [data features] :as row}] - (cond-> row - features (assoc :features (db/decode-pgarray features #{})) - data (assoc :data (blob/decode data)))) +(def ^:private page-id #uuid "2c6952ee-d00e-8160-8004-d2250b7210cb") +(def ^:private shape-id #uuid "765e9f82-c44e-802e-8004-d72a10b7b445") +(def ^:private update-path + [:pages-index page-id :objects shape-id + :content :children 0 :children 0 :children 0]) -(defn- update-welcome-text - [conn file name] - (let [page-id #uuid "2c6952ee-d00e-8160-8004-d2250b7210cb" - text-id #uuid "765e9f82-c44e-802e-8004-d72a10b7b445" - fdata (:data file) - page (ctpl/get-page fdata page-id) - objects (:objects page) - text (-> (get objects text-id) - (assoc :name "Welcome to Penpot" :position-data nil) - (assoc-in [:content :children 0 :children 0 :children 0 :text] (str "Welcome to Penpot, " name "!"))) - - fdata (assoc-in fdata [:pages-index page-id :objects text-id] text)] - - (db/update! conn :file - {:data (blob/encode fdata)} - {:id (:id file)}))) - - -(defn- update-welcome-file - [{:keys [::db/conn] :as cfg} file-id name] - (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg file-id)] - (when-let [file (db/get* conn :file {:id file-id} - {::db/remove-deleted false})] - (let [file (-> file - (decode-row) - (update :data feat.fdata/process-pointers deref) - (update :data feat.fdata/process-objects (partial into {})))] - (update-welcome-text conn file name))))) - +(defn- update-welcome-shape + [_ file name] + (let [text (str "Welcome to Penpot, " name "!")] + (update file :data update-in update-path assoc :text text))) (defn create-welcome-file - [cfg profile] + [cfg {:keys [id] :as profile}] (try (let [cfg (dissoc cfg ::db/conn) params {:profile-id (:id profile) @@ -70,8 +36,9 @@ first)] (db/tx-run! cfg (fn [cfg] - (update-welcome-file cfg file-id (:fullname profile)) - (profile/update-profile-props cfg (:id profile) {:welcome-file-id file-id})))) + (fupdate/update-file cfg file-id update-welcome-shape name) + (profile/update-profile-props cfg id {:welcome-file-id file-id})))) + (catch Throwable cause (l/error :hint "unexpected error on create welcome file " :cause cause)))) diff --git a/frontend/src/app/main/ui/auth/login.cljs b/frontend/src/app/main/ui/auth/login.cljs index 26004f0a6..fc85f0397 100644 --- a/frontend/src/app/main/ui/auth/login.cljs +++ b/frontend/src/app/main/ui/auth/login.cljs @@ -49,21 +49,24 @@ (defn- login-with-oidc [event provider params] (dom/prevent-default event) - (->> (rp/cmd! :login-with-oidc (assoc params :provider provider)) - (rx/subs! (fn [{:keys [redirect-uri] :as rsp}] - (if redirect-uri - (.replace js/location redirect-uri) - (log/error :hint "unexpected response from OIDC method" - :resp (pr-str rsp)))) - (fn [cause] - (let [{:keys [type code] :as error} (ex-data cause)] - (cond - (and (= type :restriction) - (= code :provider-not-configured)) - (st/emit! (msg/error (tr "errors.auth-provider-not-configured"))) + (let [params (-> params + (assoc :provider provider) + (assoc :create-welcome-file (cf/external-feature-flag "onboarding-03" "test")))] + (->> (rp/cmd! :login-with-oidc params) + (rx/subs! (fn [{:keys [redirect-uri] :as rsp}] + (if redirect-uri + (.replace js/location redirect-uri) + (log/error :hint "unexpected response from OIDC method" + :resp (pr-str rsp)))) + (fn [cause] + (let [{:keys [type code] :as error} (ex-data cause)] + (cond + (and (= type :restriction) + (= code :provider-not-configured)) + (st/emit! (msg/error (tr "errors.auth-provider-not-configured"))) - :else - (st/emit! (msg/error (tr "errors.generic"))))))))) + :else + (st/emit! (msg/error (tr "errors.generic")))))))))) (s/def ::email ::us/email) (s/def ::password ::us/not-empty-string) diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs index a5aa76c4f..4ab899da4 100644 --- a/frontend/src/app/main/ui/auth/register.cljs +++ b/frontend/src/app/main/ui/auth/register.cljs @@ -87,7 +87,8 @@ (fm/validate-not-empty :password (tr "auth.password-not-empty"))] :initial initial) - submitted? (mf/use-state false) + submitted? + (mf/use-state false) on-submit (mf/use-fn @@ -227,9 +228,8 @@ :validators validators :initial params) - welcome-file? (cf/external-feature-flag "onboarding-03" "test") - - submitted? (mf/use-state false) + submitted? + (mf/use-state false) on-success (mf/use-fn @@ -248,8 +248,13 @@ (mf/use-fn (fn [form _] (reset! submitted? true) - (let [params (cond-> (:clean-data @form) - welcome-file? (assoc :welcome-file true))] + (let [create-welcome-file? + (cf/external-feature-flag "onboarding-03" "test") + + params + (cond-> (:clean-data @form) + create-welcome-file? (assoc :create-welcome-file true))] + (->> (rp/cmd! :register-profile params) (rx/finalize #(reset! submitted? false)) (rx/subs! on-success on-error)))))]