diff --git a/backend/src/app/rpc/management/nitrate.clj b/backend/src/app/rpc/management/nitrate.clj index 5199945d70..84cf2630ea 100644 --- a/backend/src/app/rpc/management/nitrate.clj +++ b/backend/src/app/rpc/management/nitrate.clj @@ -540,6 +540,33 @@ RETURNING id, deleted_at;") (profile-to-map profile))) +;; ---- API: get-profiles-by-ids + +(def ^:private sql:get-profiles-by-ids + "SELECT DISTINCT id, fullname, email, photo_id + FROM profile + WHERE id = ANY(?) + AND deleted_at IS NULL;") + +(def ^:private schema:get-profiles-by-ids-params + [:map [:ids [:vector ::sm/uuid]]]) + +(sv/defmethod ::get-profiles-by-ids + "Get multiple profiles by id. Unknown ids are simply absent from the result." + {::doc/added "2.20" + ::rpc/allowed-shared-keys allowed-shared-key-ids + ::sm/params schema:get-profiles-by-ids-params + ::sm/result [:vector schema:profile] + ::nitrate/sso false} + [cfg {:keys [ids]}] + (if (empty? ids) + [] + (db/run! cfg (fn [{:keys [::db/conn]}] + (let [ids-array (db/create-array conn "uuid" ids)] + (->> (db/exec! conn [sql:get-profiles-by-ids ids-array]) + (mapv profile-to-map))))))) + + ;; ---- API: get-organization-member-team-counts (def ^:private sql:get-organization-member-team-counts diff --git a/backend/test/backend_tests/rpc_management_nitrate_test.clj b/backend/test/backend_tests/rpc_management_nitrate_test.clj index cdef65b340..abf83b4b2a 100644 --- a/backend/test/backend_tests/rpc_management_nitrate_test.clj +++ b/backend/test/backend_tests/rpc_management_nitrate_test.clj @@ -824,6 +824,34 @@ (t/is (= :not-found (th/ex-type (:error ko-out)))) (t/is (= :profile-not-found (th/ex-code (:error ko-out))))))) +(t/deftest get-profiles-by-ids-existing-only-deduped-and-empty + (with-mocks [nitrate-mock {:target 'app.nitrate/call :return nil}] + (let [profile-a (th/create-profile* 1 {:is-active true + :fullname "Batch A"}) + profile-b (th/create-profile* 2 {:is-active true + :fullname "Batch B"}) + unknown (uuid/random) + params {::th/type :get-profiles-by-ids + ::rpc/profile-id (:id profile-a)} + out (th/management-command! (assoc params :ids [(:id profile-a) + (:id profile-b) + unknown])) + dup-out (th/management-command! (assoc params :ids [(:id profile-a) + (:id profile-a)])) + empty-out (th/management-command! (assoc params :ids []))] + (t/is (th/success? out)) + (t/is (= #{(:id profile-a) (:id profile-b)} + (set (map :id (:result out))))) + (t/is (= #{"Batch A" "Batch B"} + (set (map :name (:result out))))) + (t/is (every? #(contains? % :email) (:result out))) + + (t/is (th/success? dup-out)) + (t/is (= 1 (count (:result dup-out)))) + + (t/is (th/success? empty-out)) + (t/is (= [] (:result empty-out)))))) + (t/deftest get-organization-invitations-returns-valid-deduped-by-email ;; --- Deferred organization-summary: nil during setup, filled before RPC --- (let [organization-summary-ref (atom nil)]