Adds created-, modified-, finished- and finish_date to base filters
Extends issues api filters with created_date, modified_date and finished_dateremotes/origin/issue/4795/notification_even_they_are_disabled
parent
2df813aeb9
commit
b7d8dbc1a7
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from dateutil.parser import parse as parse_date
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
@ -447,6 +449,68 @@ class WatchersFilter(FilterBackend):
|
||||||
return super().filter_queryset(request, queryset, view)
|
return super().filter_queryset(request, queryset, view)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseCompareFilter(FilterBackend):
|
||||||
|
operators = ["", "lt", "gt", "lte", "gte"]
|
||||||
|
|
||||||
|
def __init__(self, filter_name_base=None, operators=None):
|
||||||
|
if filter_name_base:
|
||||||
|
self.filter_name_base = filter_name_base
|
||||||
|
|
||||||
|
def _get_filter_names(self):
|
||||||
|
return [
|
||||||
|
self._get_filter_name(operator)
|
||||||
|
for operator in self.operators
|
||||||
|
]
|
||||||
|
|
||||||
|
def _get_filter_name(self, operator):
|
||||||
|
if operator and len(operator) > 0:
|
||||||
|
return "{base}__{operator}".format(
|
||||||
|
base=self.filter_name_base, operator=operator
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return self.filter_name_base
|
||||||
|
|
||||||
|
def _get_constraints(self, params):
|
||||||
|
constraints = {}
|
||||||
|
for filter_name in self._get_filter_names():
|
||||||
|
raw_value = params.get(filter_name, None)
|
||||||
|
if raw_value is not None:
|
||||||
|
constraints[filter_name] = self._get_value(raw_value)
|
||||||
|
return constraints
|
||||||
|
|
||||||
|
def _get_value(self, raw_value):
|
||||||
|
return raw_value
|
||||||
|
|
||||||
|
def filter_queryset(self, request, queryset, view):
|
||||||
|
constraints = self._get_constraints(request.QUERY_PARAMS)
|
||||||
|
|
||||||
|
if len(constraints) > 0:
|
||||||
|
queryset = queryset.filter(**constraints)
|
||||||
|
|
||||||
|
return super().filter_queryset(request, queryset, view)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseDateFilter(BaseCompareFilter):
|
||||||
|
def _get_value(self, raw_value):
|
||||||
|
return parse_date(raw_value)
|
||||||
|
|
||||||
|
|
||||||
|
class CreatedDateFilter(BaseDateFilter):
|
||||||
|
filter_name_base = "created_date"
|
||||||
|
|
||||||
|
|
||||||
|
class ModifiedDateFilter(BaseDateFilter):
|
||||||
|
filter_name_base = "modified_date"
|
||||||
|
|
||||||
|
|
||||||
|
class FinishedDateFilter(BaseDateFilter):
|
||||||
|
filter_name_base = "finished_date"
|
||||||
|
|
||||||
|
|
||||||
|
class FinishDateFilter(BaseDateFilter):
|
||||||
|
filter_name_base = "finish_date"
|
||||||
|
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# Text search filters
|
# Text search filters
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
|
@ -58,7 +58,10 @@ class IssueViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, W
|
||||||
filters.TagsFilter,
|
filters.TagsFilter,
|
||||||
filters.WatchersFilter,
|
filters.WatchersFilter,
|
||||||
filters.QFilter,
|
filters.QFilter,
|
||||||
filters.OrderByFilterMixin)
|
filters.OrderByFilterMixin,
|
||||||
|
filters.CreatedDateFilter,
|
||||||
|
filters.ModifiedDateFilter,
|
||||||
|
filters.FinishedDateFilter)
|
||||||
retrieve_exclude_filters = (filters.OwnersFilter,
|
retrieve_exclude_filters = (filters.OwnersFilter,
|
||||||
filters.AssignedToFilter,
|
filters.AssignedToFilter,
|
||||||
filters.StatusesFilter,
|
filters.StatusesFilter,
|
||||||
|
|
|
@ -19,6 +19,10 @@
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
import csv
|
import csv
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from urllib.parse import quote
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
@ -221,6 +225,103 @@ def test_api_filter_by_text_6(client):
|
||||||
assert number_of_issues == 1
|
assert number_of_issues == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_filter_by_created_date(client):
|
||||||
|
user = f.UserFactory(is_superuser=True)
|
||||||
|
one_day_ago = datetime.now(pytz.utc) - timedelta(days=1)
|
||||||
|
|
||||||
|
old_issue = f.create_issue(owner=user, created_date=one_day_ago)
|
||||||
|
issue = f.create_issue(owner=user)
|
||||||
|
|
||||||
|
url = reverse("issues-list") + "?created_date=%s" % (
|
||||||
|
quote(issue.created_date.isoformat())
|
||||||
|
)
|
||||||
|
|
||||||
|
client.login(issue.owner)
|
||||||
|
response = client.get(url)
|
||||||
|
number_of_issues = len(response.data)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert number_of_issues == 1
|
||||||
|
assert response.data[0]["ref"] == issue.ref
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_filter_by_created_date__gt(client):
|
||||||
|
user = f.UserFactory(is_superuser=True)
|
||||||
|
one_day_ago = datetime.now(pytz.utc) - timedelta(days=1)
|
||||||
|
|
||||||
|
old_issue = f.create_issue(owner=user, created_date=one_day_ago)
|
||||||
|
issue = f.create_issue(owner=user)
|
||||||
|
|
||||||
|
url = reverse("issues-list") + "?created_date__gt=%s" % (
|
||||||
|
quote(one_day_ago.isoformat())
|
||||||
|
)
|
||||||
|
|
||||||
|
client.login(issue.owner)
|
||||||
|
response = client.get(url)
|
||||||
|
number_of_issues = len(response.data)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert number_of_issues == 1
|
||||||
|
assert response.data[0]["ref"] == issue.ref
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_filter_by_created_date__gte(client):
|
||||||
|
user = f.UserFactory(is_superuser=True)
|
||||||
|
one_day_ago = datetime.now(pytz.utc) - timedelta(days=1)
|
||||||
|
|
||||||
|
old_issue = f.create_issue(owner=user, created_date=one_day_ago)
|
||||||
|
issue = f.create_issue(owner=user)
|
||||||
|
|
||||||
|
url = reverse("issues-list") + "?created_date__gte=%s" % (
|
||||||
|
quote(one_day_ago.isoformat())
|
||||||
|
)
|
||||||
|
|
||||||
|
client.login(issue.owner)
|
||||||
|
response = client.get(url)
|
||||||
|
number_of_issues = len(response.data)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert number_of_issues == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_filter_by_created_date__lt(client):
|
||||||
|
user = f.UserFactory(is_superuser=True)
|
||||||
|
one_day_ago = datetime.now(pytz.utc) - timedelta(days=1)
|
||||||
|
|
||||||
|
old_issue = f.create_issue(owner=user, created_date=one_day_ago)
|
||||||
|
issue = f.create_issue(owner=user)
|
||||||
|
|
||||||
|
url = reverse("issues-list") + "?created_date__lt=%s" % (
|
||||||
|
quote(issue.created_date.isoformat())
|
||||||
|
)
|
||||||
|
|
||||||
|
client.login(issue.owner)
|
||||||
|
response = client.get(url)
|
||||||
|
number_of_issues = len(response.data)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data[0]["ref"] == old_issue.ref
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_filter_by_created_date__lte(client):
|
||||||
|
user = f.UserFactory(is_superuser=True)
|
||||||
|
one_day_ago = datetime.now(pytz.utc) - timedelta(days=1)
|
||||||
|
|
||||||
|
old_issue = f.create_issue(owner=user, created_date=one_day_ago)
|
||||||
|
issue = f.create_issue(owner=user)
|
||||||
|
|
||||||
|
url = reverse("issues-list") + "?created_date__lte=%s" % (
|
||||||
|
quote(issue.created_date.isoformat())
|
||||||
|
)
|
||||||
|
|
||||||
|
client.login(issue.owner)
|
||||||
|
response = client.get(url)
|
||||||
|
number_of_issues = len(response.data)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert number_of_issues == 2
|
||||||
|
|
||||||
|
|
||||||
def test_api_filters_data(client):
|
def test_api_filters_data(client):
|
||||||
project = f.ProjectFactory.create()
|
project = f.ProjectFactory.create()
|
||||||
user1 = f.UserFactory.create(is_superuser=True)
|
user1 = f.UserFactory.create(is_superuser=True)
|
||||||
|
|
Loading…
Reference in New Issue