Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add orchestra api for todo templates and starting order #736

Merged
merged 153 commits into from
Jan 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
153 commits
Select commit Hold shift + click to select a range
51f0966
get todo templates
Jan 15, 2021
f729ee5
add todos from template
Jan 19, 2021
2bd39de
Implement api to get starting order
Jan 20, 2021
f313aef
fix lint errors
Jan 20, 2021
3c30eb8
allow passing additional data
Jan 20, 2021
7fae743
Added tests for error cases
Jan 20, 2021
9d0757f
set todo status as declined if skipped
Jan 20, 2021
f1ea5a6
Test status field in todo
Jan 21, 2021
ed0bed0
fix lint
Jan 21, 2021
d8e6d9a
remove print
Jan 21, 2021
171e564
fix tests
Jan 21, 2021
f986354
get todo templates
Jan 15, 2021
4a6add3
add todos from template
Jan 19, 2021
c80af31
Implement api to get starting order
Jan 20, 2021
687a46f
fix lint errors
Jan 20, 2021
88291b3
allow passing additional data
Jan 20, 2021
0a4b6a7
Added tests for error cases
Jan 20, 2021
88a3585
set todo status as declined if skipped
Jan 20, 2021
c6e5d01
Test status field in todo
Jan 21, 2021
acd0cb8
fix lint
Jan 21, 2021
5f502da
remove print
Jan 21, 2021
6fe2abc
fix tests
Jan 21, 2021
5ff6c51
remove starting order api
Jan 22, 2021
4d19b99
Merge branch 'todo-template-api' of github.com:b12io/orchestra into t…
Jan 22, 2021
f267d8f
Version bump.
Jul 31, 2018
445ca8f
Added Task Created column (#473)
Jul 31, 2018
0dbf521
Assignment lookup bugfix (#475)
marcua Aug 1, 2018
f84d1f7
Introduce the paused state to Project (#477)
paopow Aug 13, 2018
d66bbef
Automatically archive slack channels of completed/aborted projects (#…
paopow Aug 20, 2018
20d65ac
Version bump.
paopow Aug 20, 2018
80861e3
Added todolist_templates_to_apply with automatic application (#476)
Aug 21, 2018
1ef99a8
Add message_project_team endpoint (#479)
jumasheff Sep 19, 2018
e0d2bce
Version bump.
jumasheff Sep 20, 2018
d4f01da
Add a column on to the list display (#480)
paopow Sep 25, 2018
9f4061c
Add a tags column to dashboard (#481)
paopow Oct 4, 2018
826c564
Version bump.
paopow Oct 4, 2018
c2d8536
Add radio input support to the required field directive (#483)
paopow Oct 9, 2018
98f94e4
Version bump.
paopow Oct 9, 2018
67108a4
Add day to the team-info-card's time display (#484)
paopow Oct 31, 2018
399183d
Version bump.
paopow Oct 31, 2018
4da6f03
If assignment status is complete or failed return task (#485)
jumasheff Nov 19, 2018
6fbf5b4
Version bump.
jumasheff Nov 19, 2018
c767c3a
Extend get_project_information (#486)
jumasheff Jan 18, 2019
2113666
Version bump.
jumasheff Jan 22, 2019
79a01c3
Use unpacked steps (#487)
jumasheff Jan 24, 2019
989f571
Version bump.
paopow Jan 24, 2019
c449e2e
Open links in task details in new tabs (#488)
jumasheff Jan 28, 2019
600120c
Version bump.
jumasheff Jan 28, 2019
b77c7ba
Update README.md (#490)
katelyngray Mar 13, 2019
f553ab9
Version bump.
paopow Mar 13, 2019
2b8d110
Update README.md (#491)
katelyngray Mar 14, 2019
0d90d44
Update README.md
marcua Mar 14, 2019
744c43f
Update node & yarn; Don't consider subset dependency changes to be to…
marcua Apr 16, 2019
26191ba
Version bump.
marcua Apr 16, 2019
ae78809
Version bump.
marcua Apr 16, 2019
c6b38ea
Load vendor.js before other js files (#493)
jumasheff Apr 25, 2019
69c4805
Promisify signals.fireSignal (#494)
jumasheff Apr 30, 2019
d451f2c
Version bump.
jumasheff Apr 30, 2019
0015297
Revert "Load vendor.js before other js files (#493)" (#495)
jumasheff May 1, 2019
c8ceae3
Version bump.
jumasheff May 1, 2019
af3d588
Add raw_id_fields (#496)
jumasheff May 8, 2019
796e15c
Fix bugs and clarify the 5-minute getting started guide (#497)
marcua May 10, 2019
810f5ae
Expand on the Google settings documentation (#498)
marcua May 16, 2019
185da70
Use distinct email addresses for each of the sample accounts (#499)
marcua May 28, 2019
692cfe3
Version bump.
marcua May 28, 2019
62bbe4b
Dashboard tmpl todos (#531)
paopow Jun 13, 2019
68613a4
Fix typo in docs (#533)
marcua Jun 16, 2019
bdb4da9
Reduce Slack API usage (#532)
paopow Jun 17, 2019
9d8e1f6
Version bump.
paopow Jun 17, 2019
7799bae
Fix the todos dashboard bugs (#535)
paopow Jun 26, 2019
08e046c
Update compiled js (#536)
paopow Jun 27, 2019
55de2b8
Version bump.
paopow Jun 27, 2019
4a28fe7
adding dependabot config
dastanko Jan 14, 2020
ac88768
Adding deps-upgrade script (#576)
dastanko Jan 22, 2020
d64d602
Revert "Adding deps-upgrade script (#576)" (#579)
dastanko Jan 23, 2020
81a4872
Upgrading dependencies 2020 01 30 (#580)
dastanko Feb 4, 2020
5a5fae0
Version bump.
dastanko Feb 4, 2020
4611f9b
Adding a staffbot button to task assignment (#594)
paopow Feb 7, 2020
9230b7f
Version bump.
paopow Feb 7, 2020
d12425c
Update django version to 2.2.9 (#578)
progremir Feb 10, 2020
b42c49a
Version bump.
progremir Feb 11, 2020
04a0763
Move the code around a bit
paopow Mar 2, 2020
2d8ccab
Revert "Move the code around a bit"
paopow Mar 2, 2020
e9d7d1b
Only allow one active staffbot request per task (#605)
paopow Apr 3, 2020
25031e8
Version bump.
paopow Apr 3, 2020
a073e3c
Add function that runs when projects are aborted (#611)
jumasheff Apr 15, 2020
45d0992
Version bump.
jumasheff Apr 15, 2020
2d36904
Version bump.
jumasheff Apr 15, 2020
fc09372
Reactify Frontend for orchestra (#606)
elstonayx Jun 3, 2020
18e1e75
Allows re-loading a workflow version with --force if it has new steps…
thisisdhaas Jun 5, 2020
04e9a87
Version bump.
Jun 10, 2020
feae3cb
Checks in build artifacts for the React frontend. (#624)
thisisdhaas Jun 10, 2020
bccaa02
Version bump.
Jun 11, 2020
bbcd150
Fix email template (#552)
PavelBastov Jun 19, 2020
22e0ef6
Upgrading dependencies 2020 07 06 (#646)
dastanko Jul 13, 2020
b929d9c
Fixing release script (#651)
dastanko Jul 14, 2020
3c01adf
Version bump.
dastanko Jul 14, 2020
9e17d54
Add autocomplete fields (#660)
jumasheff Aug 10, 2020
d933b48
Rename Todo.description to Todo.title (#661)
jumasheff Aug 12, 2020
30aa8b5
Task unification: add fields to todo (#663)
jumasheff Aug 18, 2020
236d1f2
Upgrading dependencies 2020 08 12 (#662)
dastanko Aug 24, 2020
ed85b83
Version bump.
dastanko Aug 24, 2020
2046874
Todo: viewset, serializer (#666)
jumasheff Aug 27, 2020
12279c2
Task unification main branch (#683)
jumasheff Sep 17, 2020
b7ae316
Version bump.
jumasheff Sep 17, 2020
cee4889
Todo list template export/import via Google Sheets (#665)
marcua Sep 20, 2020
f2732ca
Version bump.
marcua Sep 20, 2020
24d5743
Fix permission issue (#686)
jumasheff Sep 23, 2020
f798f4d
Add autocomplete fields (#685)
jumasheff Sep 23, 2020
2fc8c76
Reset todo form after submission (#687)
jumasheff Sep 23, 2020
55e0e92
Version bump.
jumasheff Sep 23, 2020
225c6d1
Add a notion of completion_ends_project to Orchestra steps (#684)
adbharadwaj Sep 25, 2020
a163036
Version bump.
Sep 25, 2020
3f9b2bc
Version bump.
Sep 25, 2020
74e38d1
Speed up todo lists loading time on task page (#688)
adbharadwaj Oct 1, 2020
221c545
Version bump.
Oct 1, 2020
8d84f71
Fix todolists and order steps on the project management page in the o…
adbharadwaj Oct 7, 2020
bb6e333
Version bump.
Oct 7, 2020
e1442b7
render children items if the parent is expanded (#694)
adbharadwaj Oct 19, 2020
7a48a9f
Version bump.
Oct 19, 2020
2b56470
Add restaff button to Team info card (#693)
jumasheff Oct 20, 2020
10d0893
Team info card: show unassigned (#695)
jumasheff Oct 22, 2020
9f57a41
Version bump.
jumasheff Oct 22, 2020
ca6d8da
orchestra_api fixes (#699)
jumasheff Nov 12, 2020
d7627a6
Linkify urls in todo title (#715)
adbharadwaj Nov 30, 2020
b5f6257
Version bump.
Nov 30, 2020
525df9d
use pip version 20.2.4 for circleci (#716)
adbharadwaj Nov 30, 2020
799e073
Use linky instead of linkify (#724)
adbharadwaj Dec 2, 2020
5c1db20
Version bump.
Dec 2, 2020
1a99292
Filter staffing requests from completed projects (#726)
adbharadwaj Dec 16, 2020
7811df6
Version bump.
Dec 16, 2020
b6ff34c
Remove unused Kronos dependency (#734)
adbharadwaj Jan 7, 2021
2a6fd98
Version bump.
Jan 7, 2021
91f596f
get todo templates
Jan 15, 2021
cfcc455
add todos from template
Jan 19, 2021
225cdd4
Implement api to get starting order
Jan 20, 2021
9db42bd
fix lint errors
Jan 20, 2021
32ba349
allow passing additional data
Jan 20, 2021
5081cce
Added tests for error cases
Jan 20, 2021
121a8ac
set todo status as declined if skipped
Jan 20, 2021
254dbd2
Test status field in todo
Jan 21, 2021
9866146
fix lint
Jan 21, 2021
85c0723
remove print
Jan 21, 2021
fed317e
fix tests
Jan 21, 2021
3b86747
Pin py-moneyed dependency (#737)
adbharadwaj Jan 21, 2021
fd974ab
Version bump.
Jan 21, 2021
9a03584
fix rebase conflicts
Jan 22, 2021
8c6c565
fix rebase conflicts
Jan 22, 2021
23f886f
fix rebase conflicts
Jan 22, 2021
40bff9a
remove print
Jan 21, 2021
e1d7d97
Fix rebase conflicts
Jan 22, 2021
234bed9
Merge branch 'todo-template-api' of github.com:b12io/orchestra into t…
Jan 22, 2021
8259c2e
return step id with project information api
Jan 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions orchestra/api_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from orchestra.project_api.views import workflow_types
from orchestra.project_api.views import message_project_team
from orchestra.project_api.views import TodoApiViewset
from orchestra.project_api.views import TodoTemplatesList
from orchestra.project_api.views import create_todos_from_template
from orchestra.views import TimeEntryDetail
from orchestra.views import TimeEntryList
from orchestra.views import dashboard_tasks
Expand Down Expand Up @@ -87,6 +89,12 @@
url(r'^project/message_project_team',
message_project_team,
name='message_project_team'),
url(r'^project/todo_templates/$',
TodoTemplatesList.as_view(),
name='todo_templates'),
url(r'^project/create_todos_from_template/$',
create_todos_from_template,
name='create_todos_from_template'),
]

router = routers.SimpleRouter()
Expand Down
18 changes: 18 additions & 0 deletions orchestra/orchestra_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,21 @@ def message_project_team(project_id, message):
response = _make_api_request('post', 'message_project_team',
data=json.dumps(data))
return json.loads(response.text)


def get_todo_templates():
response = _make_api_request('get', 'todo_templates')
return json.loads(response.text)


def create_todos_from_template(todolist_template_slug, project_id,
step_slug, additional_data):
data = {
'todolist_template_slug': todolist_template_slug,
'project_id': project_id,
'step_slug': step_slug,
'additional_data': additional_data,
}
response = _make_api_request('post', 'create_todos_from_template',
data=json.dumps(data))
return json.loads(response.text)
4 changes: 3 additions & 1 deletion orchestra/project_api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ def _traverse_step_graph(graph, workflow_version):
current_step = Step.objects.get(
workflow_version=workflow_version,
slug=current_node)
steps.append({'slug': current_node,
steps.append({
'id': current_step.id,
'slug': current_node,
'description': current_step.description,
'is_human': current_step.is_human,
'name': current_step.name})
Expand Down
62 changes: 62 additions & 0 deletions orchestra/project_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@

from django.urls import reverse
from jsonview.exceptions import BadRequest
from rest_framework import generics

from orchestra.core.errors import TaskAssignmentError
from orchestra.core.errors import WorkerCertificationError
from orchestra.models import Project
from orchestra.models import WorkerCertification
from orchestra.models import Workflow
from orchestra.models import Todo
from orchestra.models import TodoListTemplate
from orchestra.project import create_project_with_tasks
from orchestra.project_api.api import get_project_information
from orchestra.utils.decorators import api_endpoint
Expand All @@ -19,6 +22,9 @@
from orchestra.project_api.auth import OrchestraProjectAPIAuthentication
from orchestra.project_api.auth import IsSignedUser
from orchestra.todos.views import GenericTodoViewset
from orchestra.todos.serializers import TodoListTemplateSerializer
from orchestra.todos.serializers import BulkTodoSerializerWithoutQA
from orchestra.todos.api import add_todolist_template

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -157,10 +163,66 @@ def message_project_team(request):
return {'success': True}


@api_endpoint(methods=['POST'],
permissions=(IsSignedUser,),
logger=logger,
auths=(OrchestraProjectAPIAuthentication,))
def create_todos_from_template(request):
"""
Endpoint for creating todos in a project.
Payload example:
{
'todolist_template_slug': 'some-template-slug-123',
'step_slug': 'some-step-slug-123',
'project_id': 'some-project-id-123'
'additional_data': {
'some_key': 'some_value'
}
}
"""
data = load_encoded_json(request.body)
try:
todolist_template_slug = data.get('todolist_template_slug')
step_slug = data.get('step_slug')
project_id = data.get('project_id')
additional_data = data.get('additional_data')
if step_slug and project_id and todolist_template_slug:
add_todolist_template(todolist_template_slug, project_id,
step_slug, additional_data)
todos = Todo.objects.filter(
template__slug=todolist_template_slug,
project__id=project_id,
step__slug=step_slug).order_by('-created_at')
serializer = BulkTodoSerializerWithoutQA(todos, many=True)
return {
'success': True,
'todos': serializer.data
}
else:
text = ('An object with `template_slug`, `step_slug`,'
' and `project_id` attributes should be supplied')
raise Exception(text)
except Exception as e:
return {
'success': False,
'errors': {
'error': str(e)
}
}


class TodoApiViewset(GenericTodoViewset):
"""
This viewset inherits from GenericTodoViewset and used by
an orchestra-client facing endpoint, exposed via a router in api_urls.py
"""
permission_classes = (IsSignedUser,)
authentication_classes = (OrchestraProjectAPIAuthentication,)


class TodoTemplatesList(generics.ListAPIView):
permission_classes = (IsSignedUser,)
authentication_classes = (OrchestraProjectAPIAuthentication,)

serializer_class = TodoListTemplateSerializer
queryset = TodoListTemplate.objects.all()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

queryset = TodoListTemplate.objects.filter(is_deleted=False)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we will need this because we are inheriting from BaseModel which inherits from BaseModelManager.

class TodoListTemplate(TodoListTemplateMixin, BaseModel):

class BaseModel(DeleteMixin, models.Model):
"""
Abstract base class models which defines created_at and is_deleted fields.
Attributes:
created_at (datetime.datetime):
Datetime at which the model is created.
is_deleted (boolean):
If value is True, mdoel is deleted. Default is False.
"""
objects = BaseModelManager()
unsafe_objects = models.Manager()

class BaseModelManager(models.Manager):
"""
Model manager intended to be used with models with an `is_deleted` field.
Overrides the initial QuerySet to filter for objects where `is_deleted`
is false.
"""
def get_queryset(self):
return super().get_queryset().filter(is_deleted=False)

BaseModelManager sets the default query to is_deleted=False

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be sure, I confirmed by deleting a todolist template and made sure that we don't need is_deleted=False

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow! Ignore my suggestion. A!

181 changes: 181 additions & 0 deletions orchestra/tests/test_project_api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,198 @@

from orchestra.models import Todo
from orchestra.tests.helpers.fixtures import TodoFactory
from orchestra.tests.helpers.fixtures import TodoListTemplateFactory
from orchestra.tests.helpers.fixtures import StepFactory
from orchestra.tests.helpers.fixtures import ProjectFactory
from orchestra.tests.helpers.fixtures import WorkflowVersionFactory
from orchestra.project_api.auth import SignedUser
from orchestra.orchestra_api import create_todos
from orchestra.orchestra_api import get_todos
from orchestra.orchestra_api import get_todo_templates
from orchestra.orchestra_api import create_todos_from_template
from orchestra.orchestra_api import update_todos
from orchestra.orchestra_api import delete_todos
from orchestra.orchestra_api import OrchestraError


class TodoTemplatesAPITests(TestCase):
def setUp(self):
super().setUp()
self.request_client = APIClient(enforce_csrf_checks=True)
self.request_client.force_authenticate(user=SignedUser())

self.todolist_template_slug = 'test_todolist_template_slug'
self.todolist_template_name = 'test_todolist_template_name'
self.todolist_template_description = \
'test_todolist_template_description'
self.workflow_version = WorkflowVersionFactory()
self.step = StepFactory(
slug='step-slug',
workflow_version=self.workflow_version)
self.project = ProjectFactory(
workflow_version=self.workflow_version)

@patch('orchestra.orchestra_api.requests')
def test_get_todo_templates(self, mock_request):
# This converts `requests.get` into DRF's `APIClient.get`
# To make it testable
def get(url, *args, **kwargs):
return_value = self.request_client.get(url, format='json')
return_value.text = json.dumps(return_value.data)
return return_value

mock_request.get = get

template1 = TodoListTemplateFactory()
template2 = TodoListTemplateFactory()

# Get template1 and template2
res = get_todo_templates()
self.assertEqual(len(res), 2)
expected_ids = [template1.id, template2.id]
for r in res:
self.assertIn(r['id'], expected_ids)

# # Get newly created template3
template3 = TodoListTemplateFactory()
res = get_todo_templates()
self.assertEqual(len(res), 3)
self.assertEqual(res[2]['id'], template3.id)

@patch('orchestra.orchestra_api.requests')
def test_create_todos_from_template(self, mock_request):
# This converts `requests.post` into DRF's `APIClient.post`
# To make it testable
def post(url, *args, **kwargs):
kw = kwargs.get('data', '')
data = json.loads(kw)
return_value = self.request_client.post(url, data, format='json')
return_value.text = json.dumps(return_value.json())
return return_value

todolist_template = TodoListTemplateFactory(
slug=self.todolist_template_slug,
name=self.todolist_template_name,
description=self.todolist_template_description,
todos={'items': [{
'id': 1,
'description': 'todo parent',
'project': self.project.id,
'step': self.step.slug,
'items': [{
'id': 2,
'project': self.project.id,
'step': self.step.slug,
'description': 'todo child',
'items': []
}]
}]},
)

mock_request.post = post
additional_data = {
'some_additional_data': 'value'
}
result = create_todos_from_template(
self.todolist_template_slug,
self.project.id,
self.step.slug,
additional_data)
self.assertEqual(result['success'], True)
self.assertEqual(len(result['todos']), 3)
for t in result['todos']:
self.assertEqual(t['template'], todolist_template.id)
self.assertEqual(t['section'], None)
self.assertEqual(t['additional_data'], additional_data)

@patch('orchestra.orchestra_api.requests')
def test_create_todos_from_template_key_error(self, mock_request):
# This converts `requests.post` into DRF's `APIClient.post`
# To make it testable
def post(url, *args, **kwargs):
kw = kwargs.get('data', '')
data = json.loads(kw)
return_value = self.request_client.post(url, data, format='json')
return_value.text = json.dumps(return_value.json())
return return_value

TodoListTemplateFactory(
slug=self.todolist_template_slug,
name=self.todolist_template_name,
description=self.todolist_template_description,
todos={'items': [{
'id': 1,
'description': 'todo parent',
'project': self.project.id,
'step': self.step.slug,
'items': [{
'id': 2,
'project': self.project.id,
'step': self.step.slug,
'description': 'todo child',
'items': []
}]
}]},
)

mock_request.post = post
additional_data = {
'some_additional_data': 'value'
}
result = create_todos_from_template(
self.todolist_template_slug,
self.project.id,
None,
additional_data)
err_msg = ('An object with `template_slug`, `step_slug`,'
' and `project_id` attributes should be supplied')
self.assertEqual(result['success'], False)
self.assertEqual(len(result['errors']), 1)
self.assertEqual(result['errors']['error'], err_msg)

@patch('orchestra.orchestra_api.requests')
def test_create_todos_from_template_unknown_step_slug(self, mock_request):
# This converts `requests.post` into DRF's `APIClient.post`
# To make it testable
def post(url, *args, **kwargs):
kw = kwargs.get('data', '')
data = json.loads(kw)
return_value = self.request_client.post(url, data, format='json')
return_value.text = json.dumps(return_value.json())
return return_value

TodoListTemplateFactory(
slug=self.todolist_template_slug,
name=self.todolist_template_name,
description=self.todolist_template_description,
todos={'items': [{
'id': 1,
'description': 'todo parent',
'project': self.project.id,
'step': self.step.slug,
'items': [{
'id': 2,
'project': self.project.id,
'step': self.step.slug,
'description': 'todo child',
'items': []
}]
}]},
)

mock_request.post = post
additional_data = {
'some_additional_data': 'value'
}
result = create_todos_from_template(
self.todolist_template_slug,
self.project.id,
'unknown-step-slug',
additional_data)
self.assertEqual(result['success'], False)
self.assertEqual(len(result['errors']), 1)


class TodoAPITests(TestCase):
def setUp(self):
super().setUp()
Expand Down
17 changes: 13 additions & 4 deletions orchestra/tests/test_todos.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ def _todo_data(title, completed,
due=None, parent_todo=None, template=None,
activity_log=str({'actions': []}), qa=None,
project=None, step=None, details=None, is_deleted=False):
if skipped_datetime:
status = Todo.Status.DECLINED.value
elif completed:
status = Todo.Status.COMPLETED.value
else:
status = Todo.Status.PENDING.value
return {
'completed': completed,
'title': title,
Expand All @@ -56,7 +62,7 @@ def _todo_data(title, completed,
'order': None,
'project': project,
'section': None,
'status': None,
'status': status,
'step': step,
'details': details,
'is_deleted': is_deleted
Expand Down Expand Up @@ -137,7 +143,8 @@ def _verify_todo_creation(self, success, project, step, mock_notify):
resp = self.request_client.post(self.list_create_url, {
'project': project,
'step': step.slug,
'title': self.todo_title})
'title': self.todo_title,
'status': Todo.Status.PENDING.value})
if success:
self.assertEqual(resp.status_code, 201)
self.assertEqual(Todo.objects.all().count(), num_todos + 1)
Expand Down Expand Up @@ -210,7 +217,8 @@ def test_create_todo_with_start_by_datetime(self):
project=self.project,
step=self.step,
start_by_datetime=self.deadline,
title=START_TITLE)
title=START_TITLE,
status=Todo.Status.PENDING.value)

self._verify_todos_list(start_by_todo.project.id, [
_todo_data(
Expand All @@ -230,7 +238,8 @@ def test_create_todo_with_due_datetime(self):
project=self.project,
step=self.step,
due_datetime=self.deadline,
title=DUE_TITLE)
title=DUE_TITLE,
status=Todo.Status.PENDING.value)

self._verify_todos_list(due_todo.project.id, [
_todo_data(
Expand Down