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%">
|
- Hi{{ user-name|abbreviate:25 }},
+ Hi{% if user-name %} {{ user-name|abbreviate:25 }}{% endif %},
|
@@ -187,7 +187,7 @@
- {{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:
|
@@ -195,14 +195,19 @@
-
- {{ org-initials }}
-
-
+
+
+ |
+ {{org-initials}}
+ |
+
+
“{{ org-name|abbreviate:25 }}”
-
+
|
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"