From 9ec8875c4c88a4c5d74f72b61564fd262db114fd Mon Sep 17 00:00:00 2001 From: Adam Coldrick Date: Tue, 22 Sep 2020 18:42:36 +0100 Subject: [PATCH] Allow Project Groups to be filtered by project Currently there is no easy way to find the set of Project Groups that a specific Project belongs to. This commit adds a parameter to the Project Groups browse endpoint to enable filtering by Project ID to add this functionality. Change-Id: I7b09665bb554c19e8cc4074ce0d1813f3adc4218 --- storyboard/api/v1/project_groups.py | 10 +++++--- storyboard/db/api/project_groups.py | 26 ++++++++++++++++++--- storyboard/tests/api/test_project_groups.py | 15 ++++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/storyboard/api/v1/project_groups.py b/storyboard/api/v1/project_groups.py index 6ca01e5a..b778691c 100644 --- a/storyboard/api/v1/project_groups.py +++ b/storyboard/api/v1/project_groups.py @@ -166,9 +166,10 @@ class ProjectGroupsController(rest.RestController): @decorators.db_exceptions @secure(checks.guest) @wsme_pecan.wsexpose([wmodels.ProjectGroup], int, int, int, wtypes.text, - wtypes.text, int, wtypes.text, wtypes.text) + wtypes.text, int, int, wtypes.text, wtypes.text) def get(self, marker=None, offset=None, limit=None, name=None, title=None, - subscriber_id=None, sort_field='id', sort_dir='asc'): + subscriber_id=None, project_id=None, sort_field='id', + sort_dir='asc'): """Retrieve a list of projects groups. Example:: @@ -181,6 +182,7 @@ class ProjectGroupsController(rest.RestController): :param name: A string to filter the name by. :param title: A string to filter the title by. :param subscriber_id: The ID of a subscriber to filter by. + :param project_id: The ID of a project to filter by. :param sort_field: The name of the field to sort on. :param sort_dir: Sort direction for results (asc, desc). """ @@ -200,11 +202,13 @@ class ProjectGroupsController(rest.RestController): name=name, title=title, subscriber_id=subscriber_id, + project_id=project_id, sort_field=sort_field, sort_dir=sort_dir) group_count = project_groups.project_group_get_count( - name=name, title=title, subscriber_id=subscriber_id) + name=name, title=title, subscriber_id=subscriber_id, + project_id=project_id) # Apply the query response headers. if limit: diff --git a/storyboard/db/api/project_groups.py b/storyboard/db/api/project_groups.py index d08cd305..16197029 100644 --- a/storyboard/db/api/project_groups.py +++ b/storyboard/db/api/project_groups.py @@ -47,8 +47,8 @@ def project_group_get_by_name(name): def project_group_get_all(marker=None, limit=None, offset=None, - subscriber_id=None, sort_field=None, sort_dir=None, - **kwargs): + subscriber_id=None, project_id=None, sort_field=None, + sort_dir=None, **kwargs): # Sanity checks, in case someone accidentally explicitly passes in 'None' if not sort_field: sort_field = 'id' @@ -70,6 +70,16 @@ def project_group_get_all(marker=None, limit=None, offset=None, subs = subs.subquery() query = query.join(subs, subs.c.target_id == models.ProjectGroup.id) + # Filtering by project + if project_id: + # We can filter using the project_id column in the + # project_group_mapping table, so we can skip joining the full + # projects table. + pgm = models.project_group_mapping + query = query.join( + (pgm, pgm.c.project_group_id == models.ProjectGroup.id)) + query = query.filter(pgm.c.project_id == project_id) + query = api_base.paginate_query(query=query, model=models.ProjectGroup, limit=limit, @@ -82,7 +92,7 @@ def project_group_get_all(marker=None, limit=None, offset=None, return query.all() -def project_group_get_count(subscriber_id=None, **kwargs): +def project_group_get_count(subscriber_id=None, project_id=None, **kwargs): # Construct the query query = api_base.model_query(models.ProjectGroup) query = api_base.apply_query_filters(query=query, @@ -99,6 +109,16 @@ def project_group_get_count(subscriber_id=None, **kwargs): subs = subs.subquery() query = query.join(subs, subs.c.target_id == models.ProjectGroup.id) + # Filtering by project + if project_id: + # We can filter using the project_id column in the + # project_group_mapping table, so we can skip joining the full + # projects table. + pgm = models.project_group_mapping + query = query.join( + (pgm, pgm.c.project_group_id == models.ProjectGroup.id)) + query = query.filter(pgm.c.project_id == project_id) + return query.count() diff --git a/storyboard/tests/api/test_project_groups.py b/storyboard/tests/api/test_project_groups.py index de9e5304..d908218b 100644 --- a/storyboard/tests/api/test_project_groups.py +++ b/storyboard/tests/api/test_project_groups.py @@ -171,6 +171,21 @@ class TestProjectGroupSearch(base.FunctionalTest): result = results.json[1] self.assertEqual(3, result['id']) + def test_search_by_project(self): + url = self.build_search_url({ + 'project_id': 3 + }) + + results = self.get_json(url, expect_errors=True) + self.assertEqual(2, len(results.json)) + self.assertEqual('2', results.headers['X-Total']) + self.assertFalse('X-Marker' in results.headers) + + result = results.json[0] + self.assertEqual(1, result['id']) + result = results.json[1] + self.assertEqual(2, result['id']) + def test_search_limit(self): url = self.build_search_url({ 'title': 'foo',