Merge "Allow lists of boards and worklists to be paged"
This commit is contained in:
commit
fb52a5318e
@ -142,10 +142,10 @@ class BoardsController(rest.RestController):
|
||||
@decorators.db_exceptions
|
||||
@secure(checks.guest)
|
||||
@wsme_pecan.wsexpose([wmodels.Board], wtypes.text, int, int, bool,
|
||||
int, int, int, wtypes.text, wtypes.text)
|
||||
int, int, int, int, int, wtypes.text, wtypes.text)
|
||||
def get_all(self, title=None, creator_id=None, project_id=None,
|
||||
archived=False, user_id=None, story_id=None, task_id=None,
|
||||
sort_field='id', sort_dir='asc'):
|
||||
offset=None, limit=None, sort_field='id', sort_dir='asc'):
|
||||
"""Retrieve definitions of all of the boards.
|
||||
|
||||
:param title: A string to filter the title by.
|
||||
@ -154,31 +154,45 @@ class BoardsController(rest.RestController):
|
||||
:param archived: Filter boards by whether they are archived or not.
|
||||
:param story_id: Filter boards by whether they contain a story.
|
||||
:param task_id: Filter boards by whether they contain a task.
|
||||
:param offset: Value to offset results by.
|
||||
:param limit: Maximum number of results to return.
|
||||
:param sort_field: The name of the field to sort on.
|
||||
:param sort_dir: Sort direction for results (asc, desc).
|
||||
|
||||
"""
|
||||
current_user = request.current_user_id
|
||||
boards = boards_api.get_all(title=title,
|
||||
creator_id=creator_id,
|
||||
user_id=user_id,
|
||||
project_id=project_id,
|
||||
story_id=story_id,
|
||||
task_id=task_id,
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
current_user=current_user,
|
||||
sort_field=sort_field,
|
||||
sort_dir=sort_dir)
|
||||
count = boards_api.get_count(title=title,
|
||||
creator_id=creator_id,
|
||||
user_id=user_id,
|
||||
project_id=project_id,
|
||||
story_id=story_id,
|
||||
task_id=task_id,
|
||||
current_user=current_user,)
|
||||
|
||||
visible_boards = []
|
||||
user_id = request.current_user_id
|
||||
for board in boards:
|
||||
if boards_api.visible(board, user_id) and\
|
||||
board.archived == archived:
|
||||
board_model = wmodels.Board.from_db_model(board)
|
||||
board_model.resolve_lanes(board, resolve_items=False)
|
||||
board_model.resolve_permissions(board)
|
||||
visible_boards.append(board_model)
|
||||
board_model = wmodels.Board.from_db_model(board)
|
||||
board_model.resolve_lanes(board, resolve_items=False)
|
||||
board_model.resolve_permissions(board)
|
||||
visible_boards.append(board_model)
|
||||
|
||||
# Apply the query response headers
|
||||
response.headers['X-Total'] = str(len(visible_boards))
|
||||
response.headers['X-Total'] = str(count)
|
||||
if limit is not None:
|
||||
response.headers['X-Limit'] = str(limit)
|
||||
if offset is not None:
|
||||
response.headers['X-Offset'] = str(offset)
|
||||
|
||||
return visible_boards
|
||||
|
||||
|
@ -357,11 +357,11 @@ class WorklistsController(rest.RestController):
|
||||
@secure(checks.guest)
|
||||
@wsme_pecan.wsexpose([wmodels.Worklist], wtypes.text, int, int,
|
||||
bool, int, int, int, bool, wtypes.text, wtypes.text,
|
||||
int)
|
||||
int, int, int)
|
||||
def get_all(self, title=None, creator_id=None, project_id=None,
|
||||
archived=False, user_id=None, story_id=None, task_id=None,
|
||||
hide_lanes=True, sort_field='id', sort_dir='asc',
|
||||
board_id=None):
|
||||
board_id=None, offset=None, limit=None):
|
||||
"""Retrieve definitions of all of the worklists.
|
||||
|
||||
:param title: A string to filter the title by.
|
||||
@ -377,8 +377,11 @@ class WorklistsController(rest.RestController):
|
||||
:param sort_dir: Sort direction for results (asc, desc).
|
||||
:param board_id: Get all worklists in the board with this id. Other
|
||||
filters are not applied.
|
||||
:param offset: Offset at which to begin the results.
|
||||
:param limit: Maximum number of results to return.
|
||||
|
||||
"""
|
||||
current_user = request.current_user_id
|
||||
worklists = worklists_api.get_all(title=title,
|
||||
creator_id=creator_id,
|
||||
project_id=project_id,
|
||||
@ -388,25 +391,40 @@ class WorklistsController(rest.RestController):
|
||||
story_id=story_id,
|
||||
task_id=task_id,
|
||||
sort_field=sort_field,
|
||||
sort_dir=sort_dir)
|
||||
sort_dir=sort_dir,
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
current_user=current_user,
|
||||
hide_lanes=hide_lanes)
|
||||
count = worklists_api.get_count(title=title,
|
||||
creator_id=creator_id,
|
||||
project_id=project_id,
|
||||
archived=archived,
|
||||
board_id=board_id,
|
||||
user_id=user_id,
|
||||
story_id=story_id,
|
||||
task_id=task_id,
|
||||
current_user=current_user,
|
||||
hide_lanes=hide_lanes)
|
||||
|
||||
user_id = request.current_user_id
|
||||
visible_worklists = []
|
||||
for worklist in worklists:
|
||||
if (worklists_api.visible(worklist, user_id, hide_lanes) and
|
||||
worklist.archived == archived):
|
||||
worklist_model = wmodels.Worklist.from_db_model(worklist)
|
||||
worklist_model.resolve_permissions(worklist)
|
||||
visible_items = worklists_api.get_visible_items(
|
||||
worklist, request.current_user_id)
|
||||
worklist_model.items = [
|
||||
wmodels.WorklistItem.from_db_model(item)
|
||||
for item in visible_items
|
||||
]
|
||||
visible_worklists.append(worklist_model)
|
||||
worklist_model = wmodels.Worklist.from_db_model(worklist)
|
||||
worklist_model.resolve_permissions(worklist)
|
||||
visible_items = worklists_api.get_visible_items(
|
||||
worklist, request.current_user_id)
|
||||
worklist_model.items = [
|
||||
wmodels.WorklistItem.from_db_model(item)
|
||||
for item in visible_items
|
||||
]
|
||||
visible_worklists.append(worklist_model)
|
||||
|
||||
# Apply the query response headers
|
||||
response.headers['X-Total'] = str(len(visible_worklists))
|
||||
response.headers['X-Total'] = str(count)
|
||||
if limit is not None:
|
||||
response.headers['X-Limit'] = str(limit)
|
||||
if offset is not None:
|
||||
response.headers['X-Offset'] = str(offset)
|
||||
|
||||
return visible_worklists
|
||||
|
||||
|
@ -13,7 +13,9 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from sqlalchemy.orm import subqueryload
|
||||
from sqlalchemy import and_, or_
|
||||
from sqlalchemy.orm import aliased, subqueryload
|
||||
from sqlalchemy.sql.expression import false, true
|
||||
from wsme.exc import ClientSideError
|
||||
|
||||
from storyboard.db.api import base as api_base
|
||||
@ -35,40 +37,115 @@ def get(id):
|
||||
return _board_get(id)
|
||||
|
||||
|
||||
def get_all(title=None, creator_id=None, user_id=None, project_id=None,
|
||||
task_id=None, story_id=None, sort_field=None, sort_dir=None,
|
||||
**kwargs):
|
||||
if user_id is not None:
|
||||
user = users_api.user_get(user_id)
|
||||
boards = []
|
||||
for board in get_all():
|
||||
if any(permission in board.permissions
|
||||
for permission in user.permissions):
|
||||
boards.append(board)
|
||||
return boards
|
||||
def _build_board_query(title=None, creator_id=None, user_id=None,
|
||||
project_id=None, archived=False, current_user=None,
|
||||
session=None):
|
||||
query = api_base.model_query(models.Board, session=session).distinct()
|
||||
|
||||
boards = api_base.entity_get_all(models.Board,
|
||||
title=title,
|
||||
creator_id=creator_id,
|
||||
project_id=project_id,
|
||||
sort_field=sort_field,
|
||||
sort_dir=sort_dir,
|
||||
**kwargs)
|
||||
query = api_base.apply_query_filters(query=query,
|
||||
model=models.Worklist,
|
||||
title=title,
|
||||
creator_id=creator_id,
|
||||
project_id=project_id)
|
||||
|
||||
# Filter out boards that the current user can't see
|
||||
query = query.join(models.board_permissions,
|
||||
models.Permission,
|
||||
models.user_permissions,
|
||||
models.User)
|
||||
if current_user:
|
||||
query = query.filter(
|
||||
or_(
|
||||
and_(
|
||||
models.User.id == current_user,
|
||||
models.Board.private == true()
|
||||
),
|
||||
models.Board.private == false()
|
||||
)
|
||||
)
|
||||
else:
|
||||
query = query.filter(models.Board.private == false())
|
||||
|
||||
# Filter by boards that a given user has permissions to use
|
||||
if user_id:
|
||||
board_permissions = aliased(models.board_permissions)
|
||||
permissions = aliased(models.Permission)
|
||||
user_permissions = aliased(models.user_permissions)
|
||||
users = aliased(models.User)
|
||||
query = query.join(
|
||||
(board_permissions,
|
||||
models.Board.id == board_permissions.c.board_id)
|
||||
)
|
||||
query = query.join(
|
||||
(permissions,
|
||||
board_permissions.c.permission_id == permissions.id)
|
||||
)
|
||||
query = query.join(
|
||||
(user_permissions,
|
||||
permissions.id == user_permissions.c.permission_id)
|
||||
)
|
||||
query = query.join((users, user_permissions.c.user_id == users.id))
|
||||
query = query.filter(users.id == user_id)
|
||||
|
||||
# Filter by whether or not we want archived boards
|
||||
query = query.filter(models.Board.archived == archived)
|
||||
|
||||
return query
|
||||
|
||||
|
||||
def get_all(title=None, creator_id=None, user_id=None, project_id=None,
|
||||
task_id=None, story_id=None, archived=False, offset=None,
|
||||
limit=None, sort_field=None, sort_dir=None, current_user=None,
|
||||
**kwargs):
|
||||
if sort_field is None:
|
||||
sort_field = 'id'
|
||||
if sort_dir is None:
|
||||
sort_dir = 'asc'
|
||||
|
||||
boards = _build_board_query(title=title,
|
||||
creator_id=creator_id,
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
archived=archived,
|
||||
current_user=current_user,
|
||||
**kwargs)
|
||||
if task_id:
|
||||
boards = boards.all()
|
||||
matching = []
|
||||
for board in boards:
|
||||
if has_card(board, 'task', task_id):
|
||||
matching.append(board)
|
||||
boards = matching
|
||||
return matching
|
||||
|
||||
if story_id:
|
||||
if not task_id:
|
||||
boards.all()
|
||||
matching = []
|
||||
for board in boards:
|
||||
if has_card(board, 'story', story_id):
|
||||
matching.append(board)
|
||||
boards = matching
|
||||
return matching
|
||||
|
||||
return boards
|
||||
boards = api_base.paginate_query(query=boards,
|
||||
model=models.Board,
|
||||
limit=limit,
|
||||
offset=offset,
|
||||
sort_key=sort_field,
|
||||
sort_dir=sort_dir)
|
||||
return boards.all()
|
||||
|
||||
|
||||
def get_count(title=None, creator_id=None, user_id=None, project_id=None,
|
||||
task_id=None, story_id=None, archived=False, current_user=None,
|
||||
**kwargs):
|
||||
query = _build_board_query(title=title,
|
||||
creator_id=creator_id,
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
archived=archived,
|
||||
current_user=current_user,
|
||||
**kwargs)
|
||||
return query.count()
|
||||
|
||||
|
||||
def create(values):
|
||||
|
@ -14,6 +14,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
from sqlalchemy import and_, or_
|
||||
from sqlalchemy.orm import aliased
|
||||
from sqlalchemy.sql.expression import false, true
|
||||
from wsme.exc import ClientSideError
|
||||
|
||||
@ -39,8 +40,9 @@ def get(worklist_id):
|
||||
|
||||
|
||||
def _build_worklist_query(title=None, creator_id=None, project_id=None,
|
||||
user_id=None, session=None):
|
||||
query = api_base.model_query(models.Worklist, session=session)
|
||||
archived=False, user_id=None, session=None,
|
||||
current_user=None, hide_lanes=True):
|
||||
query = api_base.model_query(models.Worklist, session=session).distinct()
|
||||
|
||||
query = api_base.apply_query_filters(query=query,
|
||||
model=models.Worklist,
|
||||
@ -48,19 +50,85 @@ def _build_worklist_query(title=None, creator_id=None, project_id=None,
|
||||
creator_id=creator_id,
|
||||
project_id=project_id)
|
||||
|
||||
# Filter out lists that the current user can't see.
|
||||
# This gets complicated because worklists permissions must be
|
||||
# inherited from the board which contains the list (if any). To
|
||||
# handle this we split the query into the lists which are in
|
||||
# boards (`lanes`) and those which aren't (`lists`). We then
|
||||
# either hide the lanes entirely or unify the two queries.
|
||||
lanes = query.join(models.BoardWorklist,
|
||||
models.Board,
|
||||
models.board_permissions)
|
||||
lanes = lanes.join(models.Permission,
|
||||
models.user_permissions,
|
||||
models.User)
|
||||
lists = query.outerjoin(models.BoardWorklist)
|
||||
lists = lists.filter(models.BoardWorklist.board_id.is_(None))
|
||||
lists = lists.join(models.worklist_permissions,
|
||||
models.Permission,
|
||||
models.user_permissions,
|
||||
models.User)
|
||||
if current_user:
|
||||
if not hide_lanes:
|
||||
lanes = lanes.filter(
|
||||
or_(
|
||||
and_(
|
||||
models.User.id == current_user,
|
||||
models.Board.private == true()
|
||||
),
|
||||
models.Board.private == false()
|
||||
)
|
||||
)
|
||||
lists = lists.filter(
|
||||
or_(
|
||||
and_(
|
||||
models.User.id == current_user,
|
||||
models.Worklist.private == true()
|
||||
),
|
||||
models.Worklist.private == false()
|
||||
)
|
||||
)
|
||||
else:
|
||||
if not hide_lanes:
|
||||
lanes = lanes.filter(models.Board.private == false())
|
||||
lists = lists.filter(models.Worklist.private == false())
|
||||
|
||||
if hide_lanes:
|
||||
query = lists
|
||||
else:
|
||||
query = lists.union(lists)
|
||||
|
||||
# Filter by lists that a given user has permissions to use
|
||||
if user_id:
|
||||
query = query.join(models.worklist_permissions,
|
||||
models.Permission,
|
||||
models.user_permissions,
|
||||
models.User)
|
||||
query = query.filter(models.User.id == user_id)
|
||||
worklist_permissions = aliased(models.worklist_permissions)
|
||||
permissions = aliased(models.Permission)
|
||||
user_permissions = aliased(models.user_permissions)
|
||||
users = aliased(models.User)
|
||||
query = query.join(
|
||||
(worklist_permissions,
|
||||
models.Worklist.id == worklist_permissions.c.worklist_id)
|
||||
)
|
||||
query = query.join(
|
||||
(permissions,
|
||||
worklist_permissions.c.permission_id == permissions.id)
|
||||
)
|
||||
query = query.join(
|
||||
(user_permissions,
|
||||
permissions.id == user_permissions.c.permission_id)
|
||||
)
|
||||
query = query.join((users, user_permissions.c.user_id == users.id))
|
||||
query = query.filter(users.id == user_id)
|
||||
|
||||
# Filter by whether or not we want archived lists
|
||||
query = query.filter(models.Worklist.archived == archived)
|
||||
|
||||
return query
|
||||
|
||||
|
||||
def get_all(title=None, creator_id=None, project_id=None, board_id=None,
|
||||
user_id=None, story_id=None, task_id=None, sort_field=None,
|
||||
sort_dir=None, session=None, **kwargs):
|
||||
sort_dir=None, session=None, offset=None, limit=None,
|
||||
archived=False, current_user=None, hide_lanes=True, **kwargs):
|
||||
if sort_field is None:
|
||||
sort_field = 'id'
|
||||
if sort_dir is None:
|
||||
@ -68,13 +136,19 @@ def get_all(title=None, creator_id=None, project_id=None, board_id=None,
|
||||
|
||||
if board_id is not None:
|
||||
board = boards.get(board_id)
|
||||
return [lane.worklist for lane in board.lanes]
|
||||
if board is None:
|
||||
return []
|
||||
return [lane.worklist for lane in board.lanes
|
||||
if visible(lane.worklist, current_user)]
|
||||
|
||||
query = _build_worklist_query(title=title,
|
||||
creator_id=creator_id,
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
session=session)
|
||||
archived=archived,
|
||||
session=session,
|
||||
current_user=current_user,
|
||||
hide_lanes=hide_lanes)
|
||||
|
||||
query.order_by(getattr(models.Worklist, sort_field), sort_dir)
|
||||
|
||||
@ -90,12 +164,41 @@ def get_all(title=None, creator_id=None, project_id=None, board_id=None,
|
||||
if has_item(worklist, 'task', task_id)]
|
||||
|
||||
if story_id or task_id:
|
||||
if offset is not None and limit is not None:
|
||||
return worklists[offset:offset + limit]
|
||||
elif offset is not None:
|
||||
return worklists[offset:]
|
||||
return worklists
|
||||
|
||||
query = api_base.paginate_query(query=query,
|
||||
model=models.Worklist,
|
||||
limit=limit,
|
||||
offset=offset,
|
||||
sort_key=sort_field,
|
||||
sort_dir=sort_dir)
|
||||
return query.all()
|
||||
|
||||
|
||||
def get_count(**kwargs):
|
||||
return api_base.entity_get_count(models.Worklist, **kwargs)
|
||||
def get_count(title=None, creator_id=None, project_id=None, board_id=None,
|
||||
user_id=None, story_id=None, task_id=None, session=None,
|
||||
archived=False, current_user=None, hide_lanes=True, **kwargs):
|
||||
if board_id is not None:
|
||||
board = boards.get(board_id)
|
||||
if board is None:
|
||||
return 0
|
||||
lists = [lane.worklist for lane in board.lanes
|
||||
if visible(lane.worklist, current_user)]
|
||||
return len(lists)
|
||||
|
||||
query = _build_worklist_query(title=title,
|
||||
creator_id=creator_id,
|
||||
project_id=project_id,
|
||||
user_id=user_id,
|
||||
archived=archived,
|
||||
session=session,
|
||||
current_user=current_user,
|
||||
hide_lanes=hide_lanes)
|
||||
return query.count()
|
||||
|
||||
|
||||
def get_visible_items(worklist, current_user=None):
|
||||
|
Loading…
x
Reference in New Issue
Block a user