Add filters to the /v1/tasks/search endpoint
This commit adds almost the same set of parameters that the /v1/tasks endpoint supports to the /v1/tasks/search endpoint. This allows one to obtain some search results and then filter them more easily than before, as well as avoiding a bug when trying to naively search for tasks without removing the default criteria in the web ui. Eventually we should probably merge the two endpoints. Change-Id: Ie65d5b8a23c96369050013face90f15d3a39d84b
This commit is contained in:
parent
4aed46c189
commit
e0b093ab89
@ -20,6 +20,7 @@ import sqlalchemy_fulltext.modes as FullTextMode
|
||||
from storyboard.api.v1.search import search_engine
|
||||
from storyboard.db.api import base as api_base
|
||||
from storyboard.db.api import stories as stories_api
|
||||
from storyboard.db.api import tasks as tasks_api
|
||||
from storyboard.db import models
|
||||
|
||||
|
||||
@ -45,9 +46,10 @@ class SqlAlchemySearchImpl(search_engine.SearchEngine):
|
||||
return api_base.paginate_query(query=query,
|
||||
model=model_cls,
|
||||
limit=limit,
|
||||
sort_key="id",
|
||||
sort_key=sort_field,
|
||||
marker=marker_entity,
|
||||
offset=offset)
|
||||
offset=offset,
|
||||
sort_dir=sort_dir)
|
||||
|
||||
def projects_query(self, q, sort_dir=None, marker=None,
|
||||
offset=None, limit=None):
|
||||
@ -112,19 +114,35 @@ class SqlAlchemySearchImpl(search_engine.SearchEngine):
|
||||
|
||||
return query.all()
|
||||
|
||||
def tasks_query(self, q, marker=None, offset=None, limit=None,
|
||||
current_user=None, **kwargs):
|
||||
def tasks_query(self, q, story_id=None, assignee_id=None, project_id=None,
|
||||
project_group_id=None, branch_id=None, milestone_id=None,
|
||||
status=None, offset=None, limit=None, current_user=None,
|
||||
sort_field='id', sort_dir='asc'):
|
||||
session = api_base.get_session()
|
||||
query = api_base.model_query(models.Task, session)
|
||||
|
||||
query = tasks_api.task_build_query(
|
||||
project_group_id=project_group_id,
|
||||
story_id=story_id,
|
||||
assignee_id=assignee_id,
|
||||
project_id=project_id,
|
||||
branch_id=branch_id,
|
||||
milestone_id=milestone_id,
|
||||
status=status,
|
||||
session=session)
|
||||
|
||||
query = self._build_fulltext_search(models.Task, query, q)
|
||||
|
||||
# Filter out tasks or stories that the current user can't see
|
||||
# Filter out stories that the current user can't see
|
||||
query = query.outerjoin(models.Story)
|
||||
query = api_base.filter_private_stories(query, current_user)
|
||||
|
||||
query = self._apply_pagination(
|
||||
models.Task, query, marker, offset, limit)
|
||||
models.Task,
|
||||
query,
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
sort_field=sort_field,
|
||||
sort_dir=sort_dir)
|
||||
|
||||
return query.all()
|
||||
|
||||
|
@ -444,25 +444,49 @@ class TasksPrimaryController(rest.RestController):
|
||||
|
||||
@decorators.db_exceptions
|
||||
@secure(checks.guest)
|
||||
@wsme_pecan.wsexpose([wmodels.Task], wtypes.text, wtypes.text, int,
|
||||
int, int)
|
||||
def search(self, q="", marker=None, offset=None, limit=None):
|
||||
"""The search endpoint for tasks.
|
||||
@wsme_pecan.wsexpose([wmodels.Task], wtypes.text, int, int, int, int, int,
|
||||
int, [wtypes.text], int, int, wtypes.text,
|
||||
wtypes.text)
|
||||
def search(self, q="", story_id=None, assignee_id=None,
|
||||
project_id=None, project_group_id=None, branch_id=None,
|
||||
milestone_id=None, status=None, offset=None, limit=None,
|
||||
sort_field='id', sort_dir='asc'):
|
||||
"""Search and filter the tasks.
|
||||
|
||||
Example::
|
||||
|
||||
curl https://my.example.org/api/v1/tasks/search?q=mary
|
||||
|
||||
:param q: The query string.
|
||||
:param q: Fulltext search query parameter.
|
||||
:param story_id: Filter tasks by story ID.
|
||||
:param assignee_id: Filter tasks by who they are assigned to.
|
||||
:param project_id: Filter the tasks based on project.
|
||||
:param project_group_id: Filter tasks based on project group.
|
||||
:param branch_id: Filter tasks based on branch_id.
|
||||
:param milestone_id: Filter tasks based on milestone.
|
||||
:param status: Filter tasks by status.
|
||||
:param offset: The offset to start the results at.
|
||||
:param limit: The number of tasks to retrieve.
|
||||
:param sort_field: The name of the field to sort on.
|
||||
:param sort_dir: Sort direction for results (asc, desc).
|
||||
:return: List of Tasks matching the query.
|
||||
"""
|
||||
|
||||
user = request.current_user_id
|
||||
tasks = SEARCH_ENGINE.tasks_query(q=q,
|
||||
marker=marker,
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
current_user=user)
|
||||
tasks = SEARCH_ENGINE.tasks_query(
|
||||
q=q,
|
||||
story_id=story_id,
|
||||
assignee_id=assignee_id,
|
||||
project_id=project_id,
|
||||
project_group_id=project_group_id,
|
||||
branch_id=branch_id,
|
||||
milestone_id=milestone_id,
|
||||
status=status,
|
||||
sort_field=sort_field,
|
||||
sort_dir=sort_dir,
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
current_user=user)
|
||||
|
||||
return [wmodels.Task.from_db_model(task) for task in tasks]
|
||||
|
||||
|
@ -38,8 +38,11 @@ def task_get_all(marker=None, limit=None, sort_field=None, sort_dir=None,
|
||||
sort_dir = 'asc'
|
||||
|
||||
# Construct the query
|
||||
query = task_build_query(
|
||||
project_group_id, current_user=current_user, **kwargs)
|
||||
query = task_build_query(project_group_id, **kwargs)
|
||||
|
||||
# Filter out tasks or stories that the current user can't see
|
||||
query = query.outerjoin(models.Story)
|
||||
query = api_base.filter_private_stories(query, current_user)
|
||||
|
||||
query = api_base.paginate_query(query=query,
|
||||
model=models.Task,
|
||||
@ -53,8 +56,12 @@ def task_get_all(marker=None, limit=None, sort_field=None, sort_dir=None,
|
||||
|
||||
|
||||
def task_get_count(project_group_id=None, current_user=None, **kwargs):
|
||||
query = task_build_query(
|
||||
project_group_id, current_user=current_user, **kwargs)
|
||||
query = task_build_query(project_group_id, **kwargs)
|
||||
|
||||
# Filter out tasks or stories that the current user can't see
|
||||
query = query.outerjoin(models.Story)
|
||||
query = api_base.filter_private_stories(query, current_user)
|
||||
|
||||
return query.count()
|
||||
|
||||
|
||||
@ -82,9 +89,9 @@ def task_delete(task_id):
|
||||
api_base.entity_hard_delete(models.Task, task_id)
|
||||
|
||||
|
||||
def task_build_query(project_group_id, current_user=None, **kwargs):
|
||||
def task_build_query(project_group_id, session=None, **kwargs):
|
||||
# Construct the query
|
||||
query = api_base.model_query(models.Task)
|
||||
query = api_base.model_query(models.Task, session=session)
|
||||
|
||||
if project_group_id:
|
||||
query = query.join(models.Project,
|
||||
@ -97,10 +104,6 @@ def task_build_query(project_group_id, current_user=None, **kwargs):
|
||||
model=models.Task,
|
||||
**kwargs)
|
||||
|
||||
# Filter out tasks or stories that the current user can't see
|
||||
query = query.outerjoin(models.Story)
|
||||
query = api_base.filter_private_stories(query, current_user)
|
||||
|
||||
return query
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user