Refactor searches module
parent
ab9043a7d7
commit
d6546dc518
|
@ -167,7 +167,6 @@ INSTALLED_APPS = [
|
||||||
"django.contrib.staticfiles",
|
"django.contrib.staticfiles",
|
||||||
|
|
||||||
"taiga.base",
|
"taiga.base",
|
||||||
"taiga.base.searches",
|
|
||||||
"taiga.events",
|
"taiga.events",
|
||||||
"taiga.front",
|
"taiga.front",
|
||||||
"taiga.users",
|
"taiga.users",
|
||||||
|
@ -183,6 +182,7 @@ INSTALLED_APPS = [
|
||||||
"taiga.projects.history",
|
"taiga.projects.history",
|
||||||
"taiga.projects.notifications",
|
"taiga.projects.notifications",
|
||||||
"taiga.projects.votes",
|
"taiga.projects.votes",
|
||||||
|
"taiga.searches",
|
||||||
"taiga.timeline",
|
"taiga.timeline",
|
||||||
"taiga.mdrender",
|
"taiga.mdrender",
|
||||||
|
|
||||||
|
@ -294,9 +294,11 @@ REST_FRAMEWORK = {
|
||||||
DEFAULT_PROJECT_TEMPLATE = "scrum"
|
DEFAULT_PROJECT_TEMPLATE = "scrum"
|
||||||
PUBLIC_REGISTER_ENABLED = False
|
PUBLIC_REGISTER_ENABLED = False
|
||||||
|
|
||||||
|
SEARCHES_MAX_RESULTS = 150
|
||||||
|
|
||||||
# NOTE: DON'T INSERT MORE SETTINGS AFTER THIS LINE
|
# NOTE: DON'T INSERT MORE SETTINGS AFTER THIS LINE
|
||||||
|
|
||||||
TEST_RUNNER="django.test.runner.DiscoverRunner"
|
#TEST_RUNNER="django.test.runner.DiscoverRunner"
|
||||||
|
|
||||||
# Test conditions
|
# Test conditions
|
||||||
if "test" in sys.argv:
|
if "test" in sys.argv:
|
||||||
|
|
|
@ -1,118 +0,0 @@
|
||||||
# Copyright (C) 2014 Andrey Antukh <niwi@niwi.be>
|
|
||||||
# Copyright (C) 2014 Jesús Espino <jespinog@gmail.com>
|
|
||||||
# Copyright (C) 2014 David Barragán <bameda@dbarragan.com>
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
from django.db.models.loading import get_model
|
|
||||||
|
|
||||||
from rest_framework.response import Response
|
|
||||||
from rest_framework import viewsets
|
|
||||||
|
|
||||||
from taiga.base import exceptions as excp
|
|
||||||
from taiga.projects.userstories.serializers import UserStorySerializer
|
|
||||||
from taiga.projects.tasks.serializers import TaskSerializer
|
|
||||||
from taiga.projects.issues.serializers import IssueSerializer
|
|
||||||
from taiga.projects.wiki.serializers import WikiPageSerializer
|
|
||||||
|
|
||||||
|
|
||||||
class SearchViewSet(viewsets.ViewSet):
|
|
||||||
def list(self, request, **kwargs):
|
|
||||||
project_model = get_model("projects", "Project")
|
|
||||||
text = request.QUERY_PARAMS.get('text', "")
|
|
||||||
get_all = request.QUERY_PARAMS.get('get_all', False)
|
|
||||||
project_id = request.QUERY_PARAMS.get('project', None)
|
|
||||||
|
|
||||||
try:
|
|
||||||
project = self._get_project(project_id)
|
|
||||||
except (project_model.DoesNotExist, TypeError):
|
|
||||||
raise excp.PermissionDenied({"detail": "Wrong project id"})
|
|
||||||
|
|
||||||
result = {
|
|
||||||
"userstories": self._search_user_stories(project, text, get_all),
|
|
||||||
"tasks": self._search_tasks(project, text, get_all),
|
|
||||||
"issues": self._search_issues(project, text, get_all),
|
|
||||||
"wikipages": self._search_wiki_pages(project, text, get_all)
|
|
||||||
}
|
|
||||||
|
|
||||||
result["count"] = sum(map(lambda x: len(x), result.values()))
|
|
||||||
return Response(result)
|
|
||||||
|
|
||||||
def _get_project(self, project_id):
|
|
||||||
project_model = get_model("projects", "Project")
|
|
||||||
own_projects = (project_model.objects
|
|
||||||
.filter(members=self.request.user))
|
|
||||||
|
|
||||||
return own_projects.get(pk=project_id)
|
|
||||||
|
|
||||||
def _search_user_stories(self, project, text, get_all):
|
|
||||||
where_clause = ("to_tsvector(userstories_userstory.subject || "
|
|
||||||
"userstories_userstory.description) @@ plainto_tsquery(%s)")
|
|
||||||
|
|
||||||
model_cls = get_model("userstories", "UserStory")
|
|
||||||
if get_all != "false" and text == '':
|
|
||||||
queryset = model_cls.objects.filter(project_id=project.pk)
|
|
||||||
else:
|
|
||||||
queryset = (model_cls.objects
|
|
||||||
.extra(where=[where_clause], params=[text])
|
|
||||||
.filter(project_id=project.pk)[:50])
|
|
||||||
|
|
||||||
serializer = UserStorySerializer(queryset, many=True)
|
|
||||||
return serializer.data
|
|
||||||
|
|
||||||
def _search_tasks(self, project, text, get_all):
|
|
||||||
where_clause = ("to_tsvector(tasks_task.subject || tasks_task.description) "
|
|
||||||
"@@ plainto_tsquery(%s)")
|
|
||||||
|
|
||||||
model_cls = get_model("tasks", "Task")
|
|
||||||
if get_all != "false" and text == '':
|
|
||||||
queryset = model_cls.objects.filter(project_id=project.pk)
|
|
||||||
else:
|
|
||||||
queryset = (model_cls.objects
|
|
||||||
.extra(where=[where_clause], params=[text])
|
|
||||||
.filter(project_id=project.pk)[:50])
|
|
||||||
|
|
||||||
serializer = TaskSerializer(queryset, many=True)
|
|
||||||
return serializer.data
|
|
||||||
|
|
||||||
def _search_issues(self, project, text, get_all):
|
|
||||||
where_clause = ("to_tsvector(issues_issue.subject || issues_issue.description) "
|
|
||||||
"@@ plainto_tsquery(%s)")
|
|
||||||
|
|
||||||
model_cls = get_model("issues", "Issue")
|
|
||||||
if get_all != "false" and text == '':
|
|
||||||
queryset = model_cls.objects.filter(project_id=project.pk)
|
|
||||||
else:
|
|
||||||
queryset = (model_cls.objects
|
|
||||||
.extra(where=[where_clause], params=[text])
|
|
||||||
.filter(project_id=project.pk)[:50])
|
|
||||||
|
|
||||||
serializer = IssueSerializer(queryset, many=True)
|
|
||||||
return serializer.data
|
|
||||||
|
|
||||||
def _search_wiki_pages(self, project, text, get_all):
|
|
||||||
where_clause = ("to_tsvector(wiki_wikipage.slug || wiki_wikipage.content) "
|
|
||||||
"@@ plainto_tsquery(%s)")
|
|
||||||
|
|
||||||
model_cls = get_model("wiki", "WikiPage")
|
|
||||||
if get_all != "false" and text == '':
|
|
||||||
queryset = model_cls.objects.filter(project_id=project.pk)
|
|
||||||
else:
|
|
||||||
queryset = (model_cls.objects
|
|
||||||
.extra(where=[where_clause], params=[text])
|
|
||||||
.filter(project_id=project.pk)[:50])
|
|
||||||
|
|
||||||
serializer = WikiPageSerializer(queryset, many=True)
|
|
||||||
return serializer.data
|
|
||||||
|
|
||||||
|
|
|
@ -32,11 +32,15 @@ from taiga.userstorage.api import StorageEntriesViewSet
|
||||||
router.register(r"user-storage", StorageEntriesViewSet, base_name="user-storage")
|
router.register(r"user-storage", StorageEntriesViewSet, base_name="user-storage")
|
||||||
|
|
||||||
|
|
||||||
# Resolver & Search
|
# Resolver
|
||||||
from taiga.base.searches.api import SearchViewSet
|
|
||||||
from taiga.projects.references.api import ResolverViewSet
|
from taiga.projects.references.api import ResolverViewSet
|
||||||
|
|
||||||
router.register(r"resolver", ResolverViewSet, base_name="resolver")
|
router.register(r"resolver", ResolverViewSet, base_name="resolver")
|
||||||
|
|
||||||
|
|
||||||
|
# Search
|
||||||
|
from taiga.searches.api import SearchViewSet
|
||||||
|
|
||||||
router.register(r"search", SearchViewSet, base_name="search")
|
router.register(r"search", SearchViewSet, base_name="search")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
# Copyright (C) 2014 Andrey Antukh <niwi@niwi.be>
|
||||||
|
# Copyright (C) 2014 Jesús Espino <jespinog@gmail.com>
|
||||||
|
# Copyright (C) 2014 David Barragán <bameda@dbarragan.com>
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from django.db.models.loading import get_model
|
||||||
|
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework import viewsets
|
||||||
|
|
||||||
|
from taiga.base import exceptions as excp
|
||||||
|
from taiga.projects.userstories.serializers import UserStorySerializer
|
||||||
|
from taiga.projects.tasks.serializers import TaskSerializer
|
||||||
|
from taiga.projects.issues.serializers import IssueSerializer
|
||||||
|
from taiga.projects.wiki.serializers import WikiPageSerializer
|
||||||
|
|
||||||
|
from . import services
|
||||||
|
|
||||||
|
|
||||||
|
class SearchViewSet(viewsets.ViewSet):
|
||||||
|
def list(self, request, **kwargs):
|
||||||
|
project_model = get_model("projects", "Project")
|
||||||
|
|
||||||
|
text = request.QUERY_PARAMS.get('text', "")
|
||||||
|
project_id = request.QUERY_PARAMS.get('project', None)
|
||||||
|
|
||||||
|
try:
|
||||||
|
project = self._get_project(project_id)
|
||||||
|
except (project_model.DoesNotExist, TypeError):
|
||||||
|
raise excp.PermissionDenied({"detail": "Wrong project id"})
|
||||||
|
|
||||||
|
result = {
|
||||||
|
"userstories": self._search_user_stories(project, text),
|
||||||
|
"tasks": self._search_tasks(project, text),
|
||||||
|
"issues": self._search_issues(project, text),
|
||||||
|
"wikipages": self._search_wiki_pages(project, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
result["count"] = sum(map(lambda x: len(x), result.values()))
|
||||||
|
return Response(result)
|
||||||
|
|
||||||
|
def _get_project(self, project_id):
|
||||||
|
project_model = get_model("projects", "Project")
|
||||||
|
own_projects = (project_model.objects
|
||||||
|
.filter(members=self.request.user))
|
||||||
|
|
||||||
|
return own_projects.get(pk=project_id)
|
||||||
|
|
||||||
|
def _search_user_stories(self, project, text):
|
||||||
|
queryset = services.search_user_stories(project, text)
|
||||||
|
serializer = UserStorySerializer(queryset, many=True)
|
||||||
|
return serializer.data
|
||||||
|
|
||||||
|
def _search_tasks(self, project, text):
|
||||||
|
queryset = services.search_tasks(project, text)
|
||||||
|
serializer = TaskSerializer(queryset, many=True)
|
||||||
|
return serializer.data
|
||||||
|
|
||||||
|
def _search_issues(self, project, text):
|
||||||
|
queryset = services.search_issues(project, text)
|
||||||
|
serializer = IssueSerializer(queryset, many=True)
|
||||||
|
return serializer.data
|
||||||
|
|
||||||
|
def _search_wiki_pages(self, project, text):
|
||||||
|
queryset = services.search_wiki_pages(project, text)
|
||||||
|
serializer = WikiPageSerializer(queryset, many=True)
|
||||||
|
return serializer.data
|
|
@ -0,0 +1,69 @@
|
||||||
|
# Copyright (C) 2014 Andrey Antukh <niwi@niwi.be>
|
||||||
|
# Copyright (C) 2014 Jesús Espino <jespinog@gmail.com>
|
||||||
|
# Copyright (C) 2014 David Barragán <bameda@dbarragan.com>
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from django.db.models.loading import get_model
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
|
MAX_RESULTS = getattr(settings, "SEARCHES_MAX_RESULTS", 150)
|
||||||
|
|
||||||
|
|
||||||
|
def search_user_stories(project, text):
|
||||||
|
model_cls = get_model("userstories", "UserStory")
|
||||||
|
where_clause = ("to_tsvector(coalesce(userstories_userstory.subject) || ' ' || "
|
||||||
|
"coalesce(userstories_userstory.description)) @@ plainto_tsquery(%s)")
|
||||||
|
|
||||||
|
if text:
|
||||||
|
return (model_cls.objects.extra(where=[where_clause], params=[text])
|
||||||
|
.filter(project_id=project.pk)[:MAX_RESULTS])
|
||||||
|
|
||||||
|
return model_cls.objects.filter(project_id=project.pk)[:MAX_RESULTS]
|
||||||
|
|
||||||
|
|
||||||
|
def search_tasks(project, text):
|
||||||
|
model_cls = get_model("tasks", "Task")
|
||||||
|
where_clause = ("to_tsvector(coalesce(tasks_task.subject, '') || ' ' || coalesce(tasks_task.description, '')) "
|
||||||
|
"@@ plainto_tsquery(%s)")
|
||||||
|
|
||||||
|
if text:
|
||||||
|
return (model_cls.objects.extra(where=[where_clause], params=[text])
|
||||||
|
.filter(project_id=project.pk)[:MAX_RESULTS])
|
||||||
|
|
||||||
|
return model_cls.objects.filter(project_id=project.pk)[:MAX_RESULTS]
|
||||||
|
|
||||||
|
|
||||||
|
def search_issues(project, text):
|
||||||
|
model_cls = get_model("issues", "Issue")
|
||||||
|
where_clause = ("to_tsvector(coalesce(issues_issue.subject) || ' ' || coalesce(issues_issue.description)) "
|
||||||
|
"@@ plainto_tsquery(%s)")
|
||||||
|
|
||||||
|
if text:
|
||||||
|
return (model_cls.objects.extra(where=[where_clause], params=[text])
|
||||||
|
.filter(project_id=project.pk)[:MAX_RESULTS])
|
||||||
|
|
||||||
|
return model_cls.objects.filter(project_id=project.pk)[:MAX_RESULTS]
|
||||||
|
|
||||||
|
|
||||||
|
def search_wiki_pages(project, text):
|
||||||
|
model_cls = get_model("wiki", "WikiPage")
|
||||||
|
where_clause = ("to_tsvector(coalesce(wiki_wikipage.slug) || ' ' || coalesce(wiki_wikipage.content)) "
|
||||||
|
"@@ plainto_tsquery(%s)")
|
||||||
|
|
||||||
|
if text:
|
||||||
|
return (model_cls.objects.extra(where=[where_clause], params=[text])
|
||||||
|
.filter(project_id=project.pk)[:MAX_RESULTS])
|
||||||
|
|
||||||
|
return model_cls.objects.filter(project_id=project.pk)[:MAX_RESULTS]
|
|
@ -110,6 +110,7 @@ class UserStoryFactory(Factory):
|
||||||
project = factory.SubFactory("tests.factories.ProjectFactory")
|
project = factory.SubFactory("tests.factories.ProjectFactory")
|
||||||
owner = factory.SubFactory("tests.factories.UserFactory")
|
owner = factory.SubFactory("tests.factories.UserFactory")
|
||||||
subject = factory.Sequence(lambda n: "User Story {}".format(n))
|
subject = factory.Sequence(lambda n: "User Story {}".format(n))
|
||||||
|
description = factory.Sequence(lambda n: "User Story {} description".format(n))
|
||||||
|
|
||||||
|
|
||||||
class MilestoneFactory(Factory):
|
class MilestoneFactory(Factory):
|
||||||
|
@ -124,6 +125,7 @@ class IssueFactory(Factory):
|
||||||
FACTORY_FOR = get_model("issues", "Issue")
|
FACTORY_FOR = get_model("issues", "Issue")
|
||||||
|
|
||||||
subject = factory.Sequence(lambda n: "Issue {}".format(n))
|
subject = factory.Sequence(lambda n: "Issue {}".format(n))
|
||||||
|
description = factory.Sequence(lambda n: "Issue {} description".format(n))
|
||||||
owner = factory.SubFactory("tests.factories.UserFactory")
|
owner = factory.SubFactory("tests.factories.UserFactory")
|
||||||
project = factory.SubFactory("tests.factories.ProjectFactory")
|
project = factory.SubFactory("tests.factories.ProjectFactory")
|
||||||
status = factory.SubFactory("tests.factories.IssueStatusFactory")
|
status = factory.SubFactory("tests.factories.IssueStatusFactory")
|
||||||
|
@ -137,6 +139,7 @@ class TaskFactory(Factory):
|
||||||
FACTORY_FOR = get_model("tasks", "Task")
|
FACTORY_FOR = get_model("tasks", "Task")
|
||||||
|
|
||||||
subject = factory.Sequence(lambda n: "Task {}".format(n))
|
subject = factory.Sequence(lambda n: "Task {}".format(n))
|
||||||
|
description = factory.Sequence(lambda n: "Task {} description".format(n))
|
||||||
owner = factory.SubFactory("tests.factories.UserFactory")
|
owner = factory.SubFactory("tests.factories.UserFactory")
|
||||||
project = factory.SubFactory("tests.factories.ProjectFactory")
|
project = factory.SubFactory("tests.factories.ProjectFactory")
|
||||||
status = factory.SubFactory("tests.factories.TaskStatusFactory")
|
status = factory.SubFactory("tests.factories.TaskStatusFactory")
|
||||||
|
@ -148,6 +151,8 @@ class WikiPageFactory(Factory):
|
||||||
|
|
||||||
project = factory.SubFactory("tests.factories.ProjectFactory")
|
project = factory.SubFactory("tests.factories.ProjectFactory")
|
||||||
owner = factory.SubFactory("tests.factories.UserFactory")
|
owner = factory.SubFactory("tests.factories.UserFactory")
|
||||||
|
slug = factory.Sequence(lambda n: "wiki-page-{}".format(n))
|
||||||
|
content = factory.Sequence(lambda n: "Wiki Page {} content".format(n))
|
||||||
|
|
||||||
|
|
||||||
class IssueStatusFactory(Factory):
|
class IssueStatusFactory(Factory):
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
|
from .. import factories as f
|
||||||
|
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def searches_initial_data():
|
||||||
|
m = type("InitialData", (object,), {})()
|
||||||
|
|
||||||
|
m.project1 = f.ProjectFactory.create()
|
||||||
|
m.project2 = f.ProjectFactory.create()
|
||||||
|
|
||||||
|
m.member1 = f.MembershipFactory.create(project=m.project1)
|
||||||
|
m.member2 = f.MembershipFactory.create(project=m.project1)
|
||||||
|
|
||||||
|
m.us1 = f.UserStoryFactory.create(project=m.project1)
|
||||||
|
m.us2 = f.UserStoryFactory.create(project=m.project1, description="Back to the future")
|
||||||
|
m.us3 = f.UserStoryFactory.create(project=m.project2)
|
||||||
|
|
||||||
|
m.tsk1 = f.TaskFactory.create(project=m.project2)
|
||||||
|
m.tsk2 = f.TaskFactory.create(project=m.project1)
|
||||||
|
m.tsk3 = f.TaskFactory.create(project=m.project1, subject="Back to the future")
|
||||||
|
|
||||||
|
m.iss1 = f.IssueFactory.create(project=m.project1, subject="Backend and Frontend")
|
||||||
|
m.iss2 = f.IssueFactory.create(project=m.project2)
|
||||||
|
m.iss3 = f.IssueFactory.create(project=m.project1)
|
||||||
|
|
||||||
|
m.wiki1 = f.WikiPageFactory.create(project=m.project1)
|
||||||
|
m.wiki2 = f.WikiPageFactory.create(project=m.project1, content="Frontend, future")
|
||||||
|
m.wiki3 = f.WikiPageFactory.create(project=m.project2)
|
||||||
|
|
||||||
|
return m
|
||||||
|
|
||||||
|
|
||||||
|
def test_search_all_objects_in_my_project(client, searches_initial_data):
|
||||||
|
data = searches_initial_data
|
||||||
|
|
||||||
|
client.login(data.member1.user)
|
||||||
|
|
||||||
|
response = client.get(reverse("search-list"), {"project": data.project1.id})
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data["count"] == 8
|
||||||
|
assert len(response.data["userstories"]) == 2
|
||||||
|
assert len(response.data["tasks"]) == 2
|
||||||
|
assert len(response.data["issues"]) == 2
|
||||||
|
assert len(response.data["wikipages"]) == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_search_all_objects_in_project_is_not_mine(client, searches_initial_data):
|
||||||
|
data = searches_initial_data
|
||||||
|
|
||||||
|
client.login(data.member1.user)
|
||||||
|
|
||||||
|
response = client.get(reverse("search-list"), {"project": data.project2.id})
|
||||||
|
assert response.status_code == 403
|
||||||
|
|
||||||
|
|
||||||
|
def test_search_text_query_in_my_project(client, searches_initial_data):
|
||||||
|
data = searches_initial_data
|
||||||
|
|
||||||
|
client.login(data.member1.user)
|
||||||
|
|
||||||
|
response = client.get(reverse("search-list"), {"project": data.project1.id, "text": "future"})
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data["count"] == 3
|
||||||
|
assert len(response.data["userstories"]) == 1
|
||||||
|
assert len(response.data["tasks"]) == 1
|
||||||
|
assert len(response.data["issues"]) == 0
|
||||||
|
assert len(response.data["wikipages"]) == 1
|
||||||
|
|
||||||
|
response = client.get(reverse("search-list"), {"project": data.project1.id, "text": "back"})
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data["count"] == 2
|
||||||
|
assert len(response.data["userstories"]) == 1
|
||||||
|
assert len(response.data["tasks"]) == 1
|
||||||
|
assert len(response.data["issues"]) == 0
|
||||||
|
assert len(response.data["wikipages"]) == 0
|
Loading…
Reference in New Issue