This is an automated email from the ASF dual-hosted git repository.

jin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph.git


The following commit(s) were added to refs/heads/master by this push:
     new ef2db2c9c feat(server): add gs profile api (#2950)
ef2db2c9c is described below

commit ef2db2c9c088c245fc8d608c24285fb4485694ab
Author: Tsukilc <[email protected]>
AuthorDate: Sat Feb 14 14:29:59 2026 +0800

    feat(server): add gs profile api (#2950)
---
 .../apache/hugegraph/api/space/GraphSpaceAPI.java  |  60 +++++++
 .../apache/hugegraph/api/GraphSpaceApiTest.java    | 180 +++++++++++++++++++--
 2 files changed, 228 insertions(+), 12 deletions(-)

diff --git 
a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/space/GraphSpaceAPI.java
 
b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/space/GraphSpaceAPI.java
index 1471814cb..bd0fb4e84 100644
--- 
a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/space/GraphSpaceAPI.java
+++ 
b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/space/GraphSpaceAPI.java
@@ -19,6 +19,9 @@
 
 package org.apache.hugegraph.api.space;
 
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -26,6 +29,7 @@ import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.hugegraph.api.API;
 import org.apache.hugegraph.api.filter.StatusFilter.Status;
+import org.apache.hugegraph.auth.AuthManager;
 import org.apache.hugegraph.auth.HugeGraphAuthProxy;
 import org.apache.hugegraph.core.GraphManager;
 import org.apache.hugegraph.define.Checkable;
@@ -52,6 +56,7 @@ import jakarta.ws.rs.PUT;
 import jakarta.ws.rs.Path;
 import jakarta.ws.rs.PathParam;
 import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
 import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.SecurityContext;
 
@@ -93,6 +98,55 @@ public class GraphSpaceAPI extends API {
         return gsInfo;
     }
 
+    @GET
+    @Timed
+    @Path("profile")
+    @Produces(APPLICATION_JSON_WITH_CHARSET)
+    @RolesAllowed({"admin"})
+    public Object listProfile(@Context GraphManager manager,
+                              @QueryParam("prefix") String prefix,
+                              @Context SecurityContext sc) {
+        Set<String> spaces = manager.graphSpaces();
+        List<Map<String, Object>> spaceList = new ArrayList<>();
+        List<Map<String, Object>> result = new ArrayList<>();
+        String user = HugeGraphAuthProxy.username();
+        AuthManager authManager = manager.authManager();
+        // FIXME: defaultSpace related interface is not implemented
+        // String defaultSpace = authManager.getDefaultSpace(user);
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
+        for (String sp : spaces) {
+            manager.getSpaceStorage(sp);
+            GraphSpace gs = space(manager, sp);
+            Map<String, Object> gsProfile = gs.info();
+            boolean isManager = verifyPermission(user, authManager, sp);
+
+            // 设置当前用户的是否允许访问该空间
+            if (gs.auth() && !isManager) {
+                gsProfile.put("authed", false);
+            } else {
+                gsProfile.put("authed", true);
+            }
+
+            gsProfile.put("create_time", format.format(gs.createTime()));
+            gsProfile.put("update_time", format.format(gs.updateTime()));
+            if (!isPrefix(gsProfile, prefix)) {
+                continue;
+            }
+
+            gsProfile.put("default", false);
+            result.add(gsProfile);
+            //boolean defaulted = StringUtils.equals(sp, defaultSpace);
+            //gsProfile.put("default", defaulted);
+            //if (defaulted) {
+            //    result.add(gsProfile);
+            //} else {
+            //    spaceList.add(gsProfile);
+            //}
+        }
+        result.addAll(spaceList);
+        return result;
+    }
+
     @POST
     @Timed
     @Status(Status.CREATED)
@@ -275,6 +329,12 @@ public class GraphSpaceAPI extends API {
                "_dp" : graphSpace.toLowerCase() + "_dp";
     }
 
+    private boolean verifyPermission(String user, AuthManager authManager, 
String graphSpace) {
+        return authManager.isAdminManager(user) ||
+               authManager.isSpaceManager(graphSpace, user) ||
+               authManager.isSpaceMember(graphSpace, user);
+    }
+
     private static class JsonGraphSpace implements Checkable {
 
         @JsonProperty("name")
diff --git 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/api/GraphSpaceApiTest.java
 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/api/GraphSpaceApiTest.java
index d18409ff2..01782e7e0 100644
--- 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/api/GraphSpaceApiTest.java
+++ 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/api/GraphSpaceApiTest.java
@@ -22,10 +22,13 @@ import java.util.Map;
 import java.util.Objects;
 
 import org.apache.hugegraph.util.JsonUtil;
+import org.junit.Assert;
 import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.google.common.collect.ImmutableMap;
+
 import jakarta.ws.rs.core.Response;
 
 public class GraphSpaceApiTest extends BaseApiTest {
@@ -51,8 +54,8 @@ public class GraphSpaceApiTest extends BaseApiTest {
     public void testAddSpaceNamespace() {
         String body = "{\n" +
                       "  \"name\": \"test_add_no_ns\",\n" +
-                      "  \"nickname\":\"Test No Namespace\",\n" +
-                      "  \"description\": \"no namespace\",\n" +
+                      "  \"nickname\":\"TestNoNamespace\",\n" +
+                      "  \"description\": \"nonamespace\",\n" +
                       "  \"cpu_limit\": 1000,\n" +
                       "  \"memory_limit\": 1024,\n" +
                       "  \"storage_limit\": 1000,\n" +
@@ -73,8 +76,8 @@ public class GraphSpaceApiTest extends BaseApiTest {
 
         String body2 = "{\n" +
                        "  \"name\": \"test_add_has_ns\",\n" +
-                       "  \"nickname\":\"Test With Namespace\",\n" +
-                       "  \"description\": \"has namespace\",\n" +
+                       "  \"nickname\":\"TestWithNamespace\",\n" +
+                       "  \"description\": \"hasnamespace\",\n" +
                        "  \"cpu_limit\": 1000,\n" +
                        "  \"memory_limit\": 1024,\n" +
                        "  \"storage_limit\": 1000,\n" +
@@ -105,8 +108,8 @@ public class GraphSpaceApiTest extends BaseApiTest {
         String spaceName = "test_delete_space";
         String body = "{"
                       + "\"name\":\"" + spaceName + "\","
-                      + "\"nickname\":\"Test Delete Space\","
-                      + "\"description\":\"Test delete space\","
+                      + "\"nickname\":\"TestDeleteSpace\","
+                      + "\"description\":\"Testdeletespace\","
                       + "\"cpu_limit\":1000,"
                       + "\"memory_limit\":1024,"
                       + "\"storage_limit\":1000,"
@@ -145,8 +148,8 @@ public class GraphSpaceApiTest extends BaseApiTest {
         String spaceName = "duplicate_space";
         String body = "{"
                       + "\"name\":\"" + spaceName + "\","
-                      + "\"nickname\":\"Duplicate Test Space\","
-                      + "\"description\":\"Test duplicate space\","
+                      + "\"nickname\":\"DuplicateTestSpace\","
+                      + "\"description\":\"Testduplicatespace\","
                       + "\"cpu_limit\":1000,"
                       + "\"memory_limit\":1024,"
                       + "\"storage_limit\":1000,"
@@ -179,8 +182,8 @@ public class GraphSpaceApiTest extends BaseApiTest {
         // Test minimum limits
         String minLimitsBody = "{"
                                + "\"name\":\"" + spaceName + "_min\","
-                               + "\"nickname\":\"Minimum Limits Test\","
-                               + "\"description\":\"Test minimum limits\","
+                               + "\"nickname\":\"MinimumLimitsTest\","
+                               + "\"description\":\"Testminimumlimits\","
                                + "\"cpu_limit\":1,"
                                + "\"memory_limit\":1,"
                                + "\"storage_limit\":1,"
@@ -203,8 +206,8 @@ public class GraphSpaceApiTest extends BaseApiTest {
         // Test maximum limits
         String maxLimitsBody = "{"
                                + "\"name\":\"" + spaceName + "_max\","
-                               + "\"nickname\":\"Maximum Limits Test\","
-                               + "\"description\":\"Test maximum limits\","
+                               + "\"nickname\":\"MaximumLimitsTest\","
+                               + "\"description\":\"Testmaximumlimits\","
                                + "\"cpu_limit\":999999,"
                                + "\"memory_limit\":999999,"
                                + "\"storage_limit\":999999,"
@@ -275,4 +278,157 @@ public class GraphSpaceApiTest extends BaseApiTest {
         r = this.client().post(PATH, negativeLimitsBody);
         assertResponseStatus(400, r);
     }
+
+    @Test
+    public void testListProfile() {
+        // Get profile list without prefix
+        Response r = this.client().get(PATH + "/profile");
+        String result = assertResponseStatus(200, r);
+
+        @SuppressWarnings("unchecked")
+        List<Map<String, Object>> profiles = JsonUtil.fromJson(result, 
List.class);
+
+        // Should contain at least the DEFAULT space
+        Assert.assertTrue("Expected at least one profile", profiles.size() >= 
1);
+
+        // Verify profile structure
+        for (Map<String, Object> profile : profiles) {
+            Assert.assertTrue("Profile should contain 'name'",
+                              profile.containsKey("name"));
+            Assert.assertTrue("Profile should contain 'authed'",
+                              profile.containsKey("authed"));
+            Assert.assertTrue("Profile should contain 'create_time'",
+                              profile.containsKey("create_time"));
+            Assert.assertTrue("Profile should contain 'update_time'",
+                              profile.containsKey("update_time"));
+            Assert.assertTrue("Profile should contain 'default'",
+                              profile.containsKey("default"));
+        }
+    }
+
+    @Test
+    public void testListProfileWithPrefix() {
+        // Create test spaces with different names
+        String space1 = "{"
+                        + "\"name\":\"test_profile_space1\","
+                        + "\"nickname\":\"TestProfileSpace\","
+                        + "\"description\":\"Testprofilelisting\","
+                        + "\"cpu_limit\":1000,"
+                        + "\"memory_limit\":1024,"
+                        + "\"storage_limit\":1000,"
+                        + "\"compute_cpu_limit\":0,"
+                        + "\"compute_memory_limit\":0,"
+                        + "\"oltp_namespace\":null,"
+                        + "\"olap_namespace\":null,"
+                        + "\"storage_namespace\":null,"
+                        + "\"operator_image_path\":\"test\","
+                        + "\"internal_algorithm_image_url\":\"test\","
+                        + "\"max_graph_number\":100,"
+                        + "\"max_role_number\":100,"
+                        + "\"auth\":false,"
+                        + "\"configs\":{}"
+                        + "}";
+
+        // Create a space that should NOT match the prefix filter
+        String space2 = "{"
+                        + "\"name\":\"other_profile_space\","
+                        + "\"nickname\":\"OtherProfileSpace\","
+                        + "\"description\":\"Other profile listing\","
+                        + "\"cpu_limit\":1000,"
+                        + "\"memory_limit\":1024,"
+                        + "\"storage_limit\":1000,"
+                        + "\"compute_cpu_limit\":0,"
+                        + "\"compute_memory_limit\":0,"
+                        + "\"oltp_namespace\":null,"
+                        + "\"olap_namespace\":null,"
+                        + "\"storage_namespace\":null,"
+                        + "\"operator_image_path\":\"test\","
+                        + "\"internal_algorithm_image_url\":\"test\","
+                        + "\"max_graph_number\":100,"
+                        + "\"max_role_number\":100,"
+                        + "\"auth\":false,"
+                        + "\"configs\":{}"
+                        + "}";
+
+        // Create spaces
+        Response r = this.client().post(PATH, space1);
+        assertResponseStatus(201, r);
+        r = this.client().post(PATH, space2);
+        assertResponseStatus(201, r);
+
+        // Test with prefix filter
+        r = this.client().get(PATH + "/profile",
+                              ImmutableMap.of("prefix", "test"));
+        String result = assertResponseStatus(200, r);
+
+        @SuppressWarnings("unchecked")
+        List<Map<String, Object>> profiles = JsonUtil.fromJson(result, 
List.class);
+        Assert.assertFalse("Expected non-empty profile list with prefix 
filter",
+                           profiles.isEmpty());
+
+        // Verify all returned profiles match the prefix
+        for (Map<String, Object> profile : profiles) {
+            String name = Objects.toString(profile.get("name"), "");
+            String nickname = Objects.toString(profile.get("nickname"), "");
+            boolean matchesPrefix = name.startsWith("test") ||
+                                    nickname.startsWith("test") ||
+                                    nickname.startsWith("Test");
+            Assert.assertTrue(
+                    "Profile should match prefix 'test': " + profile,
+                    matchesPrefix);
+
+            // Ensure the non-matching space is excluded
+            Assert.assertNotEquals("Non-matching space should be filtered out",
+                                   "other_profile_space", name);
+        }
+    }
+
+    @Test
+    public void testListProfileWithAuth() {
+        // Create a space with auth enabled
+        String authSpace = "{"
+                           + "\"name\":\"auth_test_space\","
+                           + "\"nickname\":\"AuthTestSpace\","
+                           + "\"description\":\"Test auth in profile\","
+                           + "\"cpu_limit\":1000,"
+                           + "\"memory_limit\":1024,"
+                           + "\"storage_limit\":1000,"
+                           + "\"compute_cpu_limit\":0,"
+                           + "\"compute_memory_limit\":0,"
+                           + "\"oltp_namespace\":null,"
+                           + "\"olap_namespace\":null,"
+                           + "\"storage_namespace\":null,"
+                           + "\"operator_image_path\":\"test\","
+                           + "\"internal_algorithm_image_url\":\"test\","
+                           + "\"max_graph_number\":100,"
+                           + "\"max_role_number\":100,"
+                           + "\"auth\":true,"
+                           + "\"configs\":{}"
+                           + "}";
+
+        Response r = this.client().post(PATH, authSpace);
+        assertResponseStatus(201, r);
+
+        // Get profile list
+        r = this.client().get(PATH + "/profile");
+        String result = assertResponseStatus(200, r);
+
+        @SuppressWarnings("unchecked")
+        List<Map<String, Object>> profiles = JsonUtil.fromJson(result, 
List.class);
+
+        // Find the auth_test_space and verify authed field
+        boolean found = false;
+        for (Map<String, Object> profile : profiles) {
+            if ("auth_test_space".equals(profile.get("name"))) {
+                found = true;
+                // Admin user should be authed
+                Assert.assertTrue("Profile should contain 'authed' field",
+                                  profile.containsKey("authed"));
+                Assert.assertEquals("Admin user should be authorized",
+                                    true, profile.get("authed"));
+                break;
+            }
+        }
+        Assert.assertTrue("auth_test_space not found in profile list", found);
+    }
 }

Reply via email to