def is_visible(event, user_id, session=None): if event is None: return False if 'worklist_contents' in event.event_type: event_info = json.loads(event.event_info) if event_info['updated'] is not None: info = event_info['updated']['old'] elif event_info['removed'] is not None: info = event_info['removed'] elif event_info['added'] is not None: info = event_info['added'] else: return True if info.get('item_type') == 'story': story = stories_api.story_get_simple(info['item_id'], current_user=user_id, session=session) if story is None: return False elif info.get('item_type') == 'task': task = tasks_api.task_get(info['item_id'], current_user=user_id, session=session) if task is None: return False return True
def test_delete_story(self): # This test uses mock_data story_id = 1 # Verify that we can look up a story with tasks and events story = stories_api.story_get_simple(story_id) self.assertIsNotNone(story) tasks = tasks_api.task_get_all(story_id=story_id) self.assertEqual(len(tasks), 3) task_ids = [t.id for t in tasks] events = events_api.events_get_all(story_id=story_id) self.assertEqual(len(events), 3) event_ids = [e.id for e in events] # Delete the story stories_api.story_delete(story_id) story = stories_api.story_get_simple(story_id) self.assertIsNone(story) # Verify that the story's tasks were deleted tasks = tasks_api.task_get_all(story_id=story_id) self.assertEqual(len(tasks), 0) for tid in task_ids: task = tasks_api.task_get(task_id=tid) self.assertIsNone(task) # And the events events = events_api.events_get_all(story_id=story_id) self.assertEqual(len(events), 0) for eid in event_ids: event = events_api.event_get(event_id=eid) self.assertIsNone(event)
def post(self, id, item_id, item_type, list_position): """Add an item to a worklist. :param id: The ID of the worklist. :param item_id: The ID of the item. :param item_type: The type of the item (i.e. "story" or "task"). :param list_position: The position in the list to add the item. """ user_id = request.current_user_id if not worklists_api.editable_contents(worklists_api.get(id), user_id): raise exc.NotFound(_("Worklist %s not found") % id) item = None if item_type == 'story': item = stories_api.story_get( item_id, current_user=request.current_user_id) elif item_type == 'task': item = tasks_api.task_get( item_id, current_user=request.current_user_id) if item is None: raise exc.NotFound(_("Item %s refers to a non-existent task or " "story.") % item_id) worklists_api.add_item( id, item_id, item_type, list_position, current_user=request.current_user_id) return wmodels.WorklistItem.from_db_model( worklists_api.get_item_at_position(id, list_position))
def resolve_item(self, item, story_cache, task_cache, due_dates=True): user_id = request.current_user_id if item.item_type == 'story': story = story_cache.get(item.item_id) or stories_api.story_get( item.item_id, current_user=request.current_user_id) if story is None: return False self.story = Story.from_db_model(story) if due_dates: self.story.due_dates = [ date.id for date in story.due_dates if due_dates_api.visible(date, user_id) ] elif item.item_type == 'task': task = task_cache.get(item.item_id) or tasks_api.task_get( item.item_id, current_user=request.current_user_id) if task is None or task.story is None: return False self.task = Task.from_db_model(task) if due_dates: self.task.due_dates = [ date.id for date in task.due_dates if due_dates_api.visible(date, user_id) ] return True
def put(self, task_id, task): """Modify this task. Example:: curl https://my.example.org/api/v1/tasks -X PUT \\ -H 'Authorization: Bearer MY_ACCESS_TOKEN' \\ -H 'Content-Type: application/json;charset=UTF-8' \\ --data-binary '{"task_id":27,"status":"merged"}' :param task_id: An ID of the task. :param task: A task within the request body. """ original_task = copy.deepcopy( tasks_api.task_get(task_id, current_user=request.current_user_id)) if not original_task: raise exc.NotFound(_("Task %s not found.") % task_id) task = task_is_valid_put(task, original_task) updated_task = tasks_api.task_update(task_id, task.as_dict( omit_unset=True)) post_timeline_events(original_task, updated_task) return wmodels.Task.from_db_model(updated_task)
def test_delete_story(self): # This test uses mock_data story_id = 1 # Verify that we can look up a story with tasks and events story = stories_api.story_get_simple(story_id) self.assertIsNotNone(story) tasks = tasks_api.task_get_all(story_id=story_id) self.assertEqual(len(tasks), 3) task_ids = [t.id for t in tasks] events = events_api.events_get_all(story_id=story_id) self.assertEqual(len(events), 3) event_ids = [e.id for e in events] # Delete the story stories_api.story_delete(story_id) story = stories_api.story_get_simple(story_id) self.assertIsNone(story) # Verify that the story's tasks were deleted tasks = tasks_api.task_get_all(story_id=story_id) self.assertEqual(len(tasks), 0) for tid in task_ids: task = tasks_api.task_get(task_id=tid) self.assertIsNone(task) # And the events events = events_api.events_get_all(story_id=story_id) self.assertEqual(len(events), 0) for eid in event_ids: event = events_api.event_get(event_id=eid) self.assertIsNone(event)
def is_visible(event, user_id, session=None): if event is None: return False if 'worklist_contents' in event.event_type: event_info = json.loads(event.event_info) if event_info['updated'] is not None: info = event_info['updated']['old'] elif event_info['removed'] is not None: info = event_info['removed'] elif event_info['added'] is not None: info = event_info['added'] else: return True if info.get('item_type') == 'story': story = stories_api.story_get_simple( info['item_id'], current_user=user_id, session=session) if story is None: return False elif info.get('item_type') == 'task': task = tasks_api.task_get( info['item_id'], current_user=user_id, session=session) if task is None: return False return True
def resolve_item(self, item): user_id = request.current_user_id if item.item_type == 'story': story = stories_api.story_get(item.item_id, current_user=request.current_user_id) if story is None: return False self.story = Story.from_db_model(story) due_dates = [ date.id for date in story.due_dates if due_dates_api.visible(date, user_id) ] self.story.due_dates = due_dates elif item.item_type == 'task': task = tasks_api.task_get(item.item_id, current_user=request.current_user_id) if task is None or task.story is None: return False self.task = Task.from_db_model(task) due_dates = [ date.id for date in task.due_dates if due_dates_api.visible(date, user_id) ] self.task.due_dates = due_dates return True
def delete(self, story_id, task_id): """Delete this task. Example:: curl 'https://my.example.org/api/v1/stories/11/tasks/28' -X DELETE \\ -H 'Authorization: Bearer MY_ACCESS_TOKEN' :param story_id: An ID of the story. :param task_id: An ID of the task. """ original_task = copy.deepcopy( tasks_api.task_get(task_id, current_user=request.current_user_id)) if not original_task: raise exc.NotFound(_("Task %s not found.") % task_id) if original_task.story_id != story_id: abort(400, _("URL story_id and task.story_id do not match")) events_api.task_deleted_event( story_id=original_task.story_id, task_id=original_task.id, task_title=original_task.title, author_id=request.current_user_id) tasks_api.task_delete(task_id)
def add_item(worklist_id, item_id, item_type, list_position, current_user=None): worklist = _worklist_get(worklist_id) if worklist is None: raise exc.NotFound(_("Worklist %s not found") % worklist_id) # Check if this item has an archived card in this worklist to restore archived = get_item_by_item_id( worklist, item_type, item_id, archived=True) if archived: update = { 'archived': False, 'list_position': list_position } api_base.entity_update(models.WorklistItem, archived.id, update) return worklist # If this worklist is a lane, check if the item has an archived card # somewhere in the board to restore if is_lane(worklist): board = boards.get_from_lane(worklist) archived = boards.get_card(board, item_type, item_id, archived=True) if archived: update = { 'archived': False, 'list_id': worklist_id, 'list_position': list_position } api_base.entity_update(models.WorklistItem, archived.id, update) return worklist # Create a new card if item_type == 'story': item = stories_api.story_get(item_id, current_user=current_user) elif item_type == 'task': item = tasks_api.task_get(item_id, current_user=current_user) else: raise ClientSideError(_("An item in a worklist must be either a " "story or a task")) if item is None: raise exc.NotFound(_("%(type)s %(id)s not found") % {'type': item_type, 'id': item_id}) item_dict = { 'list_id': worklist_id, 'item_id': item_id, 'item_type': item_type, 'list_position': list_position } worklist_item = api_base.entity_create(models.WorklistItem, item_dict) if worklist.items is None: worklist.items = [worklist_item] else: worklist.items.append(worklist_item) return worklist
def add_item(worklist_id, item_id, item_type, list_position, current_user=None): worklist = _worklist_get(worklist_id) if worklist is None: raise exc.NotFound(_("Worklist %s not found") % worklist_id) # Check if this item has an archived card in this worklist to restore archived = get_item_by_item_id( worklist, item_type, item_id, archived=True) if archived: update = { 'archived': False, 'list_position': list_position } api_base.entity_update(models.WorklistItem, archived.id, update) return worklist # If this worklist is a lane, check if the item has an archived card # somewhere in the board to restore if is_lane(worklist): board = boards.get_from_lane(worklist) archived = boards.get_card(board, item_type, item_id, archived=True) if archived: update = { 'archived': False, 'list_id': worklist_id, 'list_position': list_position } api_base.entity_update(models.WorklistItem, archived.id, update) return worklist # Create a new card if item_type == 'story': item = stories_api.story_get(item_id, current_user=current_user) elif item_type == 'task': item = tasks_api.task_get(item_id, current_user=current_user) else: raise ClientSideError(_("An item in a worklist must be either a " "story or a task")) if item is None: raise exc.NotFound(_("%(type)s %(id)s not found") % {'type': item_type, 'id': item_id}) item_dict = { 'list_id': worklist_id, 'item_id': item_id, 'item_type': item_type, 'list_position': list_position } worklist_item = api_base.entity_create(models.WorklistItem, item_dict) if worklist.items is None: worklist.items = [worklist_item] else: worklist.items.append(worklist_item) return worklist
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)
def subscription_get_resource(target_type, target_id, current_user=None): if target_type not in SUPPORTED_TYPES: return None if target_type == 'story': return stories_api.story_get(target_id, current_user=current_user) elif target_type == 'task': return tasks_api.task_get(target_id, current_user=current_user) return api_base.entity_get(SUPPORTED_TYPES[target_type], target_id)
def subscription_get_resource(target_type, target_id, current_user=None): if target_type not in SUPPORTED_TYPES: return None if target_type == 'story': return stories_api.story_get(target_id, current_user=current_user) elif target_type == 'task': return tasks_api.task_get(target_id, current_user=current_user) return api_base.entity_get(SUPPORTED_TYPES[target_type], target_id)
def get_one(self, task_id): """Retrieve details about one task. :param task_id: An ID of the task. """ task = tasks_api.task_get(task_id) if task: return wmodels.Task.from_db_model(task) else: raise exc.NotFound(_("Task %s not found") % task_id)
def get_one(self, task_id): """Retrieve details about one task. :param task_id: An ID of the task. """ task = tasks_api.task_get( task_id, current_user=request.current_user_id) if task: return wmodels.Task.from_db_model(task) else: raise exc.NotFound(_("Task %s not found") % task_id)
def subscription_get_resource(target_type, target_id, current_user=None): if target_type not in SUPPORTED_TYPES: return None if target_type == 'story': return stories_api.story_get(target_id, current_user=current_user) elif target_type == 'task': return tasks_api.task_get(target_id, current_user=current_user) elif target_type == 'worklist': worklist = worklists_api.get(target_id) if worklists_api.visible(worklist, current_user): return worklist return None return api_base.entity_get(SUPPORTED_TYPES[target_type], target_id)
def subscription_get_resource(target_type, target_id, current_user=None): if target_type not in SUPPORTED_TYPES: return None if target_type == 'story': return stories_api.story_get(target_id, current_user=current_user) elif target_type == 'task': return tasks_api.task_get(target_id, current_user=current_user) elif target_type == 'worklist': worklist = worklists_api.get(target_id) if worklists_api.visible(worklist, current_user): return worklist return None return api_base.entity_get(SUPPORTED_TYPES[target_type], target_id)
def get_one(self, story_id, task_id): """Retrieve details about one task. :param story_id: An ID of the story. :param task_id: An ID of the task. """ task = tasks_api.task_get(task_id) if task: if task.story_id != story_id: abort(400, _("URL story_id and task.story_id do not match")) return wmodels.Task.from_db_model(task) else: raise exc.NotFound(_("Task %s not found") % task_id)
def get_one(self, story_id, task_id): """Retrieve details about one task. :param story_id: An ID of the story. :param task_id: An ID of the task. """ task = tasks_api.task_get( task_id, current_user=request.current_user_id) if task: if task.story_id != story_id: abort(400, _("URL story_id and task.story_id do not match")) return wmodels.Task.from_db_model(task) else: raise exc.NotFound(_("Task %s not found") % task_id)
def get_one(self, task_id): """Retrieve details about one task. Example:: curl https://my.example.org/api/v1/tasks/24 :param task_id: An ID of the task. """ task = tasks_api.task_get( task_id, current_user=request.current_user_id) if task: return wmodels.Task.from_db_model(task) else: raise exc.NotFound(_("Task %s not found") % task_id)
def put(self, id, item_id, list_position, list_id=None, display_due_date=None): """Update a WorklistItem. This method also updates the positions of other items in affected worklists, if necessary. :param id: The ID of the worklist. :param item_id: The ID of the worklist_item to be moved. :param display_due_date: The ID of the due date displayed on the item. """ user_id = request.current_user_id if not worklists_api.editable_contents(worklists_api.get(id), user_id): raise exc.NotFound(_("Worklist %s not found") % id) card = worklists_api.get_item_by_id(item_id) if card is None: raise exc.NotFound(_("Item %s seems to have been deleted, " "try refreshing your page.") % item_id) item = None if card.item_type == 'story': item = stories_api.story_get( card.item_id, current_user=request.current_user_id) elif card.item_type == 'task': item = tasks_api.task_get( card.item_id, current_user=request.current_user_id) if item is None: raise exc.NotFound(_("Item %s refers to a non-existent task or " "story.") % item_id) worklists_api.move_item(id, item_id, list_position, list_id) if display_due_date is not None: if display_due_date == -1: display_due_date = None update_dict = { 'display_due_date': display_due_date } worklists_api.update_item(item_id, update_dict) updated = worklists_api.get_item_by_id(item_id) result = wmodels.WorklistItem.from_db_model(updated) result.resolve_due_date(updated) return result
def delete(self, task_id): """Delete this task. :param task_id: An ID of the task. """ original_task = copy.deepcopy(tasks_api.task_get(task_id)) if not original_task: raise exc.NotFound(_("Task %s not found.") % task_id) events_api.task_deleted_event( story_id=original_task.story_id, task_id=original_task.id, task_title=original_task.title, author_id=request.current_user_id) tasks_api.task_delete(task_id)
def post(self, id, item_id, item_type, list_position): """Add an item to a worklist. Example:: TODO :param id: The ID of the worklist. :param item_id: The ID of the item. :param item_type: The type of the item (i.e. "story" or "task"). :param list_position: The position in the list to add the item. """ user_id = request.current_user_id if not worklists_api.editable_contents(worklists_api.get(id), user_id): raise exc.NotFound(_("Worklist %s not found") % id) item = None if item_type == 'story': item = stories_api.story_get(item_id, current_user=request.current_user_id) elif item_type == 'task': item = tasks_api.task_get(item_id, current_user=request.current_user_id) if item is None: raise exc.NotFound( _("Item %s refers to a non-existent task or " "story.") % item_id) card = worklists_api.add_item(id, item_id, item_type, list_position, current_user=request.current_user_id) added = { "worklist_id": id, "item_id": item_id, "item_title": item.title, "item_type": item_type, "position": card.list_position } events_api.worklist_contents_changed_event(id, user_id, added=added) return wmodels.WorklistItem.from_db_model(card)
def delete(self, task_id): """Delete this task. :param task_id: An ID of the task. """ original_task = copy.deepcopy( tasks_api.task_get(task_id, current_user=request.current_user_id)) if not original_task: raise exc.NotFound(_("Task %s not found.") % task_id) events_api.task_deleted_event( story_id=original_task.story_id, task_id=original_task.id, task_title=original_task.title, author_id=request.current_user_id) tasks_api.task_delete(task_id)
def post(self, id, item_id, item_type, list_position): """Add an item to a worklist. Example:: TODO :param id: The ID of the worklist. :param item_id: The ID of the item. :param item_type: The type of the item (i.e. "story" or "task"). :param list_position: The position in the list to add the item. """ user_id = request.current_user_id if not worklists_api.editable_contents(worklists_api.get(id), user_id): raise exc.NotFound(_("Worklist %s not found") % id) item = None if item_type == 'story': item = stories_api.story_get( item_id, current_user=request.current_user_id) elif item_type == 'task': item = tasks_api.task_get( item_id, current_user=request.current_user_id) if item is None: raise exc.NotFound(_("Item %s refers to a non-existent task or " "story.") % item_id) card = worklists_api.add_item( id, item_id, item_type, list_position, current_user=request.current_user_id) added = { "worklist_id": id, "item_id": item_id, "item_title": item.title, "item_type": item_type, "position": card.list_position } events_api.worklist_contents_changed_event(id, user_id, added=added) return wmodels.WorklistItem.from_db_model(card)
def get_one(self, story_id, task_id): """Retrieve details about one task. Example:: curl https://my.example.org/api/v1/stories/11/tasks/2691 :param story_id: An ID of the story. :param task_id: An ID of the task. """ task = tasks_api.task_get( task_id, current_user=request.current_user_id) if task: if task.story_id != story_id: abort(400, _("URL story_id and task.story_id do not match")) return wmodels.Task.from_db_model(task) else: raise exc.NotFound(_("Task %s not found") % task_id)
def put(self, task_id, task): """Modify this task. :param task_id: An ID of the task. :param task: A task within the request body. """ original_task = copy.deepcopy(tasks_api.task_get(task_id)) if not original_task: raise exc.NotFound(_("Task %s not found.") % task_id) task = task_is_valid_put(task, original_task) updated_task = tasks_api.task_update(task_id, task.as_dict( omit_unset=True)) post_timeline_events(original_task, updated_task) return wmodels.Task.from_db_model(updated_task)
def put(self, task_id, task): """Modify this task. :param task_id: An ID of the task. :param task: A task within the request body. """ original_task = copy.deepcopy( tasks_api.task_get(task_id, current_user=request.current_user_id)) if not original_task: raise exc.NotFound(_("Task %s not found.") % task_id) task = task_is_valid_put(task, original_task) updated_task = tasks_api.task_update(task_id, task.as_dict( omit_unset=True)) post_timeline_events(original_task, updated_task) return wmodels.Task.from_db_model(updated_task)
def delete(self, id, item_id): """Remove an item from a worklist. Example:: TODO :param id: The ID of the worklist. :param item_id: The ID of the worklist item to be removed. """ user_id = request.current_user_id worklist = worklists_api.get(id) if not worklists_api.editable_contents(worklist, user_id): raise exc.NotFound(_("Worklist %s not found") % id) card = worklists_api.get_item_by_id(item_id) if card is None: raise exc.NotFound(_("Item %s seems to have already been deleted," " try refreshing your page.") % item_id) worklists_api.archive_item(item_id) item = None if card.item_type == 'story': item = stories_api.story_get( card.item_id, current_user=user_id) elif card.item_type == 'task': item = tasks_api.task_get( card.item_id, current_user=user_id) if item is None: item.title = '' removed = { "worklist_id": id, "item_id": card.item_id, "item_type": card.item_type, "item_title": item.title } events_api.worklist_contents_changed_event(id, user_id, removed=removed)
def delete(self, id, item_id): """Remove an item from a worklist. Example:: TODO :param id: The ID of the worklist. :param item_id: The ID of the worklist item to be removed. """ user_id = request.current_user_id worklist = worklists_api.get(id) if not worklists_api.editable_contents(worklist, user_id): raise exc.NotFound(_("Worklist %s not found") % id) card = worklists_api.get_item_by_id(item_id) if card is None: raise exc.NotFound( _("Item %s seems to have already been deleted," " try refreshing your page.") % item_id) worklists_api.update_item(item_id, {'archived': True}) worklists_api.normalize_positions(worklist) item = None if card.item_type == 'story': item = stories_api.story_get(card.item_id, current_user=user_id) elif card.item_type == 'task': item = tasks_api.task_get(card.item_id, current_user=user_id) if item is None: item.title = '' removed = { "worklist_id": id, "item_id": card.item_id, "item_type": card.item_type, "item_title": item.title } events_api.worklist_contents_changed_event(id, user_id, removed=removed)
def put(self, id, item_id, list_position, list_id=None, display_due_date=None): """Update a WorklistItem. This method also updates the positions of other items in affected worklists, if necessary. :param id: The ID of the worklist. :param item_id: The ID of the worklist_item to be moved. :param display_due_date: The ID of the due date displayed on the item. """ user_id = request.current_user_id if not worklists_api.editable_contents(worklists_api.get(id), user_id): raise exc.NotFound(_("Worklist %s not found") % id) card = worklists_api.get_item_by_id(item_id) if card is None: raise exc.NotFound(_("Item %s seems to have been deleted, " "try refreshing your page.") % item_id) item = None if card.item_type == "story": item = stories_api.story_get(card.item_id, current_user=request.current_user_id) elif card.item_type == "task": item = tasks_api.task_get(card.item_id, current_user=request.current_user_id) if item is None: raise exc.NotFound(_("Item %s refers to a non-existent task or " "story.") % item_id) worklists_api.move_item(id, item_id, list_position, list_id) if display_due_date is not None: if display_due_date == -1: display_due_date = None update_dict = {"display_due_date": display_due_date} worklists_api.update_item(item_id, update_dict) updated = worklists_api.get_item_by_id(item_id) result = wmodels.WorklistItem.from_db_model(updated) result.resolve_due_date(updated) return result
def put(self, story_id, task_id, task): """Modify this task. :param story_id: An ID of the story. :param task_id: An ID of the task. :param task: a task within the request body. """ original_task = copy.deepcopy(tasks_api.task_get(task_id)) if not original_task: raise exc.NotFound(_("Task %s not found") % task_id) if original_task.story_id != story_id: abort(400, _("URL story_id and task.story_id do not match")) task = task_is_valid_put(task, original_task) updated_task = tasks_api.task_update(task_id, task.as_dict( omit_unset=True)) post_timeline_events(original_task, updated_task) return wmodels.Task.from_db_model(updated_task)
def post(self, id, item_id, item_type, list_position): """Add an item to a worklist. :param id: The ID of the worklist. :param item_id: The ID of the item. :param item_type: The type of the item (i.e. "story" or "task"). :param list_position: The position in the list to add the item. """ user_id = request.current_user_id if not worklists_api.editable_contents(worklists_api.get(id), user_id): raise exc.NotFound(_("Worklist %s not found") % id) item = None if item_type == "story": item = stories_api.story_get(item_id, current_user=request.current_user_id) elif item_type == "task": item = tasks_api.task_get(item_id, current_user=request.current_user_id) if item is None: raise exc.NotFound(_("Item %s refers to a non-existent task or " "story.") % item_id) worklists_api.add_item(id, item_id, item_type, list_position, current_user=request.current_user_id) return wmodels.WorklistItem.from_db_model(worklists_api.get_item_at_position(id, list_position))
def delete(self, story_id, task_id): """Delete this task. :param story_id: An ID of the story. :param task_id: An ID of the task. """ original_task = copy.deepcopy( tasks_api.task_get(task_id, current_user=request.current_user_id)) if not original_task: raise exc.NotFound(_("Task %s not found.") % task_id) if original_task.story_id != story_id: abort(400, _("URL story_id and task.story_id do not match")) events_api.task_deleted_event( story_id=original_task.story_id, task_id=original_task.id, task_title=original_task.title, author_id=request.current_user_id) tasks_api.task_delete(task_id)
def put(self, story_id, task_id, task): """Modify this task. Example:: curl 'https://my.example.org/api/v1/stories/19/tasks/19' -X PUT \\ -H 'Authorization: Bearer MY_ACCESS_TOKEN' \\ -H 'Content-Type: application/json;charset=UTF-8' \\ --data-binary '{"title":"Task Foio","project_id":153,"key":"todo"}' :param story_id: An ID of the story. :param task_id: An ID of the task. :param task: a task within the request body. """ original_task = copy.deepcopy( tasks_api.task_get(task_id, current_user=request.current_user_id)) if not original_task: raise exc.NotFound(_("Task %s not found") % task_id) if original_task.story_id != story_id: abort(400, _("URL story_id and task.story_id do not match")) if task.story_id and original_task.story_id != task.story_id: abort( 400, _("the story_id of a task cannot be changed through this API"), ) task = task_is_valid_put(task, original_task) updated_task = tasks_api.task_update(task_id, task.as_dict( omit_unset=True)) post_timeline_events(original_task, updated_task) return wmodels.Task.from_db_model(updated_task)
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', item_type=None, board_id=None, subscriber_id=None, offset=None, limit=None): """Retrieve definitions of all of the worklists. Example:: curl https://my.example.org/api/v1/worklists :param title: A string to filter the title by. :param creator_id: Filter worklists by their creator. :param project_id: Filter worklists by project ID. :param archived: Filter worklists by whether they are archived or not. :param user_id: Filter worklists by the users with permissions. :param story_id: Filter worklists by whether they contain a story. :param task_id: Filter worklists by whether they contain a task. :param hide_lanes: If true, don't return worklists which are lanes in a board. :param sort_field: The name of the field to sort on. :param sort_dir: Sort direction for results (asc, desc). :param item_type: Used when filtering by story_id. If item_type is 'story' then only return worklists that contain the story, if item_type is 'task' then only return worklists that contain tasks from the story, otherwise return worklists that contain the story or tasks from the story. :param board_id: Get all worklists in the board with this id. Other filters are not applied. :param subscriber_id: Filter worklists by whether a user is subscribed. :param offset: Offset at which to begin the results. :param limit: Maximum number of results to return. """ current_user = request.current_user_id # If a non existent story/task is requested, there is no point trying # to find worklists which contain it if story_id: story = stories_api.story_get(story_id, current_user=current_user) if story is None: response.headers['X-Total'] = '0' return [] if task_id: task = tasks_api.task_get(task_id, current_user=current_user) if task is None: response.headers['X-Total'] = '0' return [] worklists = worklists_api.get_all(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, subscriber_id=subscriber_id, sort_field=sort_field, sort_dir=sort_dir, offset=offset, limit=limit, current_user=current_user, hide_lanes=hide_lanes, item_type=item_type) 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, subscriber_id=subscriber_id, current_user=current_user, hide_lanes=hide_lanes, item_type=item_type) visible_worklists = [] for worklist in worklists: 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(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
def add_item(worklist_id, item_id, item_type, list_position, current_user=None): worklist = _worklist_get(worklist_id) if worklist is None: raise exc.NotFound(_("Worklist %s not found") % worklist_id) # If the target position is "outside" the list, override it if list_position > worklist.items.count(): list_position = worklist.items.count() # Check if this item has an archived card in this worklist to restore archived = get_item_by_item_id(worklist, item_type, item_id, archived=True) if archived: update_item(archived.id, {'archived': False}) # Move the newly unarchived card into position, and move other cards # to compensate for the move move_item(archived.id, list_position) return archived # If this worklist is a lane, check if the item has an archived card # somewhere in the board to restore if is_lane(worklist): board = boards.get_from_lane(worklist) archived = boards.get_card(board, item_type, item_id, archived=True) if archived: update_item(archived.id, {'archived': False}) # Move the newly unarchived card into position, and move other # cards to compensate for the move move_item(archived.id, list_position, new_list_id=worklist_id) return archived # Create a new card if item_type == 'story': item = stories_api.story_get(item_id, current_user=current_user) elif item_type == 'task': item = tasks_api.task_get(item_id, current_user=current_user) else: raise ClientSideError( _("An item in a worklist must be either a " "story or a task")) if item is None: raise exc.NotFound( _("%(type)s %(id)s not found") % { 'type': item_type, 'id': item_id }) card_dict = { 'list_id': worklist_id, 'item_id': item_id, 'item_type': item_type, 'list_position': 99999 # Initialise the card "outside" the list } card = api_base.entity_create(models.WorklistItem, card_dict) # Move the card into position, and move other cards to compensate card = move_item(card.id, list_position) if worklist.items is None: worklist.items = [card] else: worklist.items.append(card) return card
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)
def get_all(self, story_id, title=None, assignee_id=None, project_id=None, project_group_id=None, branch_id=None, milestone_id=None, status=None, priority=None, marker=None, limit=None, sort_field='id', sort_dir='asc', link=None): """Retrieve definitions of all of the tasks. :param story_id: filter tasks by story ID. :param title: search by task title. :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 priority: filter tasks by priority. :param marker: The resource id where the page should begin. :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). """ # Boundary check on limit. if limit is not None: limit = max(0, limit) # Resolve the marker record. marker_task = tasks_api.task_get( marker, current_user=request.current_user_id) tasks = tasks_api \ .task_get_all(title=title, link=link, 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, priority=priority, sort_field=sort_field, sort_dir=sort_dir, marker=marker_task, limit=limit, current_user=request.current_user_id) task_count = tasks_api \ .task_get_count(title=title, link=link, 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, priority=priority, current_user=request.current_user_id) # Apply the query response headers. response.headers['X-Limit'] = str(limit) response.headers['X-Total'] = str(task_count) if marker_task: response.headers['X-Marker'] = str(marker_task.id) return [wmodels.Task.from_db_model(s) for s in tasks]
def put(self, id, item_id, list_position, list_id=None, display_due_date=None): """Update a WorklistItem. Example:: TODO This method also updates the positions of other items in affected worklists, if necessary. :param id: The ID of the worklist. :param item_id: The ID of the worklist_item to be moved. :param display_due_date: The ID of the due date displayed on the item. """ user_id = request.current_user_id if not worklists_api.editable_contents(worklists_api.get(id), user_id): raise exc.NotFound(_("Worklist %s not found") % id) card = worklists_api.get_item_by_id(item_id) if card is None: raise exc.NotFound( _("Item %s seems to have been deleted, " "try refreshing your page.") % item_id) item = None if card.item_type == 'story': item = stories_api.story_get(card.item_id, current_user=request.current_user_id) elif card.item_type == 'task': item = tasks_api.task_get(card.item_id, current_user=request.current_user_id) if item is None: raise exc.NotFound( _("Item %s refers to a non-existent task or " "story.") % item_id) old = { "worklist_id": card.list_id, "item_id": card.item_id, "item_title": item.title, "item_type": card.item_type, "position": card.list_position, "due_date_id": card.display_due_date } new = { "item_id": card.item_id, "item_title": item.title, "item_type": card.item_type } if list_position != card.list_position and list_position is not None: new['position'] = list_position if list_id != card.list_id and list_id is not None: new['worklist_id'] = list_id worklists_api.move_item(id, item_id, list_position, list_id) if display_due_date is not None: if display_due_date == -1: display_due_date = None update_dict = {'display_due_date': display_due_date} worklists_api.update_item(item_id, update_dict) new['due_date_id'] = display_due_date updated = {"old": old, "new": new} events_api.worklist_contents_changed_event(id, user_id, updated=updated) updated = worklists_api.get_item_by_id(item_id) result = wmodels.WorklistItem.from_db_model(updated) result.resolve_due_date(updated) return result
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', item_type=None, board_id=None, subscriber_id=None, offset=None, limit=None): """Retrieve definitions of all of the worklists. Example:: curl https://my.example.org/api/v1/worklists :param title: A string to filter the title by. :param creator_id: Filter worklists by their creator. :param project_id: Filter worklists by project ID. :param archived: Filter worklists by whether they are archived or not. :param user_id: Filter worklists by the users with permissions. :param story_id: Filter worklists by whether they contain a story. :param task_id: Filter worklists by whether they contain a task. :param hide_lanes: If true, don't return worklists which are lanes in a board. :param sort_field: The name of the field to sort on. :param sort_dir: Sort direction for results (asc, desc). :param item_type: Used when filtering by story_id. If item_type is 'story' then only return worklists that contain the story, if item_type is 'task' then only return worklists that contain tasks from the story, otherwise return worklists that contain the story or tasks from the story. :param board_id: Get all worklists in the board with this id. Other filters are not applied. :param subscriber_id: Filter worklists by whether a user is subscribed. :param offset: Offset at which to begin the results. :param limit: Maximum number of results to return. """ current_user = request.current_user_id # If a non existent story/task is requested, there is no point trying # to find worklists which contain it if story_id: story = stories_api.story_get(story_id, current_user=current_user) if story is None: response.headers['X-Total'] = '0' return [] if task_id: task = tasks_api.task_get(task_id, current_user=current_user) if task is None: response.headers['X-Total'] = '0' return [] worklists = worklists_api.get_all(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, subscriber_id=subscriber_id, sort_field=sort_field, sort_dir=sort_dir, offset=offset, limit=limit, current_user=current_user, hide_lanes=hide_lanes, item_type=item_type) 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, subscriber_id=subscriber_id, current_user=current_user, hide_lanes=hide_lanes, item_type=item_type) visible_worklists = [] for worklist in worklists: 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(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
def put(self, id, item_id, list_position, list_id=None, display_due_date=None): """Update a WorklistItem. Example:: TODO This method also updates the positions of other items in affected worklists, if necessary. :param id: The ID of the worklist. :param item_id: The ID of the worklist_item to be moved. :param display_due_date: The ID of the due date displayed on the item. """ user_id = request.current_user_id if not worklists_api.editable_contents(worklists_api.get(id), user_id): raise exc.NotFound(_("Worklist %s not found") % id) card = worklists_api.get_item_by_id(item_id) if card is None: raise exc.NotFound(_("Item %s seems to have been deleted, " "try refreshing your page.") % item_id) item = None if card.item_type == 'story': item = stories_api.story_get( card.item_id, current_user=request.current_user_id) elif card.item_type == 'task': item = tasks_api.task_get( card.item_id, current_user=request.current_user_id) if item is None: raise exc.NotFound(_("Item %s refers to a non-existent task or " "story.") % item_id) old = { "worklist_id": card.list_id, "item_id": card.item_id, "item_title": item.title, "item_type": card.item_type, "position": card.list_position, "due_date_id": card.display_due_date } new = { "item_id": card.item_id, "item_title": item.title, "item_type": card.item_type } if list_position != card.list_position and list_position is not None: new['position'] = list_position if list_id != card.list_id and list_id is not None: new['worklist_id'] = list_id worklists_api.move_item(item_id, list_position, list_id) if display_due_date is not None: if display_due_date == -1: display_due_date = None update_dict = { 'display_due_date': display_due_date } worklists_api.update_item(item_id, update_dict) new['due_date_id'] = display_due_date updated = { "old": old, "new": new } events_api.worklist_contents_changed_event(id, user_id, updated=updated) updated = worklists_api.get_item_by_id(item_id) result = wmodels.WorklistItem.from_db_model(updated) result.resolve_due_date(updated) return result