From c22c28ca389517a69592c34d5db06b3157e39762 Mon Sep 17 00:00:00 2001
From: Timm Fitschen <t.fitschen@indiscale.com>
Date: Thu, 8 Feb 2024 23:25:10 +0100
Subject: [PATCH] ENH: add Connection::ListUsers method

---
 doc/CHANGELOG.md            |  2 ++
 include/caosdb/connection.h |  8 ++++++++
 requirements.txt            |  2 +-
 src/caosdb/connection.cpp   | 36 ++++++++++++++++++++++++++++++++++++
 4 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md
index 20438ea..66d8b36 100644
--- a/doc/CHANGELOG.md
+++ b/doc/CHANGELOG.md
@@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added
 
+-  Connection::ListUsers method
+
 ### Changed
 
 - Updated dependency versions.
diff --git a/include/caosdb/connection.h b/include/caosdb/connection.h
index d0414f2..9a62b4d 100644
--- a/include/caosdb/connection.h
+++ b/include/caosdb/connection.h
@@ -43,6 +43,9 @@
 #include <map>                             // for map
 #include <memory>                          // for shared_ptr, unique_ptr
 #include <string>                          // for string, basic_string
+#ifdef BUILD_ACM
+#include <vector>                           // for vector
+#endif
 
 namespace caosdb::connection {
 #ifdef BUILD_ACM
@@ -122,6 +125,11 @@ public:
   // TODO(tf) find a way to deal with this:
   // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
   auto DeleteSingleUser(const std::string &realm, const std::string &name) const -> void;
+
+  /**
+   * List known users.
+   */
+  auto ListUsers() const -> std::vector<User>;
 #endif
 
 private:
diff --git a/requirements.txt b/requirements.txt
index b0410ad..c3029f4 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -15,7 +15,7 @@ pluginbase==1.0.1
 Pygments==2.13.0
 PyJWT==2.6.0
 python-dateutil==2.8.2
-PyYAML==6.0
+PyYAML==6.0.1
 requests==2.28.1
 six==1.16.0
 tqdm==4.64.1
diff --git a/src/caosdb/connection.cpp b/src/caosdb/connection.cpp
index 4c77c52..53ff587 100644
--- a/src/caosdb/connection.cpp
+++ b/src/caosdb/connection.cpp
@@ -36,6 +36,9 @@
 #include <grpcpp/create_channel.h>       // for CreateChannel
 #include <grpcpp/support/status.h>       // for Status
 #include <string>                        // for string, operator+
+#ifdef BUILD_ACM
+#include <vector>                           // for vector
+#endif
 // IWYU pragma: no_include "net/proto2/public/repeated_field.h"
 
 namespace caosdb::connection {
@@ -46,6 +49,8 @@ using caosdb::acm::v1alpha1::CreateSingleUserRequest;
 using caosdb::acm::v1alpha1::CreateSingleUserResponse;
 using caosdb::acm::v1alpha1::DeleteSingleUserRequest;
 using caosdb::acm::v1alpha1::DeleteSingleUserResponse;
+using caosdb::acm::v1alpha1::ListUsersRequest;
+using caosdb::acm::v1alpha1::ListUsersResponse;
 using caosdb::acm::v1alpha1::RetrieveSingleUserRequest;
 using caosdb::acm::v1alpha1::RetrieveSingleUserResponse;
 #endif
@@ -204,6 +209,37 @@ auto Connection::CreateSingleUser(const User &user) const -> void {
   }
   status.ThrowExceptionIfError();
 }
+
+auto Connection::ListUsers() const -> std::vector<User> {
+  ListUsersRequest request;
+  ListUsersResponse response;
+  grpc::ClientContext context;
+  const grpc::Status grpc_status =
+    this->access_controll_management_service->ListUsers(&context, request, &response);
+  auto status = TransactionStatus::SUCCESS();
+  if (!grpc_status.ok()) {
+    switch (grpc_status.error_code()) {
+    case grpc::StatusCode::UNAUTHENTICATED:
+      status = TransactionStatus::AUTHENTICATION_ERROR(grpc_status.error_message());
+      break;
+    case grpc::StatusCode::UNAVAILABLE:
+      status = TransactionStatus::CONNECTION_ERROR();
+      break;
+    default:
+      auto error_message = grpc_status.error_message();
+      status = TransactionStatus::RPC_ERROR(std::to_string(grpc_status.error_code()) + " - " +
+                                            error_message);
+    }
+  }
+  status.ThrowExceptionIfError();
+
+  std::vector<User> results;
+  for (auto &user : *(response.mutable_users())) {
+    results.push_back(User(std::make_unique<UserImpl>(&user)));
+  }
+
+  return results;
+}
 #endif
 
 auto ConnectionManager::mHasConnection(const std::string &name) const -> bool {
-- 
GitLab