Add estimated_start, estimated_finish filters to tasks, userstories and milestones
parent
e3226f4cb9
commit
421a213f5e
|
@ -10,6 +10,7 @@
|
|||
- Ability to create rich text custom fields in Epics, User Stories, Tasks and Isues.
|
||||
|
||||
### Misc
|
||||
- API: Filter milestones, user stories and tasks by estimated_start and estimated_finish dates.
|
||||
- Lots of small and not so small bugfixes.
|
||||
|
||||
|
||||
|
|
|
@ -526,6 +526,22 @@ class FinishDateFilter(BaseDateFilter):
|
|||
filter_name_base = "finish_date"
|
||||
|
||||
|
||||
class EstimatedStartFilter(BaseDateFilter):
|
||||
filter_name_base = "estimated_start"
|
||||
|
||||
|
||||
class EstimatedFinishFilter(BaseDateFilter):
|
||||
filter_name_base = "estimated_finish"
|
||||
|
||||
|
||||
class MilestoneEstimatedStartFilter(BaseDateFilter):
|
||||
filter_name_base = "milestone__estimated_start"
|
||||
|
||||
|
||||
class MilestoneEstimatedFinishFilter(BaseDateFilter):
|
||||
filter_name_base = "milestone__estimated_finish"
|
||||
|
||||
|
||||
#####################################################################
|
||||
# Text search filters
|
||||
#####################################################################
|
||||
|
|
|
@ -46,7 +46,13 @@ class MilestoneViewSet(HistoryResourceMixin, WatchedResourceMixin,
|
|||
serializer_class = serializers.MilestoneSerializer
|
||||
validator_class = validators.MilestoneValidator
|
||||
permission_classes = (permissions.MilestonePermission,)
|
||||
filter_backends = (filters.CanViewMilestonesFilterBackend,)
|
||||
filter_backends = (
|
||||
filters.CanViewMilestonesFilterBackend,
|
||||
filters.CreatedDateFilter,
|
||||
filters.ModifiedDateFilter,
|
||||
filters.EstimatedStartFilter,
|
||||
filters.EstimatedFinishFilter,
|
||||
)
|
||||
filter_fields = (
|
||||
"project",
|
||||
"project__slug",
|
||||
|
|
|
@ -59,6 +59,8 @@ class TaskViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, Wa
|
|||
filters.QFilter,
|
||||
filters.CreatedDateFilter,
|
||||
filters.ModifiedDateFilter,
|
||||
filters.MilestoneEstimatedStartFilter,
|
||||
filters.MilestoneEstimatedFinishFilter,
|
||||
filters.FinishedDateFilter)
|
||||
filter_fields = ["user_story",
|
||||
"milestone",
|
||||
|
|
|
@ -70,6 +70,8 @@ class UserStoryViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixi
|
|||
base_filters.CreatedDateFilter,
|
||||
base_filters.ModifiedDateFilter,
|
||||
base_filters.FinishDateFilter,
|
||||
base_filters.MilestoneEstimatedStartFilter,
|
||||
base_filters.MilestoneEstimatedFinishFilter,
|
||||
base_filters.OrderByFilterMixin)
|
||||
filter_fields = ["project",
|
||||
"project__slug",
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pytest
|
||||
import pytz
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from urllib.parse import quote
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
|
@ -82,3 +86,97 @@ def test_list_milestones_taiga_info_headers(client):
|
|||
assert response2.has_header("Taiga-Info-Total-Opened-Milestones") == True
|
||||
assert response2["taiga-info-total-closed-milestones"] == "3"
|
||||
assert response2["taiga-info-total-opened-milestones"] == "1"
|
||||
|
||||
|
||||
def test_api_filter_by_created_date__lte(client):
|
||||
user = f.UserFactory.create()
|
||||
project = f.ProjectFactory.create(owner=user)
|
||||
role = f.RoleFactory.create(project=project)
|
||||
f.MembershipFactory.create(
|
||||
project=project, user=user, role=role, is_admin=True
|
||||
)
|
||||
one_day_ago = datetime.now(pytz.utc) - timedelta(days=1)
|
||||
|
||||
old_milestone = f.MilestoneFactory.create(
|
||||
project=project, owner=user, created_date=one_day_ago
|
||||
)
|
||||
milestone = f.MilestoneFactory.create(project=project, owner=user)
|
||||
|
||||
url = reverse("milestones-list") + "?created_date__lte=%s" % (
|
||||
quote(milestone.created_date.isoformat())
|
||||
)
|
||||
|
||||
client.login(milestone.owner)
|
||||
response = client.get(url)
|
||||
number_of_milestones = len(response.data)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert number_of_milestones == 2
|
||||
|
||||
|
||||
def test_api_filter_by_modified_date__gte(client):
|
||||
user = f.UserFactory.create()
|
||||
project = f.ProjectFactory.create(owner=user)
|
||||
role = f.RoleFactory.create(project=project)
|
||||
f.MembershipFactory.create(
|
||||
project=project, user=user, role=role, is_admin=True
|
||||
)
|
||||
one_day_ago = datetime.now(pytz.utc) - timedelta(days=1)
|
||||
|
||||
older_milestone = f.MilestoneFactory.create(
|
||||
project=project, owner=user, created_date=one_day_ago
|
||||
)
|
||||
milestone = f.MilestoneFactory.create(project=project, owner=user)
|
||||
# we have to refresh as it slightly differs
|
||||
milestone.refresh_from_db()
|
||||
|
||||
assert older_milestone.modified_date < milestone.modified_date
|
||||
|
||||
url = reverse("milestones-list") + "?modified_date__gte=%s" % (
|
||||
quote(milestone.modified_date.isoformat())
|
||||
)
|
||||
|
||||
client.login(milestone.owner)
|
||||
response = client.get(url)
|
||||
number_of_milestones = len(response.data)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert number_of_milestones == 1
|
||||
assert response.data[0]["slug"] == milestone.slug
|
||||
|
||||
|
||||
@pytest.mark.parametrize("field_name", [
|
||||
"estimated_start", "estimated_finish"
|
||||
])
|
||||
def test_api_filter_by_milestone__estimated_start_and_end(client, field_name):
|
||||
user = f.UserFactory.create()
|
||||
project = f.ProjectFactory.create(owner=user)
|
||||
role = f.RoleFactory.create(project=project)
|
||||
f.MembershipFactory.create(
|
||||
project=project, user=user, role=role, is_admin=True
|
||||
)
|
||||
milestone = f.MilestoneFactory.create(project=project, owner=user)
|
||||
|
||||
assert hasattr(milestone, field_name)
|
||||
date = getattr(milestone, field_name)
|
||||
before = (date - timedelta(days=1)).isoformat()
|
||||
after = (date + timedelta(days=1)).isoformat()
|
||||
|
||||
client.login(milestone.owner)
|
||||
|
||||
expections = {
|
||||
field_name + "__gte=" + quote(before): 1,
|
||||
field_name + "__gte=" + quote(after): 0,
|
||||
field_name + "__lte=" + quote(before): 0,
|
||||
field_name + "__lte=" + quote(after): 1
|
||||
}
|
||||
|
||||
for param, expection in expections.items():
|
||||
url = reverse("milestones-list") + "?" + param
|
||||
response = client.get(url)
|
||||
number_of_milestones = len(response.data)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert number_of_milestones == expection, param
|
||||
if number_of_milestones > 0:
|
||||
assert response.data[0]["slug"] == milestone.slug
|
||||
|
|
|
@ -702,6 +702,38 @@ def test_api_filter_by_finished_date(client):
|
|||
assert response.data[0]["subject"] == finished_task.subject
|
||||
|
||||
|
||||
@pytest.mark.parametrize("field_name", ["estimated_start", "estimated_finish"])
|
||||
def test_api_filter_by_milestone__estimated_start_and_end(client, field_name):
|
||||
user = f.UserFactory(is_superuser=True)
|
||||
task = f.create_task(owner=user)
|
||||
|
||||
assert task.milestone
|
||||
assert hasattr(task.milestone, field_name)
|
||||
date = getattr(task.milestone, field_name)
|
||||
before = (date - timedelta(days=1)).isoformat()
|
||||
after = (date + timedelta(days=1)).isoformat()
|
||||
|
||||
client.login(task.owner)
|
||||
|
||||
full_field_name = "milestone__" + field_name
|
||||
expections = {
|
||||
full_field_name + "__gte=" + quote(before): 1,
|
||||
full_field_name + "__gte=" + quote(after): 0,
|
||||
full_field_name + "__lte=" + quote(before): 0,
|
||||
full_field_name + "__lte=" + quote(after): 1
|
||||
}
|
||||
|
||||
for param, expection in expections.items():
|
||||
url = reverse("tasks-list") + "?" + param
|
||||
response = client.get(url)
|
||||
number_of_tasks = len(response.data)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert number_of_tasks == expection, param
|
||||
if number_of_tasks > 0:
|
||||
assert response.data[0]["subject"] == task.subject
|
||||
|
||||
|
||||
def test_api_filters_data(client):
|
||||
project = f.ProjectFactory.create()
|
||||
user1 = f.UserFactory.create(is_superuser=True)
|
||||
|
|
|
@ -655,6 +655,37 @@ def test_api_filter_by_finish_date(client):
|
|||
assert number_of_userstories == 1
|
||||
assert response.data[0]["subject"] == userstory_to_finish.subject
|
||||
|
||||
@pytest.mark.parametrize("field_name", ["estimated_start", "estimated_finish"])
|
||||
def test_api_filter_by_milestone__estimated_start_and_end(client, field_name):
|
||||
user = f.UserFactory(is_superuser=True)
|
||||
userstory = f.create_userstory(owner=user)
|
||||
|
||||
assert userstory.milestone
|
||||
assert hasattr(userstory.milestone, field_name)
|
||||
date = getattr(userstory.milestone, field_name)
|
||||
before = (date - timedelta(days=1)).isoformat()
|
||||
after = (date + timedelta(days=1)).isoformat()
|
||||
|
||||
client.login(userstory.owner)
|
||||
|
||||
full_field_name = "milestone__" + field_name
|
||||
expections = {
|
||||
full_field_name + "__gte=" + quote(before): 1,
|
||||
full_field_name + "__gte=" + quote(after): 0,
|
||||
full_field_name + "__lte=" + quote(before): 0,
|
||||
full_field_name + "__lte=" + quote(after): 1
|
||||
}
|
||||
|
||||
for param, expection in expections.items():
|
||||
url = reverse("userstories-list") + "?" + param
|
||||
response = client.get(url)
|
||||
number_of_userstories = len(response.data)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert number_of_userstories == expection, param
|
||||
if number_of_userstories > 0:
|
||||
assert response.data[0]["subject"] == userstory.subject
|
||||
|
||||
|
||||
def test_api_filters_data(client):
|
||||
project = f.ProjectFactory.create()
|
||||
|
|
Loading…
Reference in New Issue