From 704bfbe39763f15cda8cf590de450beff3e3c2e1 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Mon, 30 Mar 2026 12:07:32 -0700 Subject: [PATCH 01/10] lint fixes --- plugins/auth/systems/bread/alpha/plugin/account.cljc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/auth/systems/bread/alpha/plugin/account.cljc b/plugins/auth/systems/bread/alpha/plugin/account.cljc index dc10f033..52c112d6 100644 --- a/plugins/auth/systems/bread/alpha/plugin/account.cljc +++ b/plugins/auth/systems/bread/alpha/plugin/account.cljc @@ -197,7 +197,7 @@ pr-str)))])) (defmethod bread/dispatch ::account=> - [{:as req :keys [params request-method session] ::bread/keys [config dispatcher]}] + [{:as req :keys [params request-method session] ::bread/keys [dispatcher]}] (if (= :post request-method) ;; Account update. (let [action (keyword (:action params)) @@ -205,9 +205,7 @@ [txs error-key] (try [(account-action req) nil] (catch clojure.lang.ExceptionInfo e - [nil (-> e ex-data :error-key)])) - success-key (cond - account-update? :account-updated)] + [nil (-> e ex-data :error-key)]))] (if txs {:effects [(db/txs->effect req txs :effect/description "Update account details")] From bc887f974c076748a25defb7d4ddf5ca65c24c93 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Mon, 30 Mar 2026 20:43:18 -0700 Subject: [PATCH 02/10] whitespace --- src/systems/bread/alpha/component.cljc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/systems/bread/alpha/component.cljc b/src/systems/bread/alpha/component.cljc index e6c97a37..eeb73d91 100644 --- a/src/systems/bread/alpha/component.cljc +++ b/src/systems/bread/alpha/component.cljc @@ -130,10 +130,10 @@ (defmethod bread/action ::render [{:keys [::bread/data body] :as res} _ _] (if body - res - (let [component (match res) - body (render component data)] - (assoc res :body body)))) + res + (let [component (match res) + body (render component data)] + (assoc res :body body)))) (defmethod bread/action ::hook-fn [req _ _] From 37229d4653bed65aa65556216eba3543b4d43d95 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Mon, 30 Mar 2026 20:46:25 -0700 Subject: [PATCH 03/10] fix :delete-session issue, test ::account=> dispatch --- .../systems/bread/alpha/plugin/account.cljc | 108 +++--- .../bread/alpha/plugin/account_test.clj | 308 ++++++++++++++++++ 2 files changed, 373 insertions(+), 43 deletions(-) create mode 100644 test/cms/systems/bread/alpha/plugin/account_test.clj diff --git a/plugins/auth/systems/bread/alpha/plugin/account.cljc b/plugins/auth/systems/bread/alpha/plugin/account.cljc index 52c112d6..85c9e050 100644 --- a/plugins/auth/systems/bread/alpha/plugin/account.cljc +++ b/plugins/auth/systems/bread/alpha/plugin/account.cljc @@ -159,10 +159,7 @@ (defmethod account-action :delete-session [{:keys [params]}] (when-let [id (try (Integer. (:dbid params)) (catch Throwable _ nil))] - [[:db/retract id :session/id] - [:db/retract id :session/data] - [:db/retract id :thing/created-at] - [:db/retract id :thing/updated-at]])) + {:db/id id})) (defn validate-password-fields [{:auth/keys [min-password-length max-password-length]} @@ -170,6 +167,9 @@ "Returns an error code as a keyword if the :password and/or :password-confirmation params are invalid." (cond + ;; If the user submitted only the password confirmation, assume they intended + ;; to update password but forgot to fill out both fields. + (and (seq password-confirmation) (empty? password)) :auth/passwords-must-match (empty? password) :auth/password-required (not= password password-confirmation) :auth/passwords-must-match (< (count password) min-password-length) @@ -182,7 +182,7 @@ (defmethod account-action :update [{:as req :keys [params session] ::bread/keys [config]}] (let [{:keys [password password-confirmation]} params - update-password? (seq password) + update-password? (or (seq password) (seq password-confirmation)) error-key (when update-password? (validate-password-fields config params)) hash-algo (when update-password? (:auth/hash-algorithm config)) preferences (dissoc params :action :name :lang :password :password-confirmation)] @@ -196,47 +196,68 @@ (into {}) pr-str)))])) +(defmethod bread/effect [::update :delete-session] + [{:keys [conn params]} {user :user}] + (let [session-id (try (Integer. (:dbid params)) (catch Throwable _ nil)) + valid-ids (set (map :db/id (:user/sessions user))) + valid? (contains? valid-ids session-id)] + (when valid? + {:effects + [{:effect/name ::db/transact + :effect/description "Delete a user session." + :effect/key :session-deleted + :conn conn + :txs [[:db/retractEntity session-id]]}]}))) + (defmethod bread/dispatch ::account=> [{:as req :keys [params request-method session] ::bread/keys [dispatcher]}] - (if (= :post request-method) - ;; Account update. - (let [action (keyword (:action params)) - account-update? (= :update action) - [txs error-key] (try - [(account-action req) nil] - (catch clojure.lang.ExceptionInfo e - [nil (-> e ex-data :error-key)]))] - (if txs - {:effects - [(db/txs->effect req txs :effect/description "Update account details")] - :hooks - {::bread/expand - [{:action/name ::ring/redirect - :to (bread/config req :account/account-uri) - :flash (when account-update? {:success-key :account/account-updated}) - :action/description - "Redirect to account page after taking an account action"}]}} - {:hooks - {::bread/expand - [{:action/name ::ring/redirect - :to (bread/config req :account/account-uri) - :flash (when account-update? {:error-key error-key}) - :action/description - "Redirect to account page after an error"}]}})) - ;; Rendering the account page. - (let [id (:db/id (:user session)) - pull (:dispatcher/pull dispatcher)] + (let [id (:db/id (:user session)) + pull (:dispatcher/pull dispatcher) + user-pull {:find [(list 'pull '?e pull) '.] :in '[$ ?e]} + query-user {:expansion/key :user + :expansion/name ::db/query + :expansion/description "Query for all user account data" + :expansion/db (db/database req) + :expansion/args [user-pull id]} + expand-user {:expansion/key :user + :expansion/name ::user + :expansion/description "Expand user data"}] + (if (= :post request-method) + ;; Account update. + (let [action (keyword (:action params)) + account-update? (= :update action) + [txs error-key] (try + [(account-action req) nil] + (catch clojure.lang.ExceptionInfo e + [nil (-> e ex-data :error-key)]))] + (if txs + {:expansions [query-user expand-user] + :effects + [(if account-update? + (db/txs->effect req txs :effect/description "Update account details") + {:effect/name [::update action] + :effect/description "Update account state" + :params params + :conn (db/connection req) + :txs txs})] + :hooks + {::bread/expand + [{:action/name ::ring/redirect + :to (bread/config req :account/account-uri) + :flash (when account-update? {:success-key :account/account-updated}) + :action/description + "Redirect to account page after taking an account action"}]}} + {:hooks + {::bread/expand + [{:action/name ::ring/redirect + :to (bread/config req :account/account-uri) + :flash (when account-update? {:error-key error-key}) + :action/description + "Redirect to account page after an error"}]}})) + ;; Rendering the account page. {:expansions - [{:expansion/key :user - :expansion/name ::db/query - :expansion/description "Query for all user account data" - :expansion/db (db/database req) - :expansion/args [{:find [(list 'pull '?e pull) '.] - :in '[$ ?e]} - id]} - {:expansion/key :user - :expansion/name ::user - :expansion/description "Expand user data"} + [query-user + expand-user {;; TODO => i18n :expansion/key :supported-langs :expansion/name ::bread/value @@ -245,6 +266,7 @@ {;; TODO => i18n :expansion/key :lang-names :expansion/name ::bread/value + :expansion/description "Language names for display" :expansion/value (bread/config req :i18n/lang-names)}]}))) (defn plugin [{:keys [account-uri html-account-header html-account-form diff --git a/test/cms/systems/bread/alpha/plugin/account_test.clj b/test/cms/systems/bread/alpha/plugin/account_test.clj new file mode 100644 index 00000000..3902f074 --- /dev/null +++ b/test/cms/systems/bread/alpha/plugin/account_test.clj @@ -0,0 +1,308 @@ +(ns systems.bread.alpha.plugin.account-test + (:require + [buddy.hashers :as hashers] + [clojure.test :refer [deftest are]] + + [systems.bread.alpha.test-helpers :refer [db->plugin + plugins->loaded + use-db]] + [systems.bread.alpha.core :as bread] + [systems.bread.alpha.database :as db] + [systems.bread.alpha.dispatcher :as dispatcher] + [systems.bread.alpha.i18n :as i18n] + [systems.bread.alpha.plugin.account :as account] + [systems.bread.alpha.plugin.auth :as auth] + [systems.bread.alpha.ring :as ring] + [systems.bread.alpha.schema :as schema])) + +(def db-config + {:db/type :datahike + :db/migrations schema/initial + :db/config {:store {:backend :mem :id "account-test-db"}}}) + +(use-db :each db-config) + +(deftest test-account=> + (let [db-plugin (db->plugin ::FAKEDB) + db-conn (:db/connection (:config db-plugin)) + query-user + {:expansion/args ['{:find [(pull ?e [:user/attrs]) .] + :in [$ ?e]} + 123] + :expansion/db ::FAKEDB + :expansion/description "Query for all user account data" + :expansion/key :user + :expansion/name ::db/query} + expand-user + {:expansion/description "Expand user data" + :expansion/key :user + :expansion/name ::account/user} + success-hook + {:action/name ::ring/redirect + :action/description "Redirect to account page after taking an account action" + :flash {:success-key :account/account-updated} + :to "/account"}] + (are + [expected config req] + (= expected (let [dispatcher {:dispatcher/type ::account/account=> + :dispatcher/pull [:user/attrs]} + {:keys [account-config auth-config]} config + app (plugins->loaded [db-plugin + (i18n/plugin + {:supported-langs [:be :de] + :lang-names {:be "Belarusian" + :de "Deutsche"}}) + (auth/plugin auth-config) + (account/plugin account-config)]) + req* (merge app req {::bread/dispatcher dispatcher})] + (with-redefs [hashers/derive (fn [pw {:keys [alg]}] + (str "[" alg "+" pw "]"))] + (bread/dispatch req*)))) + + ;; Just loading the account page. + {:expansions [query-user + expand-user + {:expansion/description "Supported languages" + :expansion/key :supported-langs + :expansion/name ::bread/value + :expansion/value [:be :de]} + {:expansion/key :lang-names + :expansion/name ::bread/value + :expansion/description "Language names for display" + :expansion/value {:be "Belarusian" + :de "Deutsche"}}]} + {} + {:request-method :get + :session {:user {:db/id 123}}} + + ;; Updating name. + {:expansions + [query-user expand-user] + :effects + [{:effect/name ::db/transact + :effect/key nil + :effect/description "Update account details" + :txs [{:db/id 123 :user/name "Spongebob Squarepants"}] + :conn db-conn}] + :hooks + {::bread/expand + [success-hook]}} + {} + {:request-method :post + :params {:action "update" + :name "Spongebob Squarepants"} + :session {:user {:db/id 123}}} + + ;; Updating preferences. + {:expansions [query-user expand-user] + :effects [{:effect/name ::db/transact + :effect/key nil + :effect/description "Update account details" + :txs [{:db/id 123 + :user/name "Spongebob Squarepants" + :user/preferences (pr-str {:pronouns "he/they" + :timezone "America/Los_Angeles"})}] + :conn db-conn}] + :hooks {::bread/expand [success-hook]}} + {} + {:request-method :post + :params {:action "update" + :name "Spongebob Squarepants" + :pronouns "he/they" + :timezone "America/Los_Angeles"} + :session {:user {:db/id 123}}} + + ;; Any custom fields on the account form are treated as preferences. + {:expansions [query-user expand-user] + :effects [{:effect/name ::db/transact + :effect/key nil + :effect/description "Update account details" + :txs [{:db/id 123 + :user/name "Spongebob Squarepants" + :user/preferences (pr-str {:custom "something" + :other "something else"})}] + :conn db-conn}] + :hooks {::bread/expand [success-hook]}} + {} + {:request-method :post + :params {:action "update" + :name "Spongebob Squarepants" + :custom "something" + :other "something else"} + :session {:user {:db/id 123}}} + + ;; Updating password - mismatched passwords error. + {:hooks {::bread/expand [{:action/name ::ring/redirect + :action/description + "Redirect to account page after an error" + :flash {:error-key :auth/passwords-must-match} + :to "/account"}]}} + {} + {:request-method :post + :params {:action "update" + :name "Spongebob Squarepants" + :password "xyz" + :password-confirmation ""} + :session {:user {:db/id 123}}} + + ;; Updating password - only confirmation submitted. + {:hooks {::bread/expand [{:action/name ::ring/redirect + :action/description + "Redirect to account page after an error" + :flash {:error-key :auth/passwords-must-match} + :to "/account"}]}} + {} + {:request-method :post + :params {:action "update" + :name "Spongebob Squarepants" + :password "" + :password-confirmation "xyz"} + :session {:user {:db/id 123}}} + + ;; Updating password - both fields submitted, but still mismatched + {:hooks {::bread/expand [{:action/name ::ring/redirect + :action/description + "Redirect to account page after an error" + :flash {:error-key :auth/passwords-must-match} + :to "/account"}]}} + {} + {:request-method :post + :params {:action "update" + :name "Spongebob Squarepants" + :password "abc" + :password-confirmation "xyz"} + :session {:user {:db/id 123}}} + + ;; Updating password - too short. + {:hooks {::bread/expand [{:action/name ::ring/redirect + :action/description + "Redirect to account page after an error" + ;; 12 is the default from auth + :flash {:error-key [:auth/password-must-be-at-least 12]} + :to "/account"}]}} + {} + {:request-method :post + :params {:action "update" + :name "Spongebob Squarepants" + :password "tooshort" + :password-confirmation "tooshort"} + :session {:user {:db/id 123}}} + + ;; Updating password - too short with custom auth config. + {:hooks {::bread/expand [{:action/name ::ring/redirect + :action/description + "Redirect to account page after an error" + ;; 12 is the default from auth + :flash {:error-key [:auth/password-must-be-at-least 8]} + :to "/account"}]}} + {:auth-config {:min-password-length 8}} + {:request-method :post + :params {:action "update" + :name "Spongebob Squarepants" + :password "2shrt" + :password-confirmation "2shrt"} + :session {:user {:db/id 123}}} + + ;; Updating password - just long enough with custom config. + {:expansions [query-user expand-user] + :effects [{:effect/name ::db/transact + :effect/description "Update account details" + :effect/key nil + :txs [{:db/id 123 + :user/name "Spongebob Squarepants" + :user/password "[:bcrypt+blake2b-512+password]"}] + :conn db-conn}] + :hooks {::bread/expand [success-hook]}} + {:auth-config {:min-password-length 8}} + {:request-method :post + :params {:action "update" + :name "Spongebob Squarepants" + :password "password" + :password-confirmation "password"} + :session {:user {:db/id 123}}} + + ;; Updating password - meets default 12-char minimum. + {:expansions [query-user expand-user] + :effects [{:effect/name ::db/transact + :effect/description "Update account details" + :effect/key nil + :txs [{:db/id 123 + :user/name "Spongebob Squarepants" + :user/password "[:bcrypt+blake2b-512+password1234]"}] + :conn db-conn}] + :hooks {::bread/expand [success-hook]}} + {} + {:request-method :post + :params {:action "update" + :name "Spongebob Squarepants" + :password "password1234" + :password-confirmation "password1234"} + :session {:user {:db/id 123}}} + + ;; Updating password - meets default 12-char minimum. + {:expansions [query-user expand-user] + :effects [{:effect/name ::db/transact + :effect/description "Update account details" + :effect/key nil + :txs [{:db/id 123 + :user/name "Spongebob Squarepants" + :user/password (str + "[:bcrypt+blake2b-512+" + "twelve_chars" + "twelve_chars" + "twelve_chars" + "twelve_chars" + "twelve_chars" + "twelve_chars" + "]")}] + :conn db-conn}] + :hooks {::bread/expand [success-hook]}} + {} + (let [;; 6 * 12 = 72 + long-password (apply str (repeat 6 "twelve_chars"))] + {:request-method :post + :params {:action "update" + :name "Spongebob Squarepants" + :password long-password + :password-confirmation long-password} + :session {:user {:db/id 123}}}) + + ;; Updating password - too long! + {:hooks {::bread/expand [{:action/name ::ring/redirect + :action/description + "Redirect to account page after an error" + ;; 12 is the default from auth + :flash {:error-key [:auth/password-must-be-at-most 72]} + :to "/account"}]}} + {} + (let [;; 1 + 6 * 12 = 73 + long-password (apply str "x" (repeat 6 "twelve_chars"))] + {:request-method :post + :params {:action "update" + :name "Spongebob Squarepants" + :password long-password + :password-confirmation long-password} + :session {:user {:db/id 123}}}) + + ;; Updating password - too long with custom auth config. + {:hooks {::bread/expand [{:action/name ::ring/redirect + :action/description + "Redirect to account page after an error" + ;; 12 is the default from auth + :flash {:error-key [:auth/password-must-be-at-most 71]} + :to "/account"}]}} + {:auth-config {:max-password-length 71}} + (let [;; 6 * 12 = 72 + long-password (apply str (repeat 6 "twelve_chars"))] + {:request-method :post + :params {:action "update" + :name "Spongebob Squarepants" + :password long-password + :password-confirmation long-password} + :session {:user {:db/id 123}}}) + + ,))) + +(comment + (require '[kaocha.repl :as k]) + (k/run {:color? false})) From b1d7d080b109716fea9880dc2f0f0bd14013e6ff Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Mon, 30 Mar 2026 21:00:36 -0700 Subject: [PATCH 04/10] test :delete-session action --- plugins/auth/account.i18n.edn | 1 + .../auth/systems/bread/alpha/plugin/account.cljc | 8 +++++--- .../systems/bread/alpha/plugin/account_test.clj | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/plugins/auth/account.i18n.edn b/plugins/auth/account.i18n.edn index f20ca0f4..afcc7d97 100644 --- a/plugins/auth/account.i18n.edn +++ b/plugins/auth/account.i18n.edn @@ -15,6 +15,7 @@ :pronouns "Pronouns" :pronouns-example "they/them/theirs" :save "Save" + :session-deleted "Session deleted." :timezone "Timezone" :your-sessions "Your login sessions" } diff --git a/plugins/auth/systems/bread/alpha/plugin/account.cljc b/plugins/auth/systems/bread/alpha/plugin/account.cljc index 85c9e050..8e2b0fff 100644 --- a/plugins/auth/systems/bread/alpha/plugin/account.cljc +++ b/plugins/auth/systems/bread/alpha/plugin/account.cljc @@ -226,6 +226,9 @@ ;; Account update. (let [action (keyword (:action params)) account-update? (= :update action) + success-key (if account-update? + :account/account-updated + :account/session-deleted) [txs error-key] (try [(account-action req) nil] (catch clojure.lang.ExceptionInfo e @@ -238,13 +241,12 @@ {:effect/name [::update action] :effect/description "Update account state" :params params - :conn (db/connection req) - :txs txs})] + :conn (db/connection req)})] :hooks {::bread/expand [{:action/name ::ring/redirect :to (bread/config req :account/account-uri) - :flash (when account-update? {:success-key :account/account-updated}) + :flash {:success-key success-key} :action/description "Redirect to account page after taking an account action"}]}} {:hooks diff --git a/test/cms/systems/bread/alpha/plugin/account_test.clj b/test/cms/systems/bread/alpha/plugin/account_test.clj index 3902f074..150c6494 100644 --- a/test/cms/systems/bread/alpha/plugin/account_test.clj +++ b/test/cms/systems/bread/alpha/plugin/account_test.clj @@ -301,6 +301,21 @@ :password-confirmation long-password} :session {:user {:db/id 123}}}) + ;; Deleting a session. + {:expansions [query-user expand-user] + :effects [{:effect/name [::account/update :delete-session] + :effect/description "Update account state" + :params {:action "delete-session" :dbid "456"} + :conn db-conn}] + :hooks {::bread/expand [(assoc-in success-hook + [:flash :success-key] + :account/session-deleted)]}} + {} + {:request-method :post + :params {:action "delete-session" + :dbid "456"} + :session {:user {:db/id 123}}} + ,))) (comment From 21869d3ee6a7182e2b9605e6435a2c4043437500 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Mon, 30 Mar 2026 22:00:34 -0700 Subject: [PATCH 05/10] validate action, improve test coverage --- plugins/auth/account.i18n.edn | 1 + .../systems/bread/alpha/plugin/account.cljc | 6 ++- .../bread/alpha/plugin/account_test.clj | 47 +++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/plugins/auth/account.i18n.edn b/plugins/auth/account.i18n.edn index afcc7d97..4706d914 100644 --- a/plugins/auth/account.i18n.edn +++ b/plugins/auth/account.i18n.edn @@ -8,6 +8,7 @@ :account-updated "Account details have been updated." :datetime-format-default "EEE, LLL d 'at' h:mm a" :date-format-default "EEE, LLL d" + :invalid-action "Invalid action." :leave-passwords-blank "Leave password fields blank to keep your current password." :name "Name" :email "Email" diff --git a/plugins/auth/systems/bread/alpha/plugin/account.cljc b/plugins/auth/systems/bread/alpha/plugin/account.cljc index 8e2b0fff..9fbdc7a8 100644 --- a/plugins/auth/systems/bread/alpha/plugin/account.cljc +++ b/plugins/auth/systems/bread/alpha/plugin/account.cljc @@ -157,6 +157,10 @@ (defmulti account-action (fn [{:keys [params]}] (keyword (:action params)))) +(defmethod account-action :default [_] + ;; TODO standardize generic error-key? + (throw (ex-info "Invalid action" {:error-key :account/invalid-action}))) + (defmethod account-action :delete-session [{:keys [params]}] (when-let [id (try (Integer. (:dbid params)) (catch Throwable _ nil))] {:db/id id})) @@ -253,7 +257,7 @@ {::bread/expand [{:action/name ::ring/redirect :to (bread/config req :account/account-uri) - :flash (when account-update? {:error-key error-key}) + :flash (when error-key {:error-key error-key}) :action/description "Redirect to account page after an error"}]}})) ;; Rendering the account page. diff --git a/test/cms/systems/bread/alpha/plugin/account_test.clj b/test/cms/systems/bread/alpha/plugin/account_test.clj index 150c6494..7df708aa 100644 --- a/test/cms/systems/bread/alpha/plugin/account_test.clj +++ b/test/cms/systems/bread/alpha/plugin/account_test.clj @@ -112,6 +112,53 @@ :timezone "America/Los_Angeles"} :session {:user {:db/id 123}}} + ;; Updating preferences; custom account-uri. + {:expansions [query-user expand-user] + :effects [{:effect/name ::db/transact + :effect/key nil + :effect/description "Update account details" + :txs [{:db/id 123 + :user/name "Spongebob Squarepants" + :user/preferences (pr-str {:pronouns "he/they" + :timezone "America/Los_Angeles"})}] + :conn db-conn}] + :hooks {::bread/expand [(assoc success-hook :to "/custom")]}} + {:account-config {:account-uri "/custom"}} + {:request-method :post + :params {:action "update" + :name "Spongebob Squarepants" + :pronouns "he/they" + :timezone "America/Los_Angeles"} + :session {:user {:db/id 123}}} + + ;; Invalid action. + {:hooks {::bread/expand [{:action/name ::ring/redirect + :action/description + "Redirect to account page after an error" + :flash {:error-key :account/invalid-action} + :to "/account"}]}} + {} + {:request-method :post + :params {:action "booboo" + :name "Spongebob Squarepants" + :pronouns "he/they" + :timezone "America/Los_Angeles"} + :session {:user {:db/id 123}}} + + ;; Invalid action; custom URI. + {:hooks {::bread/expand [{:action/name ::ring/redirect + :action/description + "Redirect to account page after an error" + :flash {:error-key :account/invalid-action} + :to "/custom"}]}} + {:account-config {:account-uri "/custom"}} + {:request-method :post + :params {:action "booboo" + :name "Spongebob Squarepants" + :pronouns "he/they" + :timezone "America/Los_Angeles"} + :session {:user {:db/id 123}}} + ;; Any custom fields on the account form are treated as preferences. {:expansions [query-user expand-user] :effects [{:effect/name ::db/transact From 31c0b8ce8a38bf17c0c89c4be4c4d0912f2aed14 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Mon, 30 Mar 2026 22:24:35 -0700 Subject: [PATCH 06/10] s/update/update-details --- .../systems/bread/alpha/cms/theme/rise.cljc | 2 +- .../systems/bread/alpha/plugin/account.cljc | 4 +-- .../bread/alpha/plugin/account_test.clj | 28 +++++++++---------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/cms/themes/rise/src/systems/bread/alpha/cms/theme/rise.cljc b/cms/themes/rise/src/systems/bread/alpha/cms/theme/rise.cljc index a3828f2e..467c41bf 100644 --- a/cms/themes/rise/src/systems/bread/alpha/cms/theme/rise.cljc +++ b/cms/themes/rise/src/systems/bread/alpha/cms/theme/rise.cljc @@ -666,7 +666,7 @@ (ErrorMessage {:message (i18n/t i18n error-key)}))]) (defmethod Section :save [{:keys [i18n]} _] - (Submit (:account/save i18n) :name :action :value "update")) + (Submit (:account/save i18n) :name :action :value "update-details")) (defn- CustomizingSection [_] {:id :customizing diff --git a/plugins/auth/systems/bread/alpha/plugin/account.cljc b/plugins/auth/systems/bread/alpha/plugin/account.cljc index 9fbdc7a8..e7610dfb 100644 --- a/plugins/auth/systems/bread/alpha/plugin/account.cljc +++ b/plugins/auth/systems/bread/alpha/plugin/account.cljc @@ -184,7 +184,7 @@ (defn- hook-preference [req [k v]] [k (bread/hook req [::preference k] v)]) -(defmethod account-action :update [{:as req :keys [params session] ::bread/keys [config]}] +(defmethod account-action :update-details [{:as req :keys [params session] ::bread/keys [config]}] (let [{:keys [password password-confirmation]} params update-password? (or (seq password) (seq password-confirmation)) error-key (when update-password? (validate-password-fields config params)) @@ -229,7 +229,7 @@ (if (= :post request-method) ;; Account update. (let [action (keyword (:action params)) - account-update? (= :update action) + account-update? (= :update-details action) success-key (if account-update? :account/account-updated :account/session-deleted) diff --git a/test/cms/systems/bread/alpha/plugin/account_test.clj b/test/cms/systems/bread/alpha/plugin/account_test.clj index 7df708aa..a479a486 100644 --- a/test/cms/systems/bread/alpha/plugin/account_test.clj +++ b/test/cms/systems/bread/alpha/plugin/account_test.clj @@ -89,7 +89,7 @@ [success-hook]}} {} {:request-method :post - :params {:action "update" + :params {:action "update-details" :name "Spongebob Squarepants"} :session {:user {:db/id 123}}} @@ -106,7 +106,7 @@ :hooks {::bread/expand [success-hook]}} {} {:request-method :post - :params {:action "update" + :params {:action "update-details" :name "Spongebob Squarepants" :pronouns "he/they" :timezone "America/Los_Angeles"} @@ -125,7 +125,7 @@ :hooks {::bread/expand [(assoc success-hook :to "/custom")]}} {:account-config {:account-uri "/custom"}} {:request-method :post - :params {:action "update" + :params {:action "update-details" :name "Spongebob Squarepants" :pronouns "he/they" :timezone "America/Los_Angeles"} @@ -172,7 +172,7 @@ :hooks {::bread/expand [success-hook]}} {} {:request-method :post - :params {:action "update" + :params {:action "update-details" :name "Spongebob Squarepants" :custom "something" :other "something else"} @@ -186,7 +186,7 @@ :to "/account"}]}} {} {:request-method :post - :params {:action "update" + :params {:action "update-details" :name "Spongebob Squarepants" :password "xyz" :password-confirmation ""} @@ -200,7 +200,7 @@ :to "/account"}]}} {} {:request-method :post - :params {:action "update" + :params {:action "update-details" :name "Spongebob Squarepants" :password "" :password-confirmation "xyz"} @@ -214,7 +214,7 @@ :to "/account"}]}} {} {:request-method :post - :params {:action "update" + :params {:action "update-details" :name "Spongebob Squarepants" :password "abc" :password-confirmation "xyz"} @@ -229,7 +229,7 @@ :to "/account"}]}} {} {:request-method :post - :params {:action "update" + :params {:action "update-details" :name "Spongebob Squarepants" :password "tooshort" :password-confirmation "tooshort"} @@ -244,7 +244,7 @@ :to "/account"}]}} {:auth-config {:min-password-length 8}} {:request-method :post - :params {:action "update" + :params {:action "update-details" :name "Spongebob Squarepants" :password "2shrt" :password-confirmation "2shrt"} @@ -262,7 +262,7 @@ :hooks {::bread/expand [success-hook]}} {:auth-config {:min-password-length 8}} {:request-method :post - :params {:action "update" + :params {:action "update-details" :name "Spongebob Squarepants" :password "password" :password-confirmation "password"} @@ -280,7 +280,7 @@ :hooks {::bread/expand [success-hook]}} {} {:request-method :post - :params {:action "update" + :params {:action "update-details" :name "Spongebob Squarepants" :password "password1234" :password-confirmation "password1234"} @@ -308,7 +308,7 @@ (let [;; 6 * 12 = 72 long-password (apply str (repeat 6 "twelve_chars"))] {:request-method :post - :params {:action "update" + :params {:action "update-details" :name "Spongebob Squarepants" :password long-password :password-confirmation long-password} @@ -325,7 +325,7 @@ (let [;; 1 + 6 * 12 = 73 long-password (apply str "x" (repeat 6 "twelve_chars"))] {:request-method :post - :params {:action "update" + :params {:action "update-details" :name "Spongebob Squarepants" :password long-password :password-confirmation long-password} @@ -342,7 +342,7 @@ (let [;; 6 * 12 = 72 long-password (apply str (repeat 6 "twelve_chars"))] {:request-method :post - :params {:action "update" + :params {:action "update-details" :name "Spongebob Squarepants" :password long-password :password-confirmation long-password} From 8b36281aaced03ee9ed6124af8d93c679b2dc51a Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Mon, 30 Mar 2026 22:51:34 -0700 Subject: [PATCH 07/10] refactor --- .../systems/bread/alpha/plugin/account.cljc | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/plugins/auth/systems/bread/alpha/plugin/account.cljc b/plugins/auth/systems/bread/alpha/plugin/account.cljc index e7610dfb..253b1ea3 100644 --- a/plugins/auth/systems/bread/alpha/plugin/account.cljc +++ b/plugins/auth/systems/bread/alpha/plugin/account.cljc @@ -155,15 +155,18 @@ (update $ :user/preferences edn/read-string) (s/transform [:user/sessions s/ALL :session/data] edn/read-string $)))) -(defmulti account-action (fn [{:keys [params]}] (keyword (:action params)))) +(defmulti effects (fn [{:keys [params]}] (keyword (:action params)))) -(defmethod account-action :default [_] +(defmethod effects :default [_] ;; TODO standardize generic error-key? (throw (ex-info "Invalid action" {:error-key :account/invalid-action}))) -(defmethod account-action :delete-session [{:keys [params]}] - (when-let [id (try (Integer. (:dbid params)) (catch Throwable _ nil))] - {:db/id id})) +(defmethod effects :delete-session [{:as req :keys [params]}] + (when (try (Integer. (:dbid params)) (catch Throwable _ nil)) + [{:effect/name [::update :delete-session] + :effect/description "Update account state" + :params params + :conn (db/connection req)}])) (defn validate-password-fields [{:auth/keys [min-password-length max-password-length]} @@ -184,21 +187,27 @@ (defn- hook-preference [req [k v]] [k (bread/hook req [::preference k] v)]) -(defmethod account-action :update-details [{:as req :keys [params session] ::bread/keys [config]}] +(defmethod effects :update-details + [{:as req :keys [params session] ::bread/keys [config]}] (let [{:keys [password password-confirmation]} params update-password? (or (seq password) (seq password-confirmation)) error-key (when update-password? (validate-password-fields config params)) hash-algo (when update-password? (:auth/hash-algorithm config)) preferences (dissoc params :action :name :lang :password :password-confirmation)] (when error-key (throw (ex-info "Invalid password" {:error-key error-key}))) - [(cond-> {:db/id (:db/id (:user session)) :user/name (:name params)} - (:lang params) (assoc :user/lang (keyword (:lang params))) - update-password? (assoc :user/password - (hashers/derive password {:alg hash-algo})) - (seq preferences) (assoc :user/preferences (->> preferences - (map (partial hook-preference req)) - (into {}) - pr-str)))])) + [{:effect/name ::db/transact + :effect/description "Update account details" + :effect/key nil + :conn (db/connection req) + :txs + [(cond-> {:db/id (:db/id (:user session)) :user/name (:name params)} + (:lang params) (assoc :user/lang (keyword (:lang params))) + update-password? (assoc :user/password + (hashers/derive password {:alg hash-algo})) + (seq preferences) (assoc :user/preferences (->> preferences + (map (partial hook-preference req)) + (into {}) + pr-str)))]}])) (defmethod bread/effect [::update :delete-session] [{:keys [conn params]} {user :user}] @@ -233,33 +242,27 @@ success-key (if account-update? :account/account-updated :account/session-deleted) - [txs error-key] (try - [(account-action req) nil] - (catch clojure.lang.ExceptionInfo e - [nil (-> e ex-data :error-key)]))] - (if txs - {:expansions [query-user expand-user] - :effects - [(if account-update? - (db/txs->effect req txs :effect/description "Update account details") - {:effect/name [::update action] - :effect/description "Update account state" - :params params - :conn (db/connection req)})] - :hooks + [effects error-key] (try + [(effects req) nil] + (catch clojure.lang.ExceptionInfo e + [nil (-> e ex-data :error-key)]))] + (if error-key + {:hooks {::bread/expand [{:action/name ::ring/redirect :to (bread/config req :account/account-uri) - :flash {:success-key success-key} + :flash (when error-key {:error-key error-key}) :action/description - "Redirect to account page after taking an account action"}]}} - {:hooks + "Redirect to account page after an error"}]}} + {:expansions [query-user expand-user] + :effects effects + :hooks {::bread/expand [{:action/name ::ring/redirect :to (bread/config req :account/account-uri) - :flash (when error-key {:error-key error-key}) + :flash {:success-key success-key} :action/description - "Redirect to account page after an error"}]}})) + "Redirect to account page after taking an account action"}]}})) ;; Rendering the account page. {:expansions [query-user From e2178530fd4077a72a9d7b475b75c5997f508556 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Mon, 30 Mar 2026 23:35:28 -0700 Subject: [PATCH 08/10] support passing success, error keys to ::db/transact --- src/systems/bread/alpha/database.cljc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/systems/bread/alpha/database.cljc b/src/systems/bread/alpha/database.cljc index 95261b67..3ddd3e64 100644 --- a/src/systems/bread/alpha/database.cljc +++ b/src/systems/bread/alpha/database.cljc @@ -118,8 +118,13 @@ (contains? ks (migration-key migration)))) (defmethod bread/effect ::transact - [{:keys [conn txs]} _] - (transact conn {:tx-data txs})) + [{:keys [conn txs success-key error-key]} _] + (try + {:db (transact conn {:tx-data txs}) + :flash {:success-key success-key}} + (catch Throwable e + {:ex e + :flash {:error-key error-key}}))) (defn txs->effect [req txs & {desc :effect/description k :effect/key From a1957de81bfbed184eee4be7129ed9fe4fe852e0 Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Mon, 30 Mar 2026 23:35:45 -0700 Subject: [PATCH 09/10] fix account update flash --- .../systems/bread/alpha/plugin/account.cljc | 18 ++++-- .../bread/alpha/plugin/account_test.clj | 64 ++++++++++--------- 2 files changed, 46 insertions(+), 36 deletions(-) diff --git a/plugins/auth/systems/bread/alpha/plugin/account.cljc b/plugins/auth/systems/bread/alpha/plugin/account.cljc index 253b1ea3..2c5d46b8 100644 --- a/plugins/auth/systems/bread/alpha/plugin/account.cljc +++ b/plugins/auth/systems/bread/alpha/plugin/account.cljc @@ -165,6 +165,8 @@ (when (try (Integer. (:dbid params)) (catch Throwable _ nil)) [{:effect/name [::update :delete-session] :effect/description "Update account state" + :effect/key :delete-session + :success-key :account/session-deleted :params params :conn (db/connection req)}])) @@ -197,7 +199,8 @@ (when error-key (throw (ex-info "Invalid password" {:error-key error-key}))) [{:effect/name ::db/transact :effect/description "Update account details" - :effect/key nil + :effect/key :update-details + :success-key :account/account-updated :conn (db/connection req) :txs [(cond-> {:db/id (:db/id (:user session)) :user/name (:name params)} @@ -210,7 +213,7 @@ pr-str)))]}])) (defmethod bread/effect [::update :delete-session] - [{:keys [conn params]} {user :user}] + [{:keys [conn params success-key]} {user :user}] (let [session-id (try (Integer. (:dbid params)) (catch Throwable _ nil)) valid-ids (set (map :db/id (:user/sessions user))) valid? (contains? valid-ids session-id)] @@ -218,7 +221,8 @@ {:effects [{:effect/name ::db/transact :effect/description "Delete a user session." - :effect/key :session-deleted + :effect/key :delete-session + :success-key success-key :conn conn :txs [[:db/retractEntity session-id]]}]}))) @@ -248,7 +252,7 @@ [nil (-> e ex-data :error-key)]))] (if error-key {:hooks - {::bread/expand + {::bread/render [{:action/name ::ring/redirect :to (bread/config req :account/account-uri) :flash (when error-key {:error-key error-key}) @@ -257,10 +261,10 @@ {:expansions [query-user expand-user] :effects effects :hooks - {::bread/expand - [{:action/name ::ring/redirect + {::bread/render + [{:action/name ::ring/effect-redirect :to (bread/config req :account/account-uri) - :flash {:success-key success-key} + :effect/key action :action/description "Redirect to account page after taking an account action"}]}})) ;; Rendering the account page. diff --git a/test/cms/systems/bread/alpha/plugin/account_test.clj b/test/cms/systems/bread/alpha/plugin/account_test.clj index a479a486..18408dff 100644 --- a/test/cms/systems/bread/alpha/plugin/account_test.clj +++ b/test/cms/systems/bread/alpha/plugin/account_test.clj @@ -38,9 +38,9 @@ :expansion/key :user :expansion/name ::account/user} success-hook - {:action/name ::ring/redirect + {:action/name ::ring/effect-redirect :action/description "Redirect to account page after taking an account action" - :flash {:success-key :account/account-updated} + :effect/key :update-details :to "/account"}] (are [expected config req] @@ -80,13 +80,13 @@ [query-user expand-user] :effects [{:effect/name ::db/transact - :effect/key nil + :effect/key :update-details :effect/description "Update account details" + :success-key :account/account-updated :txs [{:db/id 123 :user/name "Spongebob Squarepants"}] :conn db-conn}] :hooks - {::bread/expand - [success-hook]}} + {::bread/render [success-hook]}} {} {:request-method :post :params {:action "update-details" @@ -96,14 +96,15 @@ ;; Updating preferences. {:expansions [query-user expand-user] :effects [{:effect/name ::db/transact - :effect/key nil + :effect/key :update-details :effect/description "Update account details" + :success-key :account/account-updated :txs [{:db/id 123 :user/name "Spongebob Squarepants" :user/preferences (pr-str {:pronouns "he/they" :timezone "America/Los_Angeles"})}] :conn db-conn}] - :hooks {::bread/expand [success-hook]}} + :hooks {::bread/render [success-hook]}} {} {:request-method :post :params {:action "update-details" @@ -115,14 +116,15 @@ ;; Updating preferences; custom account-uri. {:expansions [query-user expand-user] :effects [{:effect/name ::db/transact - :effect/key nil + :effect/key :update-details :effect/description "Update account details" + :success-key :account/account-updated :txs [{:db/id 123 :user/name "Spongebob Squarepants" :user/preferences (pr-str {:pronouns "he/they" :timezone "America/Los_Angeles"})}] :conn db-conn}] - :hooks {::bread/expand [(assoc success-hook :to "/custom")]}} + :hooks {::bread/render [(assoc success-hook :to "/custom")]}} {:account-config {:account-uri "/custom"}} {:request-method :post :params {:action "update-details" @@ -132,7 +134,7 @@ :session {:user {:db/id 123}}} ;; Invalid action. - {:hooks {::bread/expand [{:action/name ::ring/redirect + {:hooks {::bread/render [{:action/name ::ring/redirect :action/description "Redirect to account page after an error" :flash {:error-key :account/invalid-action} @@ -146,7 +148,7 @@ :session {:user {:db/id 123}}} ;; Invalid action; custom URI. - {:hooks {::bread/expand [{:action/name ::ring/redirect + {:hooks {::bread/render [{:action/name ::ring/redirect :action/description "Redirect to account page after an error" :flash {:error-key :account/invalid-action} @@ -162,14 +164,15 @@ ;; Any custom fields on the account form are treated as preferences. {:expansions [query-user expand-user] :effects [{:effect/name ::db/transact - :effect/key nil + :effect/key :update-details :effect/description "Update account details" + :success-key :account/account-updated :txs [{:db/id 123 :user/name "Spongebob Squarepants" :user/preferences (pr-str {:custom "something" :other "something else"})}] :conn db-conn}] - :hooks {::bread/expand [success-hook]}} + :hooks {::bread/render [success-hook]}} {} {:request-method :post :params {:action "update-details" @@ -179,7 +182,7 @@ :session {:user {:db/id 123}}} ;; Updating password - mismatched passwords error. - {:hooks {::bread/expand [{:action/name ::ring/redirect + {:hooks {::bread/render [{:action/name ::ring/redirect :action/description "Redirect to account page after an error" :flash {:error-key :auth/passwords-must-match} @@ -193,7 +196,7 @@ :session {:user {:db/id 123}}} ;; Updating password - only confirmation submitted. - {:hooks {::bread/expand [{:action/name ::ring/redirect + {:hooks {::bread/render [{:action/name ::ring/redirect :action/description "Redirect to account page after an error" :flash {:error-key :auth/passwords-must-match} @@ -207,7 +210,7 @@ :session {:user {:db/id 123}}} ;; Updating password - both fields submitted, but still mismatched - {:hooks {::bread/expand [{:action/name ::ring/redirect + {:hooks {::bread/render [{:action/name ::ring/redirect :action/description "Redirect to account page after an error" :flash {:error-key :auth/passwords-must-match} @@ -221,7 +224,7 @@ :session {:user {:db/id 123}}} ;; Updating password - too short. - {:hooks {::bread/expand [{:action/name ::ring/redirect + {:hooks {::bread/render [{:action/name ::ring/redirect :action/description "Redirect to account page after an error" ;; 12 is the default from auth @@ -236,7 +239,7 @@ :session {:user {:db/id 123}}} ;; Updating password - too short with custom auth config. - {:hooks {::bread/expand [{:action/name ::ring/redirect + {:hooks {::bread/render [{:action/name ::ring/redirect :action/description "Redirect to account page after an error" ;; 12 is the default from auth @@ -254,12 +257,13 @@ {:expansions [query-user expand-user] :effects [{:effect/name ::db/transact :effect/description "Update account details" - :effect/key nil + :effect/key :update-details + :success-key :account/account-updated :txs [{:db/id 123 :user/name "Spongebob Squarepants" :user/password "[:bcrypt+blake2b-512+password]"}] :conn db-conn}] - :hooks {::bread/expand [success-hook]}} + :hooks {::bread/render [success-hook]}} {:auth-config {:min-password-length 8}} {:request-method :post :params {:action "update-details" @@ -272,12 +276,13 @@ {:expansions [query-user expand-user] :effects [{:effect/name ::db/transact :effect/description "Update account details" - :effect/key nil + :effect/key :update-details + :success-key :account/account-updated :txs [{:db/id 123 :user/name "Spongebob Squarepants" :user/password "[:bcrypt+blake2b-512+password1234]"}] :conn db-conn}] - :hooks {::bread/expand [success-hook]}} + :hooks {::bread/render [success-hook]}} {} {:request-method :post :params {:action "update-details" @@ -290,7 +295,8 @@ {:expansions [query-user expand-user] :effects [{:effect/name ::db/transact :effect/description "Update account details" - :effect/key nil + :effect/key :update-details + :success-key :account/account-updated :txs [{:db/id 123 :user/name "Spongebob Squarepants" :user/password (str @@ -303,7 +309,7 @@ "twelve_chars" "]")}] :conn db-conn}] - :hooks {::bread/expand [success-hook]}} + :hooks {::bread/render [success-hook]}} {} (let [;; 6 * 12 = 72 long-password (apply str (repeat 6 "twelve_chars"))] @@ -315,7 +321,7 @@ :session {:user {:db/id 123}}}) ;; Updating password - too long! - {:hooks {::bread/expand [{:action/name ::ring/redirect + {:hooks {::bread/render [{:action/name ::ring/redirect :action/description "Redirect to account page after an error" ;; 12 is the default from auth @@ -332,7 +338,7 @@ :session {:user {:db/id 123}}}) ;; Updating password - too long with custom auth config. - {:hooks {::bread/expand [{:action/name ::ring/redirect + {:hooks {::bread/render [{:action/name ::ring/redirect :action/description "Redirect to account page after an error" ;; 12 is the default from auth @@ -352,11 +358,11 @@ {:expansions [query-user expand-user] :effects [{:effect/name [::account/update :delete-session] :effect/description "Update account state" + :effect/key :delete-session + :success-key :account/session-deleted :params {:action "delete-session" :dbid "456"} :conn db-conn}] - :hooks {::bread/expand [(assoc-in success-hook - [:flash :success-key] - :account/session-deleted)]}} + :hooks {::bread/render [(assoc success-hook :effect/key :delete-session)]}} {} {:request-method :post :params {:action "delete-session" From a48ec773898bde5f12748d6121c7541111701dea Mon Sep 17 00:00:00 2001 From: Coby Tamayo Date: Mon, 30 Mar 2026 23:56:00 -0700 Subject: [PATCH 10/10] test :delete-session --- .../systems/bread/alpha/plugin/account.cljc | 13 +-- .../bread/alpha/plugin/account_test.clj | 99 +++++++++++++++++++ 2 files changed, 103 insertions(+), 9 deletions(-) diff --git a/plugins/auth/systems/bread/alpha/plugin/account.cljc b/plugins/auth/systems/bread/alpha/plugin/account.cljc index 2c5d46b8..b65dad3b 100644 --- a/plugins/auth/systems/bread/alpha/plugin/account.cljc +++ b/plugins/auth/systems/bread/alpha/plugin/account.cljc @@ -213,7 +213,7 @@ pr-str)))]}])) (defmethod bread/effect [::update :delete-session] - [{:keys [conn params success-key]} {user :user}] + [{k :effect/key :keys [conn params success-key]} {user :user}] (let [session-id (try (Integer. (:dbid params)) (catch Throwable _ nil)) valid-ids (set (map :db/id (:user/sessions user))) valid? (contains? valid-ids session-id)] @@ -221,7 +221,7 @@ {:effects [{:effect/name ::db/transact :effect/description "Delete a user session." - :effect/key :delete-session + :effect/key k :success-key success-key :conn conn :txs [[:db/retractEntity session-id]]}]}))) @@ -241,12 +241,7 @@ :expansion/description "Expand user data"}] (if (= :post request-method) ;; Account update. - (let [action (keyword (:action params)) - account-update? (= :update-details action) - success-key (if account-update? - :account/account-updated - :account/session-deleted) - [effects error-key] (try + (let [[effects error-key] (try [(effects req) nil] (catch clojure.lang.ExceptionInfo e [nil (-> e ex-data :error-key)]))] @@ -264,7 +259,7 @@ {::bread/render [{:action/name ::ring/effect-redirect :to (bread/config req :account/account-uri) - :effect/key action + :effect/key (keyword (:action params)) :action/description "Redirect to account page after taking an account action"}]}})) ;; Rendering the account page. diff --git a/test/cms/systems/bread/alpha/plugin/account_test.clj b/test/cms/systems/bread/alpha/plugin/account_test.clj index 18408dff..bf05d791 100644 --- a/test/cms/systems/bread/alpha/plugin/account_test.clj +++ b/test/cms/systems/bread/alpha/plugin/account_test.clj @@ -371,6 +371,105 @@ ,))) +(deftest test-delete-session-effect + (are + [expected effect data] + (= expected (bread/effect effect data)) + + ;; Anonymous, no params. + nil + {:effect/name [::account/update :delete-session] + :effect/description "Update account state" + :effect/key :delete-session + :success-key :account/session-deleted + :params nil + :conn ::FAKEDB} + {:user nil} + + ;; Anonymous attempt to delete a session. + nil + {:effect/name [::account/update :delete-session] + :effect/description "Update account state" + :effect/key :delete-session + :success-key :account/session-deleted + :params {:dbid "345"} + :conn ::FAKEDB} + {:user nil} + + ;; Invalid session id. + nil + {:effect/name [::account/update :delete-session] + :effect/description "Update account state" + :effect/key :delete-session + :success-key :account/session-deleted + :params {:dbid "invalid"} + :conn ::FAKEDB} + {:user {:user/sessions [{:db/id 234} {:db/id 456} {:db/id 567}]}} + + ;; Invalid session id. + nil + {:effect/name [::account/update :delete-session] + :effect/description "Update account state" + :effect/key :delete-session + :success-key :account/session-deleted + :params {:dbid ""} + :conn ::FAKEDB} + {:user {:user/sessions [{:db/id 234} {:db/id 456} {:db/id 567}]}} + + ;; Invalid session id. + nil + {:effect/name [::account/update :delete-session] + :effect/description "Update account state" + :effect/key :delete-session + :success-key :account/session-deleted + :params {:dbid nil} + :conn ::FAKEDB} + {:user {:user/sessions [{:db/id 234} {:db/id 456} {:db/id 567}]}} + + ;; Attempt to delete a different user's session. + nil + {:effect/name [::account/update :delete-session] + :effect/description "Update account state" + :effect/key :delete-session + :success-key :account/session-deleted + :params {:dbid "345"} + :conn ::FAKEDB} + {:user {:user/sessions [{:db/id 234} {:db/id 456} {:db/id 567}]}} + + ;; Happy path. + {:effects + [{:effect/name ::db/transact + :effect/description "Delete a user session." + :effect/key :delete-session + :success-key :account/session-deleted + :conn ::FAKEDB + :txs [[:db/retractEntity 123]]}]} + {:effect/name [::account/update :delete-session] + :effect/description "Update account state" + :effect/key :delete-session + :success-key :account/session-deleted + :params {:dbid "123"} + :conn ::FAKEDB} + {:user {:user/sessions [{:db/id 123}]}} + + ;; Happy path; more than one session. + {:effects + [{:effect/name ::db/transact + :effect/description "Delete a user session." + :effect/key :delete-session + :success-key :account/session-deleted + :conn ::FAKEDB + :txs [[:db/retractEntity 456]]}]} + {:effect/name [::account/update :delete-session] + :effect/description "Update account state" + :effect/key :delete-session + :success-key :account/session-deleted + :params {:dbid "456"} + :conn ::FAKEDB} + {:user {:user/sessions [{:db/id 123} {:db/id 456}]}} + + ,)) + (comment (require '[kaocha.repl :as k]) (k/run {:color? false}))