mirror of
https://github.com/penpot/penpot.git
synced 2025-03-10 14:51:37 -05:00
🐛 Check complaints reports in the same way as bounces are checked
This commit is contained in:
parent
e0f2c4e0aa
commit
52425a993a
12 changed files with 272 additions and 174 deletions
|
@ -448,3 +448,11 @@
|
|||
{:email email :type "bounce"}
|
||||
{:limit 10}))]
|
||||
(>= (count reports) threshold))))
|
||||
|
||||
(defn has-reports?
|
||||
([conn email] (has-reports? conn email nil))
|
||||
([conn email {:keys [threshold] :or {threshold 1}}]
|
||||
(let [reports (db/exec! conn (sql/select :global-complaint-report
|
||||
{:email email}
|
||||
{:limit 10}))]
|
||||
(>= (count reports) threshold))))
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
(:require
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.logging :as l]
|
||||
[app.common.pprint :as pp]
|
||||
[app.db :as db]
|
||||
[app.db.sql :as sql]
|
||||
[app.http.client :as http]
|
||||
|
@ -16,10 +17,10 @@
|
|||
[app.setup :as-alias setup]
|
||||
[app.tokens :as tokens]
|
||||
[app.worker :as-alias wrk]
|
||||
[clojure.data.json :as j]
|
||||
[clojure.spec.alpha :as s]
|
||||
[cuerdas.core :as str]
|
||||
[integrant.core :as ig]
|
||||
[jsonista.core :as j]
|
||||
[promesa.exec :as px]
|
||||
[ring.request :as rreq]
|
||||
[ring.response :as-alias rres]))
|
||||
|
@ -136,83 +137,110 @@
|
|||
|
||||
(defn- parse-json
|
||||
[v]
|
||||
(ex/ignoring
|
||||
(j/read-value v)))
|
||||
(try
|
||||
(j/read-str v)
|
||||
(catch Throwable cause
|
||||
(l/wrn :hint "unable to decode request body"
|
||||
:cause cause))))
|
||||
|
||||
(defn- register-bounce-for-profile
|
||||
[{:keys [::db/pool]} {:keys [type kind profile-id] :as report}]
|
||||
(when (= kind "permanent")
|
||||
(db/with-atomic [conn pool]
|
||||
(db/insert! conn :profile-complaint-report
|
||||
(try
|
||||
(db/insert! pool :profile-complaint-report
|
||||
{:profile-id profile-id
|
||||
:type (name type)
|
||||
:content (db/tjson report)})
|
||||
|
||||
;; TODO: maybe also try to find profiles by mail and if exists
|
||||
;; register profile reports for them?
|
||||
(doseq [recipient (:recipients report)]
|
||||
(db/insert! conn :global-complaint-report
|
||||
{:email (:email recipient)
|
||||
:type (name type)
|
||||
:content (db/tjson report)}))
|
||||
(catch Throwable cause
|
||||
(l/warn :hint "unable to persist profile complaint"
|
||||
:cause cause)))
|
||||
|
||||
(let [profile (db/exec-one! conn (sql/select :profile {:id profile-id}))]
|
||||
(when (some #(= (:email profile) (:email %)) (:recipients report))
|
||||
;; If the report matches the profile email, this means that
|
||||
;; the report is for itself, can be caused when a user
|
||||
;; registers with an invalid email or the user email is
|
||||
;; permanently rejecting receiving the email. In this case we
|
||||
;; have no option to mark the user as muted (and in this case
|
||||
;; the profile will be also inactive.
|
||||
(db/update! conn :profile
|
||||
{:is-muted true}
|
||||
{:id profile-id}))))))
|
||||
|
||||
(defn- register-complaint-for-profile
|
||||
[{:keys [::db/pool]} {:keys [type profile-id] :as report}]
|
||||
(db/with-atomic [conn pool]
|
||||
(db/insert! conn :profile-complaint-report
|
||||
{:profile-id profile-id
|
||||
:type (name type)
|
||||
:content (db/tjson report)})
|
||||
|
||||
;; TODO: maybe also try to find profiles by email and if exists
|
||||
;; register profile reports for them?
|
||||
(doseq [email (:recipients report)]
|
||||
(db/insert! conn :global-complaint-report
|
||||
{:email email
|
||||
(doseq [recipient (:recipients report)]
|
||||
(db/insert! pool :global-complaint-report
|
||||
{:email (:email recipient)
|
||||
:type (name type)
|
||||
:content (db/tjson report)}))
|
||||
|
||||
(let [profile (db/exec-one! conn (sql/select :profile {:id profile-id}))]
|
||||
(when (some #(= % (:email profile)) (:recipients report))
|
||||
(let [profile (db/exec-one! pool (sql/select :profile {:id profile-id}))]
|
||||
(when (some #(= (:email profile) (:email %)) (:recipients report))
|
||||
;; If the report matches the profile email, this means that
|
||||
;; the report is for itself, rare case but can happen; In this
|
||||
;; case just mark profile as muted (very rare case).
|
||||
(db/update! conn :profile
|
||||
;; the report is for itself, can be caused when a user
|
||||
;; registers with an invalid email or the user email is
|
||||
;; permanently rejecting receiving the email. In this case we
|
||||
;; have no option to mark the user as muted (and in this case
|
||||
;; the profile will be also inactive.
|
||||
|
||||
(l/inf :hint "mark profile: muted"
|
||||
:profile-id (str (:id profile))
|
||||
:email (:email profile)
|
||||
:reason "bounce report"
|
||||
:report-id (:feedback-id report))
|
||||
|
||||
(db/update! pool :profile
|
||||
{:is-muted true}
|
||||
{:id profile-id})))))
|
||||
{:id profile-id}
|
||||
{::db/return-keys false})))))
|
||||
|
||||
(defn- register-complaint-for-profile
|
||||
[{:keys [::db/pool]} {:keys [type profile-id] :as report}]
|
||||
|
||||
(try
|
||||
(db/insert! pool :profile-complaint-report
|
||||
{:profile-id profile-id
|
||||
:type (name type)
|
||||
:content (db/tjson report)})
|
||||
(catch Throwable cause
|
||||
(l/warn :hint "unable to persist profile complaint"
|
||||
:cause cause)))
|
||||
|
||||
;; TODO: maybe also try to find profiles by email and if exists
|
||||
;; register profile reports for them?
|
||||
(doseq [email (:recipients report)]
|
||||
(db/insert! pool :global-complaint-report
|
||||
{:email email
|
||||
:type (name type)
|
||||
:content (db/tjson report)}))
|
||||
|
||||
(let [profile (db/exec-one! pool (sql/select :profile {:id profile-id}))]
|
||||
(when (some #(= % (:email profile)) (:recipients report))
|
||||
;; If the report matches the profile email, this means that
|
||||
;; the report is for itself, rare case but can happen; In this
|
||||
;; case just mark profile as muted (very rare case).
|
||||
(l/inf :hint "mark profile: muted"
|
||||
:profile-id (str (:id profile))
|
||||
:email (:email profile)
|
||||
:reason "complaint report"
|
||||
:report-id (:feedback-id report))
|
||||
|
||||
(db/update! pool :profile
|
||||
{:is-muted true}
|
||||
{:id profile-id}
|
||||
{::db/return-keys false}))))
|
||||
|
||||
(defn- process-report
|
||||
[cfg {:keys [type profile-id] :as report}]
|
||||
(l/trace :action "processing report" :report (pr-str report))
|
||||
(cond
|
||||
;; In this case we receive a bounce/complaint notification without
|
||||
;; confirmed identity, we just emit a warning but do nothing about
|
||||
;; it because this is not a normal case. All notifications should
|
||||
;; come with profile identity.
|
||||
(nil? profile-id)
|
||||
(l/warn :msg "a notification without identity received from AWS"
|
||||
:report (pr-str report))
|
||||
(l/wrn :hint "not-identified report"
|
||||
::l/body (pp/pprint-str report {:length 40 :level 6}))
|
||||
|
||||
(= "bounce" type)
|
||||
(register-bounce-for-profile cfg report)
|
||||
(do
|
||||
(l/trc :hint "bounce report"
|
||||
::l/body (pp/pprint-str report {:length 40 :level 6}))
|
||||
(register-bounce-for-profile cfg report))
|
||||
|
||||
(= "complaint" type)
|
||||
(register-complaint-for-profile cfg report)
|
||||
(do
|
||||
(l/trc :hint "complaint report"
|
||||
::l/body (pp/pprint-str report {:length 40 :level 6}))
|
||||
(register-complaint-for-profile cfg report))
|
||||
|
||||
:else
|
||||
(l/warn :msg "unrecognized report received from AWS"
|
||||
:report (pr-str report))))
|
||||
|
||||
|
||||
(l/wrn :hint "unrecognized report"
|
||||
::l/body (pp/pprint-str report {:length 20 :level 4}))))
|
||||
|
|
|
@ -209,7 +209,19 @@
|
|||
(str/lower (:password params)))
|
||||
(ex/raise :type :validation
|
||||
:code :email-as-password
|
||||
:hint "you can't use your email as password")))
|
||||
:hint "you can't use your email as password"))
|
||||
|
||||
(when (eml/has-bounce-reports? cfg (:email params))
|
||||
(ex/raise :type :restriction
|
||||
:code :email-has-permanent-bounces
|
||||
:email (:email params)
|
||||
:hint "looks like the email has bounce reports"))
|
||||
|
||||
(when (eml/has-complaint-reports? cfg (:email params))
|
||||
(ex/raise :type :restriction
|
||||
:code :email-has-complaints
|
||||
:email (:email params)
|
||||
:hint "looks like the email has complaint reports")))
|
||||
|
||||
(defn prepare-register
|
||||
[{:keys [::db/pool] :as cfg} {:keys [email] :as params}]
|
||||
|
@ -398,20 +410,22 @@
|
|||
::audit/profile-id (:id profile)}))
|
||||
|
||||
(do
|
||||
(send-email-verification! cfg profile)
|
||||
(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)})))
|
||||
|
||||
:else
|
||||
(let [elapsed? (elapsed-verify-threshold? profile)
|
||||
bounce? (eml/has-bounce-reports? conn (:email profile))
|
||||
action (if bounce?
|
||||
"ignore-because-bounce"
|
||||
(if elapsed?
|
||||
"resend-email-verification"
|
||||
"ignore"))]
|
||||
(let [elapsed? (elapsed-verify-threshold? profile)
|
||||
complaints? (eml/has-reports? conn (:email profile))
|
||||
action (if complaints?
|
||||
"ignore-because-complaints"
|
||||
(if elapsed?
|
||||
"resend-email-verification"
|
||||
"ignore"))]
|
||||
|
||||
(l/wrn :hint "repeated registry detected"
|
||||
:profile-id (str (:id profile))
|
||||
|
@ -446,7 +460,7 @@
|
|||
;; ---- COMMAND: Request Profile Recovery
|
||||
|
||||
(defn- request-profile-recovery
|
||||
[{:keys [::db/pool] :as cfg} {:keys [email] :as params}]
|
||||
[{:keys [::db/conn] :as cfg} {:keys [email] :as params}]
|
||||
(letfn [(create-recovery-token [{:keys [id] :as profile}]
|
||||
(let [token (tokens/generate (::setup/props cfg)
|
||||
{:iss :password-recovery
|
||||
|
@ -468,39 +482,42 @@
|
|||
:extra-data ptoken})
|
||||
nil))]
|
||||
|
||||
(db/with-atomic [conn pool]
|
||||
(let [profile (->> (profile/clean-email email)
|
||||
(profile/get-profile-by-email conn))]
|
||||
(let [profile (->> (profile/clean-email email)
|
||||
(profile/get-profile-by-email conn))]
|
||||
|
||||
(cond
|
||||
(not profile)
|
||||
(l/wrn :hint "attempt of profile recovery: no profile found"
|
||||
:profile-email email)
|
||||
(cond
|
||||
(not profile)
|
||||
(l/wrn :hint "attempt of profile recovery: no profile found"
|
||||
:profile-email email)
|
||||
|
||||
(not (eml/allow-send-emails? conn profile))
|
||||
(l/wrn :hint "attempt of profile recovery: profile is muted"
|
||||
:profile-id (str (:id profile))
|
||||
:profile-email (:email profile))
|
||||
(not (eml/allow-send-emails? conn profile))
|
||||
(l/wrn :hint "attempt of profile recovery: profile is muted"
|
||||
:profile-id (str (:id profile))
|
||||
:profile-email (:email profile))
|
||||
|
||||
(eml/has-bounce-reports? conn (:email profile))
|
||||
(l/wrn :hint "attempt of profile recovery: email has bounces"
|
||||
:profile-id (str (:id profile))
|
||||
:profile-email (:email profile))
|
||||
(eml/has-bounce-reports? conn (:email profile))
|
||||
(l/wrn :hint "attempt of profile recovery: email has bounces"
|
||||
:profile-id (str (:id profile))
|
||||
:profile-email (:email profile))
|
||||
|
||||
(not (elapsed-verify-threshold? profile))
|
||||
(l/wrn :hint "attempt of profile recovery: retry attempt threshold not elapsed"
|
||||
:profile-id (str (:id profile))
|
||||
:profile-email (:email profile))
|
||||
(eml/has-complaint-reports? conn (:email profile))
|
||||
(l/wrn :hint "attempt of profile recovery: email has complaints"
|
||||
:profile-id (str (:id profile))
|
||||
:profile-email (:email profile))
|
||||
|
||||
(not (elapsed-verify-threshold? profile))
|
||||
(l/wrn :hint "attempt of profile recovery: retry attempt threshold not elapsed"
|
||||
:profile-id (str (:id profile))
|
||||
:profile-email (:email profile))
|
||||
|
||||
:else
|
||||
(do
|
||||
(db/update! conn :profile
|
||||
{:modified-at (dt/now)}
|
||||
{:id (:id profile)})
|
||||
(->> profile
|
||||
(create-recovery-token)
|
||||
(send-email-notification conn))))))))
|
||||
:else
|
||||
(do
|
||||
(db/update! conn :profile
|
||||
{:modified-at (dt/now)}
|
||||
{:id (:id profile)})
|
||||
(->> profile
|
||||
(create-recovery-token)
|
||||
(send-email-notification conn)))))))
|
||||
|
||||
|
||||
(def schema:request-profile-recovery
|
||||
|
@ -512,6 +529,6 @@
|
|||
::doc/added "1.15"
|
||||
::sm/params schema:request-profile-recovery}
|
||||
[cfg params]
|
||||
(request-profile-recovery cfg params))
|
||||
(db/tx-run! cfg request-profile-recovery params))
|
||||
|
||||
|
||||
|
|
|
@ -276,19 +276,19 @@
|
|||
(sv/defmethod ::request-email-change
|
||||
{::doc/added "1.0"
|
||||
::sm/params schema:request-email-change}
|
||||
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id email] :as params}]
|
||||
(db/with-atomic [conn pool]
|
||||
(let [profile (db/get-by-id conn :profile profile-id)
|
||||
cfg (assoc cfg ::conn conn)
|
||||
params (assoc params
|
||||
:profile profile
|
||||
:email (clean-email email))]
|
||||
(if (contains? cf/flags :smtp)
|
||||
(request-email-change! cfg params)
|
||||
(change-email-immediately! cfg params)))))
|
||||
[cfg {:keys [::rpc/profile-id email] :as params}]
|
||||
(db/tx-run! cfg
|
||||
(fn [cfg]
|
||||
(let [profile (db/get-by-id cfg :profile profile-id)
|
||||
params (assoc params
|
||||
:profile profile
|
||||
:email (clean-email email))]
|
||||
(if (contains? cf/flags :smtp)
|
||||
(request-email-change! cfg params)
|
||||
(change-email-immediately! cfg params))))))
|
||||
|
||||
(defn- change-email-immediately!
|
||||
[{:keys [::conn]} {:keys [profile email] :as params}]
|
||||
[{:keys [::db/conn]} {:keys [profile email] :as params}]
|
||||
(when (not= email (:email profile))
|
||||
(check-profile-existence! conn params))
|
||||
|
||||
|
@ -299,7 +299,7 @@
|
|||
{:changed true})
|
||||
|
||||
(defn- request-email-change!
|
||||
[{:keys [::conn] :as cfg} {:keys [profile email] :as params}]
|
||||
[{:keys [::db/conn] :as cfg} {:keys [profile email] :as params}]
|
||||
(let [token (tokens/generate (::setup/props cfg)
|
||||
{:iss :change-email
|
||||
:exp (dt/in-future "15m")
|
||||
|
@ -319,9 +319,28 @@
|
|||
:hint "looks like the profile has reported repeatedly as spam or has permanent bounces."))
|
||||
|
||||
(when (eml/has-bounce-reports? conn email)
|
||||
(ex/raise :type :validation
|
||||
(ex/raise :type :restriction
|
||||
:code :email-has-permanent-bounces
|
||||
:hint "looks like the email you invite has been repeatedly reported as spam or permanent bounce"))
|
||||
:email email
|
||||
:hint "looks like the email has bounce reports"))
|
||||
|
||||
(when (eml/has-complaint-reports? conn email)
|
||||
(ex/raise :type :restriction
|
||||
:code :email-has-complaints
|
||||
:email email
|
||||
:hint "looks like the email has spam complaint reports"))
|
||||
|
||||
(when (eml/has-bounce-reports? conn (:email profile))
|
||||
(ex/raise :type :restriction
|
||||
:code :email-has-permanent-bounces
|
||||
:email (:email profile)
|
||||
:hint "looks like the email has bounce reports"))
|
||||
|
||||
(when (eml/has-complaint-reports? conn (:email profile))
|
||||
(ex/raise :type :restriction
|
||||
:code :email-has-complaints
|
||||
:email (:email profile)
|
||||
:hint "looks like the email has spam complaint reports"))
|
||||
|
||||
(eml/send! {::eml/conn conn
|
||||
::eml/factory eml/change-email
|
||||
|
|
|
@ -734,12 +734,19 @@
|
|||
:email email
|
||||
:hint "the profile has reported repeatedly as spam or has bounces"))
|
||||
|
||||
;; Secondly check if the invited member email is part of the global spam/bounce report.
|
||||
;; Secondly check if the invited member email is part of the global bounce report.
|
||||
(when (eml/has-bounce-reports? conn email)
|
||||
(ex/raise :type :validation
|
||||
(ex/raise :type :restriction
|
||||
:code :email-has-permanent-bounces
|
||||
:email email
|
||||
:hint "the email you invite has been repeatedly reported as spam or bounce"))
|
||||
:hint "the email you invite has been repeatedly reported as bounce"))
|
||||
|
||||
;; Secondly check if the invited member email is part of the global complain report.
|
||||
(when (eml/has-complaint-reports? conn email)
|
||||
(ex/raise :type :restriction
|
||||
:code :email-has-complaints
|
||||
:email email
|
||||
:hint "the email you invite has been repeatedly reported as spam"))
|
||||
|
||||
;; When we have email verification disabled and invitation user is
|
||||
;; already present in the database, we proceed to add it to the
|
||||
|
|
|
@ -590,9 +590,10 @@
|
|||
(th/create-global-complaint-for pool {:type :bounce :email "user@example.com"})
|
||||
|
||||
(let [out (th/command! data)]
|
||||
(t/is (th/success? out))
|
||||
(let [result (:result out)]
|
||||
(t/is (contains? result :token))))))
|
||||
(t/is (not (th/success? out)))
|
||||
(let [edata (-> out :error ex-data)]
|
||||
(t/is (= :restriction (:type edata)))
|
||||
(t/is (= :email-has-permanent-bounces (:code edata)))))))
|
||||
|
||||
(t/deftest register-profile-with-complained-email
|
||||
(let [pool (:app.db/pool th/*system*)
|
||||
|
@ -603,9 +604,11 @@
|
|||
(th/create-global-complaint-for pool {:type :complaint :email "user@example.com"})
|
||||
|
||||
(let [out (th/command! data)]
|
||||
(t/is (th/success? out))
|
||||
(let [result (:result out)]
|
||||
(t/is (contains? result :token))))))
|
||||
(t/is (not (th/success? out)))
|
||||
|
||||
(let [edata (-> out :error ex-data)]
|
||||
(t/is (= :restriction (:type edata)))
|
||||
(t/is (= :email-has-complaints (:code edata)))))))
|
||||
|
||||
(t/deftest register-profile-with-email-as-password
|
||||
(let [data {::th/type :prepare-register-profile
|
||||
|
@ -636,20 +639,26 @@
|
|||
|
||||
;; with complaints
|
||||
(th/create-global-complaint-for pool {:type :complaint :email (:email data)})
|
||||
(let [out (th/command! data)]
|
||||
(let [out (th/command! data)]
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:result out)))
|
||||
(t/is (= 2 (:call-count @mock))))
|
||||
|
||||
(let [edata (-> out :error ex-data)]
|
||||
(t/is (= :restriction (:type edata)))
|
||||
(t/is (= :email-has-complaints (:code edata))))
|
||||
|
||||
(t/is (= 1 (:call-count @mock))))
|
||||
|
||||
;; with bounces
|
||||
(th/create-global-complaint-for pool {:type :bounce :email (:email data)})
|
||||
(let [out (th/command! data)
|
||||
error (:error out)]
|
||||
(let [out (th/command! data)]
|
||||
;; (th/print-result! out)
|
||||
(t/is (th/ex-info? error))
|
||||
(t/is (th/ex-of-type? error :validation))
|
||||
(t/is (th/ex-of-code? error :email-has-permanent-bounces))
|
||||
(t/is (= 2 (:call-count @mock)))))))
|
||||
|
||||
(let [edata (-> out :error ex-data)]
|
||||
(t/is (= :restriction (:type edata)))
|
||||
(t/is (= :email-has-permanent-bounces (:code edata))))
|
||||
|
||||
(t/is (= 1 (:call-count @mock)))))))
|
||||
|
||||
|
||||
(t/deftest email-change-request-without-smtp
|
||||
|
@ -714,7 +723,7 @@
|
|||
out (th/command! data)]
|
||||
;; (th/print-result! out)
|
||||
(t/is (nil? (:result out)))
|
||||
(t/is (= 2 (:call-count @mock))))
|
||||
(t/is (= 1 (:call-count @mock))))
|
||||
|
||||
;; with valid email and active user with global bounce
|
||||
(th/create-global-complaint-for pool {:type :bounce :email (:email profile2)})
|
||||
|
@ -723,7 +732,7 @@
|
|||
(t/is (nil? (:result out)))
|
||||
(t/is (nil? (:error out)))
|
||||
;; (th/print-result! out)
|
||||
(t/is (= 2 (:call-count @mock))))))))
|
||||
(t/is (= 1 (:call-count @mock))))))))
|
||||
|
||||
|
||||
(t/deftest update-profile-password
|
||||
|
|
|
@ -62,8 +62,8 @@
|
|||
(th/reset-mock! mock)
|
||||
(let [data (assoc data :emails ["foo@bar.com"])
|
||||
out (th/command! data)]
|
||||
(t/is (th/success? out))
|
||||
(t/is (= 1 (:call-count (deref mock)))))
|
||||
(t/is (not (th/success? out)))
|
||||
(t/is (= 0 (:call-count (deref mock)))))
|
||||
|
||||
;; get invitation token
|
||||
(let [params {::th/type :get-team-invitation-token
|
||||
|
@ -86,7 +86,7 @@
|
|||
(t/is (= 0 (:call-count @mock)))
|
||||
|
||||
(let [edata (-> out :error ex-data)]
|
||||
(t/is (= :validation (:type edata)))
|
||||
(t/is (= :restriction (:type edata)))
|
||||
(t/is (= :email-has-permanent-bounces (:code edata)))))
|
||||
|
||||
;; invite internal user that is muted
|
||||
|
|
|
@ -59,7 +59,8 @@
|
|||
:profile-is-muted
|
||||
(rx/of (msg/error (tr "errors.profile-is-muted")))
|
||||
|
||||
:email-has-permanent-bounces
|
||||
(:email-has-permanent-bounces
|
||||
:email-has-complaints)
|
||||
(rx/of (msg/error (tr "errors.email-has-permanent-bounces" (:email data))))
|
||||
|
||||
(rx/throw cause)))))
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
|
||||
(defn- on-prepare-register-error
|
||||
[form cause]
|
||||
(let [{:keys [type code]} (ex-data cause)]
|
||||
(let [{:keys [type code] :as edata} (ex-data cause)]
|
||||
(condp = [type code]
|
||||
[:restriction :registration-disabled]
|
||||
(st/emit! (msg/error (tr "errors.registration-disabled")))
|
||||
|
@ -62,6 +62,12 @@
|
|||
[:restriction :email-domain-is-not-allowed]
|
||||
(st/emit! (msg/error (tr "errors.email-domain-not-allowed")))
|
||||
|
||||
[:restriction :email-has-permanent-bounces]
|
||||
(st/emit! (msg/error (tr "errors.email-has-permanent-bounces" (:email edata))))
|
||||
|
||||
[:restriction :email-has-complaints]
|
||||
(st/emit! (msg/error (tr "errors.email-has-permanent-bounces" (:email edata))))
|
||||
|
||||
[:validation :email-as-password]
|
||||
(swap! form assoc-in [:errors :password]
|
||||
{:message "errors.email-as-password"})
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
|
||||
(def ^:private arrow-icon
|
||||
(i/icon-xref :arrow (stl/css :arrow-icon)))
|
||||
|
||||
|
@ -62,10 +61,10 @@
|
|||
{::mf/wrap [mf/memo]
|
||||
::mf/wrap-props false}
|
||||
[{:keys [section team]}]
|
||||
(let [on-nav-members (mf/use-fn #(st/emit! (dd/go-to-team-members)))
|
||||
on-nav-settings (mf/use-fn #(st/emit! (dd/go-to-team-settings)))
|
||||
on-nav-invitations (mf/use-fn #(st/emit! (dd/go-to-team-invitations)))
|
||||
on-nav-webhooks (mf/use-fn #(st/emit! (dd/go-to-team-webhooks)))
|
||||
(let [on-nav-members (mf/use-fn #(st/emit! (dd/go-to-team-members)))
|
||||
on-nav-settings (mf/use-fn #(st/emit! (dd/go-to-team-settings)))
|
||||
on-nav-invitations (mf/use-fn #(st/emit! (dd/go-to-team-invitations)))
|
||||
on-nav-webhooks (mf/use-fn #(st/emit! (dd/go-to-team-webhooks)))
|
||||
|
||||
members-section? (= section :dashboard-team-members)
|
||||
settings-section? (= section :dashboard-team-settings)
|
||||
|
@ -157,21 +156,22 @@
|
|||
(dd/fetch-team-invitations)))
|
||||
|
||||
on-error
|
||||
(fn [{:keys [type code] :as error}]
|
||||
(cond
|
||||
(and (= :validation type)
|
||||
(= :profile-is-muted code))
|
||||
(st/emit! (msg/error (tr "errors.profile-is-muted"))
|
||||
(modal/hide))
|
||||
(fn [_form cause]
|
||||
(let [{:keys [type code] :as error} (ex-data cause)]
|
||||
(cond
|
||||
(and (= :validation type)
|
||||
(= :profile-is-muted code))
|
||||
(st/emit! (msg/error (tr "errors.profile-is-muted"))
|
||||
(modal/hide))
|
||||
|
||||
(and (= :validation type)
|
||||
(or (= :member-is-muted code)
|
||||
(= :email-has-permanent-bounces code)))
|
||||
(swap! error-text (tr "errors.email-spam-or-permanent-bounces" (:email error)))
|
||||
(or (= :member-is-muted code)
|
||||
(= :email-has-permanent-bounces code)
|
||||
(= :email-has-complaints code))
|
||||
(swap! error-text (tr "errors.email-spam-or-permanent-bounces" (:email error)))
|
||||
|
||||
:else
|
||||
(st/emit! (msg/error (tr "errors.generic"))
|
||||
(modal/hide))))
|
||||
:else
|
||||
(st/emit! (msg/error (tr "errors.generic"))
|
||||
(modal/hide)))))
|
||||
|
||||
on-submit
|
||||
(fn [form]
|
||||
|
@ -563,22 +563,24 @@
|
|||
on-error
|
||||
(mf/use-fn
|
||||
(mf/deps email)
|
||||
(fn [{:keys [type code] :as error}]
|
||||
(cond
|
||||
(and (= :validation type)
|
||||
(= :profile-is-muted code))
|
||||
(rx/of (msg/error (tr "errors.profile-is-muted")))
|
||||
(fn [cause]
|
||||
(let [{:keys [type code] :as error} (ex-data cause)]
|
||||
(cond
|
||||
(and (= :validation type)
|
||||
(= :profile-is-muted code))
|
||||
(rx/of (msg/error (tr "errors.profile-is-muted")))
|
||||
|
||||
(and (= :validation type)
|
||||
(= :member-is-muted code))
|
||||
(rx/of (msg/error (tr "errors.member-is-muted")))
|
||||
(and (= :validation type)
|
||||
(= :member-is-muted code))
|
||||
(rx/of (msg/error (tr "errors.member-is-muted")))
|
||||
|
||||
(and (= :validation type)
|
||||
(= :email-has-permanent-bounces code))
|
||||
(rx/of (msg/error (tr "errors.email-has-permanent-bounces" email)))
|
||||
(and (= :restriction type)
|
||||
(or (= :email-has-permanent-bounces code)
|
||||
(= :email-has-complaints code)))
|
||||
(rx/of (msg/error (tr "errors.email-has-permanent-bounces" email)))
|
||||
|
||||
:else
|
||||
(rx/throw error))))
|
||||
:else
|
||||
(rx/throw cause)))))
|
||||
|
||||
on-delete
|
||||
(mf/use-fn
|
||||
|
@ -588,7 +590,6 @@
|
|||
mdata {:on-success #(st/emit! (dd/fetch-team-invitations))}]
|
||||
(st/emit! (dd/delete-team-invitation (with-meta params mdata))))))
|
||||
|
||||
|
||||
on-resend-success
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
|
|
|
@ -70,8 +70,9 @@
|
|||
(on-update-submit form)
|
||||
(on-create-submit form))))
|
||||
|
||||
(mf/defc team-form-modal {::mf/register modal/components
|
||||
::mf/register-as :team-form}
|
||||
(mf/defc team-form-modal
|
||||
{::mf/register modal/components
|
||||
::mf/register-as :team-form}
|
||||
[{:keys [team] :as props}]
|
||||
(let [initial (mf/use-memo (fn [] (or team {})))
|
||||
form (fm/use-form :spec ::team-form
|
||||
|
|
|
@ -39,21 +39,22 @@
|
|||
(s/keys :req-un [::email-1 ::email-2]))
|
||||
|
||||
(defn- on-error
|
||||
[form error]
|
||||
(case (:code (ex-data error))
|
||||
:email-already-exists
|
||||
(swap! form (fn [data]
|
||||
(let [error {:message (tr "errors.email-already-exists")}]
|
||||
(assoc-in data [:errors :email-1] error))))
|
||||
[form cause]
|
||||
(let [{:keys [code] :as error} (ex-data cause)]
|
||||
(case code
|
||||
:email-already-exists
|
||||
(swap! form (fn [data]
|
||||
(let [error {:message (tr "errors.email-already-exists")}]
|
||||
(assoc-in data [:errors :email-1] error))))
|
||||
|
||||
:profile-is-muted
|
||||
(rx/of (msg/error (tr "errors.profile-is-muted")))
|
||||
:profile-is-muted
|
||||
(rx/of (msg/error (tr "errors.profile-is-muted")))
|
||||
|
||||
:email-has-permanent-bounces
|
||||
(let [email (get @form [:data :email-1])]
|
||||
(rx/of (msg/error (tr "errors.email-has-permanent-bounces" email))))
|
||||
(:email-has-permanent-bounces
|
||||
:email-has-complaints)
|
||||
(rx/of (msg/error (tr "errors.email-has-permanent-bounces" (:email error))))
|
||||
|
||||
(rx/throw error)))
|
||||
(rx/throw cause))))
|
||||
|
||||
(defn- on-success
|
||||
[profile data]
|
||||
|
|
Loading…
Add table
Reference in a new issue