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

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/main/pr-7318-86865f39926e82f5fba74574a79b05341f4e37b5
in repository https://gitbox.apache.org/repos/asf/texera.git

commit 0f2cd49c39781d683f35e02547da45fbe5adc3c3
Author: Xinyuan Lin <[email protected]>
AuthorDate: Tue Aug 4 23:32:46 2026 -0700

    fix(amber, frontend): serve created datasets to the admin quota modal 
(#7318)
    
    ### What changes were proposed in this PR?
    
    The admin user-quota modal (`UserQuotaComponent` opened from the admin
    user list) fails to load its "created datasets" panel: the request 404s.
    
    **Root cause:** `AdminUserService.getCreatedDatasets()` targets
    `/admin/user/created_datasets`, but `AdminUserResource` never exposed
    that endpoint. The only `created_datasets` endpoint lives on
    `UserQuotaResource` (`/quota/created_datasets`), and it derives the uid
    from the authenticated session (`@Auth current_user`) with no `user_id`
    parameter — so it cannot serve "datasets of the user an admin is
    inspecting" (it would return the admin's own datasets instead).
    
    | | Before | After |
    |---|---|---|
    | Frontend request | `GET /admin/user/created_datasets` (no params) |
    `GET /admin/user/created_datasets?user_id=<uid>` |
    | Backend | no such route → 404 |
    `AdminUserResource.getCreatedDatasets(user_id)` → datasets owned by
    `user_id` |
    
    ```
    admin quota modal ──> AdminUserService.getCreatedDatasets(uid)
                              │  before: GET /admin/user/created_datasets       
     ──> 404 (route missing)
                              │  after:  GET 
/admin/user/created_datasets?user_id=N  ──> AdminUserResource
                              │                                                 
           └─> DatasetStatisticsUtils.getUserCreatedDatasets(N)
    ```
    
    Changes:
    - `AdminUserResource.scala`: add `GET
    /admin/user/created_datasets?user_id=N` (ADMIN-only, like the sibling
    `created_workflows` / `access_workflows` / `user_quota_size` endpoints),
    delegating to `DatasetStatisticsUtils.getUserCreatedDatasets`.
    - `admin-user.service.ts`: `getCreatedDatasets(uid)` now sends the uid
    as the `user_id` query param (it previously accepted the uid and
    silently dropped it).
    
    ### Any related issues, documentation, discussions?
    
    Closes #7317
    
    ### How was this PR tested?
    
    Written test-first (both new tests were confirmed failing before the
    fix):
    
    - `AdminUserResourceSpec`: two new tests for `getCreatedDatasets` —
    empty list for a user with no datasets, and only the queried user's
    datasets are returned (a second user's dataset is excluded).
    - `admin-user.service.spec.ts`: the `getCreatedDatasets` test now
    asserts the `user_id` query param is sent (previously asserted no params
    were sent).
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Opus 5)
    
    ---------
    
    Signed-off-by: Xinyuan Lin <[email protected]>
    Co-authored-by: Copilot Autofix powered by AI 
<[email protected]>
---
 .../dashboard/admin/user/AdminUserResource.scala   | 11 ++++++
 .../admin/user/AdminUserResourceSpec.scala         | 45 +++++++++++++++++++++-
 .../service/admin/user/admin-user.service.spec.ts  |  6 +--
 .../service/admin/user/admin-user.service.ts       |  3 +-
 4 files changed, 60 insertions(+), 5 deletions(-)

diff --git 
a/amber/src/main/scala/org/apache/texera/web/resource/dashboard/admin/user/AdminUserResource.scala
 
b/amber/src/main/scala/org/apache/texera/web/resource/dashboard/admin/user/AdminUserResource.scala
index b50d8f3ea8..cb426f787b 100644
--- 
a/amber/src/main/scala/org/apache/texera/web/resource/dashboard/admin/user/AdminUserResource.scala
+++ 
b/amber/src/main/scala/org/apache/texera/web/resource/dashboard/admin/user/AdminUserResource.scala
@@ -28,6 +28,7 @@ import org.apache.texera.dao.jooq.generated.tables.pojos.User
 import org.apache.texera.web.resource.EmailTemplate.createRoleChangeTemplate
 import org.apache.texera.web.resource.GmailResource.sendEmail
 import 
org.apache.texera.web.resource.dashboard.admin.user.AdminUserResource.userDao
+import 
org.apache.texera.web.resource.dashboard.user.dataset.utils.DatasetStatisticsUtils.getUserCreatedDatasets
 import org.apache.texera.web.resource.dashboard.user.quota.UserQuotaResource._
 import org.jasypt.util.password.StrongPasswordEncryptor
 
@@ -126,6 +127,16 @@ class AdminUserResource {
     userDao.insert(newUser)
   }
 
+  @GET
+  @Path("/created_datasets")
+  @Produces(Array(MediaType.APPLICATION_JSON))
+  def getCreatedDatasets(@QueryParam("user_id") user_id: Integer): 
List[DatasetQuota] = {
+    if (user_id == null) {
+      throw new BadRequestException("user_id is required")
+    }
+    getUserCreatedDatasets(user_id)
+  }
+
   @GET
   @Path("/created_workflows")
   @Produces(Array(MediaType.APPLICATION_JSON))
diff --git 
a/amber/src/test/scala/org/apache/texera/web/resource/dashboard/admin/user/AdminUserResourceSpec.scala
 
b/amber/src/test/scala/org/apache/texera/web/resource/dashboard/admin/user/AdminUserResourceSpec.scala
index 741dbba464..fd35653c7a 100644
--- 
a/amber/src/test/scala/org/apache/texera/web/resource/dashboard/admin/user/AdminUserResourceSpec.scala
+++ 
b/amber/src/test/scala/org/apache/texera/web/resource/dashboard/admin/user/AdminUserResourceSpec.scala
@@ -23,6 +23,7 @@ import org.apache.texera.dao.MockTexeraDB
 import org.apache.texera.dao.jooq.generated.Tables._
 import org.apache.texera.dao.jooq.generated.enums.{PrivilegeEnum, UserRoleEnum}
 import org.apache.texera.dao.jooq.generated.tables.daos.{
+  DatasetDao,
   UserDao,
   WorkflowDao,
   WorkflowExecutionsDao,
@@ -31,6 +32,7 @@ import org.apache.texera.dao.jooq.generated.tables.daos.{
   WorkflowVersionDao
 }
 import org.apache.texera.dao.jooq.generated.tables.pojos.{
+  Dataset,
   User,
   Workflow,
   WorkflowExecutions,
@@ -44,7 +46,7 @@ import org.scalatest.matchers.should.Matchers
 
 import java.sql.Timestamp
 import java.util.UUID
-import javax.ws.rs.WebApplicationException
+import javax.ws.rs.{BadRequestException, WebApplicationException}
 import scala.jdk.CollectionConverters._
 
 class AdminUserResourceSpec
@@ -59,6 +61,7 @@ class AdminUserResourceSpec
   private val testWid = 90000 + scala.util.Random.nextInt(5000)
 
   private var userDao: UserDao = _
+  private var datasetDao: DatasetDao = _
   private var workflowDao: WorkflowDao = _
   private var workflowVersionDao: WorkflowVersionDao = _
   private var workflowExecutionsDao: WorkflowExecutionsDao = _
@@ -70,6 +73,7 @@ class AdminUserResourceSpec
   override protected def beforeAll(): Unit = {
     initializeDBAndReplaceDSLContext()
     userDao = new UserDao(getDSLContext.configuration())
+    datasetDao = new DatasetDao(getDSLContext.configuration())
     workflowDao = new WorkflowDao(getDSLContext.configuration())
     workflowVersionDao = new WorkflowVersionDao(getDSLContext.configuration())
     workflowExecutionsDao = new 
WorkflowExecutionsDao(getDSLContext.configuration())
@@ -92,6 +96,10 @@ class AdminUserResourceSpec
       .execute()
     
getDSLContext.deleteFrom(WORKFLOW_OF_USER).where(WORKFLOW_OF_USER.WID.eq(testWid)).execute()
     
getDSLContext.deleteFrom(WORKFLOW).where(WORKFLOW.WID.eq(testWid)).execute()
+    getDSLContext
+      .deleteFrom(DATASET)
+      .where(DATASET.OWNER_UID.in(primaryUid, secondaryUid))
+      .execute()
     getDSLContext.deleteFrom(USER).where(USER.UID.in(primaryUid, 
secondaryUid)).execute()
     // addUser() inserts an INACTIVE user with an auto-generated uid and a 
"User<millis>" name.
     getDSLContext
@@ -124,6 +132,19 @@ class AdminUserResourceSpec
     workflow
   }
 
+  private def seedDataset(uid: Int): Dataset = {
+    val dataset = new Dataset
+    dataset.setOwnerUid(uid)
+    dataset.setName("admin_user_spec_ds_" + 
UUID.randomUUID().toString.substring(0, 8))
+    dataset.setRepositoryName("repo-" + 
UUID.randomUUID().toString.substring(0, 8))
+    dataset.setIsPublic(false)
+    dataset.setIsDownloadable(true)
+    dataset.setDescription("")
+    dataset.setCreationTime(new Timestamp(System.currentTimeMillis()))
+    datasetDao.insert(dataset)
+    dataset
+  }
+
   private def seedExecution(uid: Int): WorkflowExecutions = {
     seedWorkflow()
     val version = new WorkflowVersion
@@ -218,6 +239,28 @@ class AdminUserResourceSpec
     a[WebApplicationException] should be thrownBy resource.updateUser(edit)
   }
 
+  // ─── getCreatedDatasets ───────────────────────────────────────────────────
+
+  "getCreatedDatasets" should "return an empty list for a user with no 
datasets" in {
+    userDao.insert(makeUser(primaryUid, "dataset_user"))
+    resource.getCreatedDatasets(primaryUid) shouldBe empty
+  }
+
+  it should "reject a missing user_id with a BadRequestException" in {
+    assertThrows[BadRequestException](resource.getCreatedDatasets(null))
+  }
+
+  it should "return only the datasets owned by the queried user" in {
+    userDao.insert(makeUser(primaryUid, "dataset_owner"))
+    userDao.insert(makeUser(secondaryUid, "other_owner"))
+    val owned = seedDataset(primaryUid)
+    seedDataset(secondaryUid)
+
+    val created = resource.getCreatedDatasets(primaryUid)
+    created.map(_.name) shouldBe List(owned.getName)
+    created.head.size shouldBe 0L
+  }
+
   // ─── getCreatedWorkflow ───────────────────────────────────────────────────
 
   "getCreatedWorkflow" should "return an empty list for a user with no created 
workflows" in {
diff --git 
a/frontend/src/app/dashboard/service/admin/user/admin-user.service.spec.ts 
b/frontend/src/app/dashboard/service/admin/user/admin-user.service.spec.ts
index 19a8aa7976..746522b9ac 100644
--- a/frontend/src/app/dashboard/service/admin/user/admin-user.service.spec.ts
+++ b/frontend/src/app/dashboard/service/admin/user/admin-user.service.spec.ts
@@ -100,12 +100,12 @@ describe("AdminUserService", () => {
     req.flush([]);
   });
 
-  it("getCreatedDatasets() GETs without a query param", () => {
+  it("getCreatedDatasets() sends the uid as a user_id query param", () => {
     service.getCreatedDatasets(9).subscribe();
 
-    const req = httpMock.expectOne(USER_CREATED_DATASETS);
+    const req = httpMock.expectOne(r => r.url === USER_CREATED_DATASETS);
     expect(req.request.method).toEqual("GET");
-    expect(req.request.params.keys().length).toEqual(0);
+    expect(req.request.params.get("user_id")).toEqual("9");
     req.flush([]);
   });
 
diff --git 
a/frontend/src/app/dashboard/service/admin/user/admin-user.service.ts 
b/frontend/src/app/dashboard/service/admin/user/admin-user.service.ts
index 481c5e5302..c7fb1b1a1c 100644
--- a/frontend/src/app/dashboard/service/admin/user/admin-user.service.ts
+++ b/frontend/src/app/dashboard/service/admin/user/admin-user.service.ts
@@ -68,7 +68,8 @@ export class AdminUserService {
   }
 
   public getCreatedDatasets(uid: number): 
Observable<ReadonlyArray<DatasetQuota>> {
-    return 
this.http.get<ReadonlyArray<DatasetQuota>>(`${USER_CREATED_DATASETS}`);
+    let params = new HttpParams().set("user_id", uid.toString());
+    return 
this.http.get<ReadonlyArray<DatasetQuota>>(`${USER_CREATED_DATASETS}`, { 
params: params });
   }
 
   public getCreatedWorkflows(uid: number): Observable<ReadonlyArray<Workflow>> 
{

Reply via email to