Merge pull request #784 from taigaio/search-into-tags

Search into tags on searches and filters
remotes/origin/issue/4795/notification_even_they_are_disabled
David Barragán Merino 2016-07-08 13:32:14 +02:00 committed by GitHub
commit 750158a16b
4 changed files with 58 additions and 48 deletions

View File

@ -20,10 +20,7 @@ answer newbie questions, and generally made taiga that much better:
- Andrea Stagi <stagi.andrea@gmail.com> - Andrea Stagi <stagi.andrea@gmail.com>
- Andrés Moya <andres.moya@kaleidos.net> - Andrés Moya <andres.moya@kaleidos.net>
- Andrey Alekseenko <al42and@gmail.com> - Andrey Alekseenko <al42and@gmail.com>
<<<<<<< HEAD
=======
- Brett Profitt <brett.profitt@gmail.com> - Brett Profitt <brett.profitt@gmail.com>
>>>>>>> master
- Bruno Clermont <bruno@robotinfra.com> - Bruno Clermont <bruno@robotinfra.com>
- Chris Wilson <chris.wilson@aridhia.com> - Chris Wilson <chris.wilson@aridhia.com>
- David Burke <david@burkesoftware.com> - David Burke <david@burkesoftware.com>
@ -33,6 +30,7 @@ answer newbie questions, and generally made taiga that much better:
- Julien Palard - Julien Palard
- luyikei <luyikei.qmltu@gmail.com> - luyikei <luyikei.qmltu@gmail.com>
- Motius GmbH <mail@motius.de> - Motius GmbH <mail@motius.de>
- Riccardo Coccioli <riccardo.coccioli@immobiliare.it>
- Ricky Posner <e@eposner.com> - Ricky Posner <e@eposner.com>
- Yamila Moreno <yamila.moreno@kaleidos.net> - Yamila Moreno <yamila.moreno@kaleidos.net>
- Yaser Alraddadi <yaser@yr.sa> - Yaser Alraddadi <yaser@yr.sa>

View File

@ -8,6 +8,8 @@
- ProjectTemplates now are sorted by the attribute 'order'. - ProjectTemplates now are sorted by the attribute 'order'.
- Create enpty wiki pages (if not exist) when a new link is created. - Create enpty wiki pages (if not exist) when a new link is created.
- Diff messages in history entries now show only the relevant changes (with some context). - Diff messages in history entries now show only the relevant changes (with some context).
- Include created, modified and finished dates for tasks in CSV reports
- User stories and tasks listing API call support extra params to include more data (tasks and attachemnts and attachments, respectively)
- Comments: - Comments:
- Now comment owners and project admins can edit existing comments with the history Entry endpoint. - Now comment owners and project admins can edit existing comments with the history Entry endpoint.
- Add a new permissions to allow add comments instead of use the existent modify permission for this purpose. - Add a new permissions to allow add comments instead of use the existent modify permission for this purpose.
@ -15,10 +17,9 @@
- New API endpoints over projects to create, rename, edit, delete and mix tags. - New API endpoints over projects to create, rename, edit, delete and mix tags.
- Tag color assignation is not automatic. - Tag color assignation is not automatic.
- Select a color (or not) to a tag when add it to stories, issues and tasks. - Select a color (or not) to a tag when add it to stories, issues and tasks.
- Now comment owners and project admins can edit existing comments with the history Entry endpoint. - Improve search system over stories, tasks and issues:
- Add a new permissions to allow add comments instead of use the existent modify permission for this purpose. - Search into tags too. (thanks to [Riccardo Cocciol](https://github.com/volans-))
- Include created, modified and finished dates for tasks in CSV reports - Weights are applied: (subject = ref > tags > description).
- User stories and tasks listing API call support extra params to include more data (tasks and attachemnts and attachments, respectively)
- Import/Export: - Import/Export:
- Gzip export/import support. - Gzip export/import support.
- Export performance improvements. - Export performance improvements.
@ -32,7 +33,7 @@
## 2.1.0 Ursus Americanus (2016-05-03) ## 2.1.0 Ursus Americanus (2016-05-03)
### Features ### Features
- Add sprint name and slug on search results for user stories ((thanks to [@everblut](https://github.com/everblut))) - Add sprint name and slug on search results for user stories (thanks to [@everblut](https://github.com/everblut))
- [API] projects resource: Random order if `discover_mode=true` and `is_featured=true`. - [API] projects resource: Random order if `discover_mode=true` and `is_featured=true`.
- Webhooks: Improve webhook data: - Webhooks: Improve webhook data:
- add permalinks - add permalinks

View File

@ -459,6 +459,7 @@ class QFilter(FilterBackend):
where_clause = (""" where_clause = ("""
to_tsvector('english_nostop', to_tsvector('english_nostop',
coalesce({table}.subject, '') || ' ' || coalesce({table}.subject, '') || ' ' ||
coalesce(array_to_string({table}.tags, ' '), '') || ' ' ||
coalesce({table}.ref) || ' ' || coalesce({table}.ref) || ' ' ||
coalesce({table}.description, '')) @@ to_tsquery('english_nostop', %s) coalesce({table}.description, '')) @@ to_tsquery('english_nostop', %s)
""".format(table=table)) """.format(table=table))

View File

@ -25,55 +25,65 @@ MAX_RESULTS = getattr(settings, "SEARCHES_MAX_RESULTS", 150)
def search_user_stories(project, text): def search_user_stories(project, text):
model_cls = apps.get_model("userstories", "UserStory") model = apps.get_model("userstories", "UserStory")
where_clause = ("to_tsvector('english_nostop', coalesce(userstories_userstory.subject) || ' ' || " queryset = model.objects.filter(project_id=project.pk)
"coalesce(userstories_userstory.ref) || ' ' || " table = "userstories_userstory"
"coalesce(userstories_userstory.description, '')) " return _search_items(queryset, table, text)
"@@ to_tsquery('english_nostop', %s)")
queryset = model_cls.objects.filter(project_id=project.pk)
if text:
queryset = queryset.extra(where=[where_clause], params=[to_tsquery(text)])
queryset = attach_total_points(queryset)
return queryset[:MAX_RESULTS]
def search_tasks(project, text): def search_tasks(project, text):
model_cls = apps.get_model("tasks", "Task") model = apps.get_model("userstories", "UserStory")
where_clause = ("to_tsvector('english_nostop', coalesce(tasks_task.subject, '') || ' ' || " queryset = model.objects.filter(project_id=project.pk)
"coalesce(tasks_task.ref) || ' ' || " table = "userstories_userstory"
"coalesce(tasks_task.description, '')) @@ to_tsquery('english_nostop', %s)") return _search_items(queryset, table, text)
if text:
return (model_cls.objects.extra(where=[where_clause], params=[to_tsquery(text)])
.filter(project_id=project.pk)[:MAX_RESULTS])
return model_cls.objects.filter(project_id=project.pk)[:MAX_RESULTS]
def search_issues(project, text): def search_issues(project, text):
model_cls = apps.get_model("issues", "Issue") model = apps.get_model("userstories", "UserStory")
where_clause = ("to_tsvector('english_nostop', coalesce(issues_issue.subject) || ' ' || " queryset = model.objects.filter(project_id=project.pk)
"coalesce(issues_issue.ref) || ' ' || " table = "userstories_userstory"
"coalesce(issues_issue.description, '')) @@ to_tsquery('english_nostop', %s)") return _search_items(queryset, table, text)
if text:
return (model_cls.objects.extra(where=[where_clause], params=[to_tsquery(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): def search_wiki_pages(project, text):
model_cls = apps.get_model("wiki", "WikiPage") model = apps.get_model("wiki", "WikiPage")
where_clause = ("to_tsvector('english_nostop', coalesce(wiki_wikipage.slug) || ' ' || " queryset = model.objects.filter(project_id=project.pk)
"coalesce(wiki_wikipage.content, '')) " tsquery = "to_tsquery('english_nostop', %s)"
"@@ to_tsquery('english_nostop', %s)") tsvector = """
setweight(to_tsvector('english_nostop', coalesce(wiki_wikipage.slug)), 'A') ||
setweight(to_tsvector('english_nostop', coalesce(wiki_wikipage.content)), 'B')
"""
return _search_by_query(queryset, tsquery, tsvector, text)
def _search_items(queryset, table, text):
tsquery = "to_tsquery('english_nostop', %s)"
tsvector = """
setweight(to_tsvector('english_nostop',
coalesce({table}.subject) || ' ' ||
coalesce({table}.ref)), 'A') ||
setweight(to_tsvector('english_nostop', coalesce(inmutable_array_to_string({table}.tags))), 'B') ||
setweight(to_tsvector('english_nostop', coalesce({table}.description)), 'C')
""".format(table=table)
return _search_by_query(queryset, tsquery, tsvector, text)
def _search_by_query(queryset, tsquery, tsvector, text):
select = {
"rank": "ts_rank({tsvector},{tsquery})".format(tsquery=tsquery,
tsvector=tsvector),
}
order_by = ["-rank", ]
where = ["{tsvector} @@ {tsquery}".format(tsquery=tsquery,
tsvector=tsvector), ]
if text: if text:
return (model_cls.objects.extra(where=[where_clause], params=[to_tsquery(text)]) queryset = queryset.extra(select=select,
.filter(project_id=project.pk)[:MAX_RESULTS]) select_params=[to_tsquery(text)],
where=where,
params=[to_tsquery(text)],
order_by=order_by)
return model_cls.objects.filter(project_id=project.pk)[:MAX_RESULTS] queryset = attach_total_points(queryset)
return queryset[:MAX_RESULTS]