diff --git a/.gitignore b/.gitignore index 100be94717..7d65539d22 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,4 @@ /**/node_modules /**/.yarn/* /.pnpm-store +/.vscode diff --git a/backend/resources/app/email/invite-to-org/en.html b/backend/resources/app/email/invite-to-org/en.html index 912b67746b..0a02932e99 100644 --- a/backend/resources/app/email/invite-to-org/en.html +++ b/backend/resources/app/email/invite-to-org/en.html @@ -174,12 +174,12 @@
+ width="100%"> @@ -187,7 +187,7 @@ @@ -195,14 +195,19 @@ diff --git a/backend/src/app/nitrate.clj b/backend/src/app/nitrate.clj index f062bbaedf..7f27ca0240 100644 --- a/backend/src/app/nitrate.clj +++ b/backend/src/app/nitrate.clj @@ -1,6 +1,7 @@ (ns app.nitrate "Module that make calls to the external nitrate aplication" (:require + [app.common.exceptions :as ex] [app.common.json :as json] [app.common.logging :as l] [app.common.schema :as sm] @@ -130,7 +131,8 @@ (def ^:private schema:profile-org [:map [:is-member :boolean] - [:organization-id ::sm/uuid]]) + [:organization-id ::sm/uuid] + [:default-team-id [:maybe ::sm/uuid]]]) ;; TODO Unify with schemas on backend/src/app/http/management.clj @@ -214,6 +216,17 @@ team-id) schema:organization params))) +(defn- get-org-membership-api + [cfg {:keys [profile-id org-id] :as params}] + (let [baseuri (cf/get :nitrate-backend-uri)] + (request-to-nitrate cfg :get + (str baseuri + "/api/organizations/" + org-id + "/members/" + profile-id) + schema:profile-org params))) + (defn- get-org-membership-by-team-api [cfg {:keys [profile-id team-id] :as params}] (let [baseuri (cf/get :nitrate-backend-uri)] @@ -308,6 +321,7 @@ (when (contains? cf/flags :nitrate) {:get-team-org (partial get-team-org-api cfg) :set-team-org (partial set-team-org-api cfg) + :get-org-membership (partial get-org-membership-api cfg) :get-org-membership-by-team (partial get-org-membership-by-team-api cfg) :get-org-summary (partial get-org-summary-api cfg) :add-profile-to-org (partial add-profile-to-org-api cfg) @@ -369,9 +383,10 @@ :is-default (:is-default params)) result (call cfg :set-team-org params)] (when (nil? result) - (throw (ex-info "Failed to set team organization" - {:team-id (:id team) - :organization-id (:organization-id params)}))) + (ex/raise :type :internal + :code :failed-to-set-team-org + :context {:team-id (:id team) + :organization-id (:organization-id params)})) team)) diff --git a/backend/src/app/rpc/commands/verify_token.clj b/backend/src/app/rpc/commands/verify_token.clj index 6e4532b3ad..9392d25648 100644 --- a/backend/src/app/rpc/commands/verify_token.clj +++ b/backend/src/app/rpc/commands/verify_token.clj @@ -16,6 +16,7 @@ [app.http.session :as session] [app.loggers.audit :as audit] [app.main :as-alias main] + [app.nitrate :as nitrate] [app.rpc :as-alias rpc] [app.rpc.commands.profile :as profile] [app.rpc.commands.teams :as teams] @@ -175,13 +176,13 @@ org-id (assoc :org-id org-id))) profile (db/get* conn :profile {:id profile-id} - {:columns [:id :email]}) - registration-disabled? (not (contains? cf/flags :registration))] + {:columns [:id :email :default-team-id]}) + registration-disabled? (not (contains? cf/flags :registration)) - (when (nil? invitation) - (ex/raise :type :validation - :code :invalid-token - :hint "no invitation associated with the token")) + org-invitation? (and (contains? cf/flags :nitrate) org-id) + membership (when org-invitation? + (nitrate/call cfg :get-org-membership {:profile-id profile-id + :org-id org-id}))] (if profile (do @@ -191,6 +192,23 @@ :code :invalid-token :hint "logged-in user does not matches the invitation")) + (when (:is-member membership) + (ex/raise :type :validation + :code :already-an-org-member + :team-id (:default-team-id membership) + :hint "the user is already a member of the organization")) + + (when (and org-invitation? (not (:organization-id membership))) + (ex/raise :type :validation + :code :org-not-found + :team-id (:default-team-id profile) + :hint "the organization doesn't exist")) + + (when (nil? invitation) + (ex/raise :type :validation + :code :invalid-token + :hint "no invitation associated with the token")) + ;; if we have logged-in user and it matches the invitation we proceed ;; with accepting the invitation and joining the current profile to the diff --git a/frontend/src/app/main/ui/auth/verify_token.cljs b/frontend/src/app/main/ui/auth/verify_token.cljs index 9a3a33c47b..e3c55c7239 100644 --- a/frontend/src/app/main/ui/auth/verify_token.cljs +++ b/frontend/src/app/main/ui/auth/verify_token.cljs @@ -76,8 +76,17 @@ (fn [tdata] (handle-token tdata)) (fn [cause] - (let [{:keys [type code] :as error} (ex-data cause)] + (let [{:keys [type code team-id] :as error} (ex-data cause)] (cond + (= :invalid-token-already-member code) + (st/emit! + (rt/nav :dashboard-recent {:team-id team-id})) + + (= :org-not-found code) + (st/emit! + (rt/nav :dashboard-recent {:team-id team-id}) + (ntf/error (tr "errors.org-not-found"))) + (or (= :validation type) (= :invalid-token code) (= :token-expired (:reason error))) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index dfabd64c24..fda3a9a5c1 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -1667,6 +1667,9 @@ msgstr "Email or password is incorrect." msgid "errors.wrong-old-password" msgstr "Old password is incorrect" +msgid "errors.org-not-found" +msgstr "That organization doesn't exists" + #: src/app/main/ui/settings/feedback.cljs:120 msgid "feedback.description" msgstr "Description" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 922b552159..16379e8e5d 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -1636,6 +1636,9 @@ msgstr "El email o la contraseña son incorrectos." msgid "errors.wrong-old-password" msgstr "La contraseña anterior no es correcta" +msgid "errors.org-not-found" +msgstr "Esa organización no existe" + #: src/app/main/ui/settings/feedback.cljs:120 msgid "feedback.description" msgstr "Descripción"
- Hi{{ user-name|abbreviate:25 }}, + Hi{% if user-name %} {{ user-name|abbreviate:25 }}{% endif %},
- {{invited-by|abbreviate:25}} sent you an invitation to join the organization {{ org-name|abbreviate:25 }}: + {{invited-by|abbreviate:25}} sent you an invitation to join the organization:
- - {{ org-initials }} - - + + + + +
+ {{org-initials}} +
“{{ org-name|abbreviate:25 }}” -
+