311 lines
12 KiB
Python
311 lines
12 KiB
Python
# Copyright (c) 2016 Codethink Limited
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
# implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
from datetime import datetime
|
|
|
|
from oslo_config import cfg
|
|
from pecan import abort
|
|
from pecan import request
|
|
from pecan import response
|
|
from pecan import rest
|
|
from pecan.secure import secure
|
|
from wsme import types as wtypes
|
|
import wsmeext.pecan as wsme_pecan
|
|
|
|
from storyboard._i18n import _
|
|
from storyboard.api.auth import authorization_checks as checks
|
|
from storyboard.api.v1 import wmodels
|
|
from storyboard.common import decorators
|
|
from storyboard.common import exception as exc
|
|
from storyboard.db.api import boards as boards_api
|
|
from storyboard.db.api import due_dates as due_dates_api
|
|
from storyboard.db.api import stories as stories_api
|
|
from storyboard.db.api import tasks as tasks_api
|
|
from storyboard.db.api import worklists as worklists_api
|
|
|
|
|
|
CONF = cfg.CONF
|
|
|
|
|
|
class PermissionsController(rest.RestController):
|
|
"""Manages operations on due date permissions."""
|
|
|
|
@decorators.db_exceptions
|
|
@secure(checks.guest)
|
|
@wsme_pecan.wsexpose([wtypes.text], int)
|
|
def get(self, due_date_id):
|
|
"""Get due date permissions for the current user.
|
|
|
|
:param due_date_id: The ID of the due date.
|
|
|
|
"""
|
|
due_date = due_dates_api.get(due_date_id)
|
|
if due_dates_api.visible(due_date, request.current_user_id):
|
|
return due_dates_api.get_permissions(due_date,
|
|
request.current_user_id)
|
|
else:
|
|
raise exc.NotFound(_("Due date %s not found") % due_date_id)
|
|
|
|
@decorators.db_exceptions
|
|
@secure(checks.authenticated)
|
|
@wsme_pecan.wsexpose(wtypes.text, int,
|
|
body=wtypes.DictType(wtypes.text, wtypes.text))
|
|
def post(self, due_date_id, permission):
|
|
"""Add a new permission to the due date.
|
|
|
|
:param due_date_id: The ID of the due date.
|
|
:param permission: The dict used to create the permission.
|
|
|
|
"""
|
|
if due_dates_api.editable(due_dates_api.get(due_date_id),
|
|
request.current_user_id):
|
|
return due_dates_api.create_permission(due_date_id, permission)
|
|
else:
|
|
raise exc.NotFound(_("Due date %s not found") % due_date_id)
|
|
|
|
@decorators.db_exceptions
|
|
@secure(checks.authenticated)
|
|
@wsme_pecan.wsexpose(wtypes.text, int,
|
|
body=wtypes.DictType(wtypes.text, wtypes.text))
|
|
def put(self, due_date_id, permission):
|
|
"""Update a permission of the due date.
|
|
|
|
:param due_date_id: The ID of the due date.
|
|
:param permission: The new contents of the permission.
|
|
|
|
"""
|
|
if due_dates_api.editable(due_dates_api.get(due_date_id),
|
|
request.current_user_id):
|
|
return due_dates_api.update_permission(
|
|
due_date_id, permission).codename
|
|
else:
|
|
raise exc.NotFound(_("Due date %s not found") % due_date_id)
|
|
|
|
|
|
class DueDatesController(rest.RestController):
|
|
"""Manages operations on due dates."""
|
|
|
|
@decorators.db_exceptions
|
|
@secure(checks.guest)
|
|
@wsme_pecan.wsexpose(wmodels.DueDate, int)
|
|
def get_one(self, id):
|
|
"""Retrieve details about one due date.
|
|
|
|
:param id: The ID of the due date.
|
|
|
|
"""
|
|
due_date = due_dates_api.get(id)
|
|
|
|
if due_dates_api.visible(due_date, request.current_user_id):
|
|
due_date_model = wmodels.DueDate.from_db_model(due_date)
|
|
due_date_model.resolve_items(due_date)
|
|
due_date_model.resolve_permissions(due_date)
|
|
return due_date_model
|
|
else:
|
|
return exc.NotFound(_("Due date %s not found") % id)
|
|
|
|
@decorators.db_exceptions
|
|
@secure(checks.guest)
|
|
@wsme_pecan.wsexpose([wmodels.DueDate], wtypes.text, datetime, int, int,
|
|
int, int, wtypes.text, wtypes.text)
|
|
def get_all(self, name=None, date=None, board_id=None, worklist_id=None,
|
|
user=None, owner=None, sort_field='id', sort_dir='asc'):
|
|
"""Retrieve details about all the due dates.
|
|
|
|
:param name: The name of the due date.
|
|
:param date: The date of the due date.
|
|
:param board_id: The ID of a board to filter by.
|
|
:param worklist_id: The ID of a worklist to filter by.
|
|
:param sort_field: The name of the field to sort on.
|
|
:param sort_dir: Sort direction for results (asc, desc).
|
|
|
|
"""
|
|
due_dates = due_dates_api.get_all(name=name,
|
|
date=date,
|
|
board_id=board_id,
|
|
worklist_id=worklist_id,
|
|
user=user,
|
|
owner=owner,
|
|
sort_field=sort_field,
|
|
sort_dir=sort_dir)
|
|
visible_dates = []
|
|
for due_date in due_dates:
|
|
if due_dates_api.visible(due_date, request.current_user_id):
|
|
due_date_model = wmodels.DueDate.from_db_model(due_date)
|
|
due_date_model.resolve_items(due_date)
|
|
due_date_model.resolve_permissions(due_date)
|
|
visible_dates.append(due_date_model)
|
|
|
|
response.headers['X-Total'] = str(len(visible_dates))
|
|
|
|
return visible_dates
|
|
|
|
@decorators.db_exceptions
|
|
@secure(checks.authenticated)
|
|
@wsme_pecan.wsexpose(wmodels.DueDate, body=wmodels.DueDate)
|
|
def post(self, due_date):
|
|
"""Create a new due date.
|
|
|
|
:param due_date: A due date within the request body.
|
|
|
|
"""
|
|
due_date_dict = due_date.as_dict()
|
|
user_id = request.current_user_id
|
|
|
|
if due_date.creator_id and due_date.creator_id != user_id:
|
|
abort(400, _("You can't select the creator of a due date."))
|
|
due_date_dict.update({'creator_id': user_id})
|
|
|
|
board_id = due_date_dict.pop('board_id')
|
|
worklist_id = due_date_dict.pop('worklist_id')
|
|
if 'stories' in due_date_dict:
|
|
del due_date_dict['stories']
|
|
if 'tasks' in due_date_dict:
|
|
del due_date_dict['tasks']
|
|
owners = due_date_dict.pop('owners')
|
|
users = due_date_dict.pop('users')
|
|
if not owners:
|
|
owners = [user_id]
|
|
if not users:
|
|
users = []
|
|
|
|
created_due_date = due_dates_api.create(due_date_dict)
|
|
|
|
if board_id is not None:
|
|
date = due_dates_api.get(created_due_date.id)
|
|
date.boards.append(boards_api.get(board_id))
|
|
|
|
if worklist_id is not None:
|
|
date = due_dates_api.get(created_due_date.id)
|
|
date.worklists.append(worklists_api.get(worklist_id))
|
|
|
|
edit_permission = {
|
|
'name': 'edit_due_date_%d' % created_due_date.id,
|
|
'codename': 'edit_date',
|
|
'users': owners
|
|
}
|
|
assign_permission = {
|
|
'name': 'assign_due_date_%d' % created_due_date.id,
|
|
'codename': 'assign_date',
|
|
'users': users
|
|
}
|
|
due_dates_api.create_permission(created_due_date.id, edit_permission)
|
|
due_dates_api.create_permission(created_due_date.id, assign_permission)
|
|
|
|
created_due_date = due_dates_api.get(created_due_date.id)
|
|
due_date_model = wmodels.DueDate.from_db_model(created_due_date)
|
|
due_date_model.resolve_items(created_due_date)
|
|
due_date_model.resolve_permissions(created_due_date,
|
|
request.current_user_id)
|
|
return due_date_model
|
|
|
|
@decorators.db_exceptions
|
|
@secure(checks.authenticated)
|
|
@wsme_pecan.wsexpose(wmodels.DueDate, int, body=wmodels.DueDate)
|
|
def put(self, id, due_date):
|
|
"""Modify a due date.
|
|
|
|
:param id: The ID of the due date to edit.
|
|
:param due_date: The new due date within the request body.
|
|
|
|
"""
|
|
if not due_dates_api.assignable(due_dates_api.get(id),
|
|
request.current_user_id):
|
|
raise exc.NotFound(_("Due date %s not found") % id)
|
|
|
|
original_due_date = due_dates_api.get(id)
|
|
|
|
due_date_dict = due_date.as_dict(omit_unset=True)
|
|
editing = any(prop in due_date_dict
|
|
for prop in ('name', 'date', 'private'))
|
|
if editing and not due_dates_api.editable(original_due_date,
|
|
request.current_user_id):
|
|
raise exc.NotFound(_("Due date %s not found") % id)
|
|
|
|
if due_date.creator_id \
|
|
and due_date.creator_id != original_due_date.creator_id:
|
|
abort(400, _("You can't select the creator of a due date."))
|
|
|
|
if 'tasks' in due_date_dict:
|
|
tasks = due_date_dict.pop('tasks')
|
|
db_tasks = []
|
|
for task in tasks:
|
|
db_tasks.append(tasks_api.task_get(
|
|
task.id, current_user=request.current_user_id))
|
|
due_date_dict['tasks'] = db_tasks
|
|
|
|
if 'stories' in due_date_dict:
|
|
stories = due_date_dict.pop('stories')
|
|
db_stories = []
|
|
for story in stories:
|
|
db_stories.append(stories_api.story_get_simple(
|
|
story.id, current_user=request.current_user_id))
|
|
due_date_dict['stories'] = db_stories
|
|
|
|
board = None
|
|
worklist = None
|
|
if 'board_id' in due_date_dict:
|
|
board = boards_api.get(due_date_dict['board_id'])
|
|
|
|
if 'worklist_id' in due_date_dict:
|
|
worklist = worklists_api.get(due_date_dict['worklist_id'])
|
|
|
|
updated_due_date = due_dates_api.update(id, due_date_dict)
|
|
|
|
if board:
|
|
updated_due_date.boards.append(board)
|
|
|
|
if worklist:
|
|
updated_due_date.worklists.append(worklist)
|
|
|
|
if due_dates_api.visible(updated_due_date, request.current_user_id):
|
|
due_date_model = wmodels.DueDate.from_db_model(updated_due_date)
|
|
due_date_model.resolve_items(updated_due_date)
|
|
due_date_model.resolve_permissions(updated_due_date,
|
|
request.current_user_id)
|
|
return due_date_model
|
|
else:
|
|
raise exc.NotFound(_("Due date %s not found") % id)
|
|
|
|
@decorators.db_exceptions
|
|
@secure(checks.authenticated)
|
|
@wsme_pecan.wsexpose(None, int, int)
|
|
def delete(self, id, board_id):
|
|
"""Stop associating a due date with a board.
|
|
|
|
Note: We don't allow actual deletion of due dates.
|
|
|
|
:param id: The ID of the due date.
|
|
:param board_id: The ID of the board.
|
|
|
|
"""
|
|
due_date = due_dates_api.get(id)
|
|
if not due_dates_api.editable(due_date, request.current_user_id):
|
|
raise exc.NotFound(_("Due date %s not found") % id)
|
|
|
|
board = boards_api.get(board_id)
|
|
if not boards_api.editable(board, request.current_user_id):
|
|
raise exc.NotFound(_("Board %s not found") % board_id)
|
|
|
|
if board in due_date.boards:
|
|
due_date.boards.remove(board)
|
|
for lane in board.lanes:
|
|
for card in lane.worklist.items:
|
|
if card.display_due_date == due_date.id:
|
|
update = {'display_due_date': None}
|
|
worklists_api.update_item(card.id, update)
|
|
|
|
permissions = PermissionsController()
|