✨ Add member profile support for organization attributes (#12652)

This commit is contained in:
María Valderrama 2026-10-28 11:02:42 +01:00 committed by GitHub
parent 4d416bd3f2
commit ff9506c551
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 99 additions and 1 deletions

View File

@ -213,6 +213,7 @@
"accept-team-invitation-from"
"add-member-to-organization"
"add-team-to-organization"
"assign-organization-attribute"
"auditlog-exported"
"auditlog-guide-downloaded"
"cancel-organization-invitation"
@ -253,6 +254,7 @@
"sso-config-tested"
"success-activate-organization-sso"
"success-apply-organization-sso-changes"
"unassign-organization-attribute"
"update-organization-invitation"
"update-organization-permissions"
"update-team-invitation"

View File

@ -17,7 +17,7 @@
[app.common.time :as ct]
[app.common.types.organization :as cto]
[app.common.types.profile :refer [schema:profile, schema:basic-profile]]
[app.common.types.team :refer [schema:team]]
[app.common.types.team :as ctt :refer [schema:team]]
[app.common.uri :as u]
[app.common.uuid :as uuid]
[app.config :as cf]
@ -562,6 +562,55 @@ RETURNING id, deleted_at;")
(db/exec! conn [sql:get-organization-member-team-counts ids-array])))))))
;; ---- API: get-organization-member-teams
(def ^:private sql:get-organization-member-teams
"SELECT t.id, t.name, t.photo_id,
CASE WHEN tpr.is_owner THEN 'owner'
WHEN tpr.is_admin THEN 'admin'
WHEN tpr.can_edit THEN 'editor'
ELSE 'viewer'
END AS role
FROM team_profile_rel AS tpr
JOIN team AS t ON t.id = tpr.team_id
WHERE tpr.profile_id = ?
AND t.id = ANY(?)
AND t.deleted_at IS NULL
AND t.is_default IS FALSE;")
(def ^:private schema:get-organization-member-teams-params
[:map
[:profile-id ::sm/uuid]
[:team-ids [:or ::sm/uuid [:vector ::sm/uuid]]]])
(def ^:private schema:get-organization-member-teams-result
[:vector [:map
[:id ::sm/uuid]
[:name ::sm/text]
[:photo-url {:optional true} ::sm/uri]
[:role ctt/schema:role]]])
(sv/defmethod ::get-organization-member-teams
"Get the non-default teams a profile belongs to within a set of teams,
with the profile's role in each one."
{::doc/added "2.18"
::sm/params schema:get-organization-member-teams-params
::sm/result schema:get-organization-member-teams-result
::nitrate/sso false}
[cfg {:keys [profile-id team-ids]}]
(let [team-ids (if (uuid? team-ids) [team-ids] team-ids)]
(if (empty? team-ids)
[]
(db/run! cfg (fn [{:keys [::db/conn]}]
(let [ids-array (db/create-array conn "uuid" team-ids)]
(->> (db/exec! conn [sql:get-organization-member-teams profile-id ids-array])
(mapv (fn [{:keys [photo-id role] :as row}]
(cond-> (-> row
(dissoc :photo-id)
(assoc :role (keyword role)))
photo-id (assoc :photo-url (files/resolve-public-uri photo-id))))))))))))
;; API: invite-to-organization
(defn- get-invitation-organization

View File

@ -251,6 +251,53 @@
(t/is (false? (get-in teams-by-id [(:id owned-team) :is-default])))
(t/is (false? (get-in teams-by-id [(:id member-team) :is-default])))))))
(t/deftest get-organization-member-teams-returns-roles-within-given-teams
(with-mocks [nitrate-mock {:target 'app.nitrate/call :return nil}]
(let [profile (th/create-profile* 1 {:is-active true})
other (th/create-profile* 2 {:is-active true})
owned-team (th/create-team* 1 {:profile-id (:id profile)})
admin-team (th/create-team* 2 {:profile-id (:id other)})
editor-team (th/create-team* 3 {:profile-id (:id other)})
viewer-team (th/create-team* 4 {:profile-id (:id other)})
foreign-team (th/create-team* 5 {:profile-id (:id other)})
not-member (th/create-team* 6 {:profile-id (:id other)})
deleted-team (th/create-team* 7 {:profile-id (:id profile)})
_ (th/db-update! :team
{:deleted-at (ct/now)}
{:id (:id deleted-team)})
_ (doseq [[team role] [[admin-team :admin]
[editor-team :editor]
[viewer-team :viewer]
[foreign-team :editor]]]
(th/create-team-role* {:team-id (:id team)
:profile-id (:id profile)
:role role}))
team-ids (mapv :id [owned-team admin-team editor-team viewer-team
not-member deleted-team
{:id (:default-team-id profile)}])
out (th/management-command! {::th/type :get-organization-member-teams
::rpc/profile-id (:id other)
:profile-id (:id profile)
:team-ids team-ids})]
(t/is (th/success? out))
(t/is (= {(:id owned-team) :owner
(:id admin-team) :admin
(:id editor-team) :editor
(:id viewer-team) :viewer}
(->> out :result (map (juxt :id :role)) (into {}))))
(t/is (= (:name owned-team)
(->> out :result (d/seek #(= (:id owned-team) (:id %))) :name))))))
(t/deftest get-organization-member-teams-empty-team-ids
(with-mocks [nitrate-mock {:target 'app.nitrate/call :return nil}]
(let [profile (th/create-profile* 1 {:is-active true})
out (th/management-command! {::th/type :get-organization-member-teams
::rpc/profile-id (:id profile)
:profile-id (:id profile)
:team-ids []})]
(t/is (th/success? out))
(t/is (= [] (:result out))))))
(t/deftest update-profile-theme-updates-only-theme
(with-mocks [nitrate-mock {:target 'app.nitrate/call :return nil}]
(let [profile (th/create-profile* 1 {:is-active true