-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TA#66862 [16.0][MIG] project_task_full_text_search (#406)
* TA#66862 [16.0][MIG] project_task_full_text_search --------- Co-authored-by: Majda EL MARIOULI <[email protected]>
- Loading branch information
1 parent
8e1867e
commit 647b9a6
Showing
14 changed files
with
472 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
============================= | ||
Project Task Full Text Search | ||
============================= | ||
This module allows to search a task by its title and description. | ||
|
||
When searching a task, a full text search is ran in postgresql. | ||
|
||
The order of the searched words has no impact on the result. | ||
The returned tasks are tasks for which the title / description contain every given words | ||
(or similar words). | ||
|
||
Usage | ||
----- | ||
* Go to Projects / Tasks | ||
* In the search bar, type something and click on ``Search Full Text for: ...``. | ||
|
||
Accents and Upper Cases | ||
----------------------- | ||
The content of a task is indexed without accents and in lower cases. | ||
|
||
When searching using the full text search, accents are removed from the searched text | ||
and upper cases are replaced with lower cases. | ||
|
||
stemmings | ||
--------- | ||
The content search uses stemmings to find similar text. | ||
|
||
stemmings are rules applied by postgresql to match text in queries. | ||
These rules depend on the language of the text searched. | ||
|
||
Natively, postgresql supports the following languages: | ||
|
||
* danish | ||
* dutch | ||
* english | ||
* finnish | ||
* french | ||
* german | ||
* hungarian | ||
* italian | ||
* norwegian | ||
* portuguese | ||
* romanian | ||
* russian | ||
* spanish | ||
* swedish | ||
* turkish | ||
|
||
A list of available language can be found using the following SQL query: | ||
|
||
`SELECT * FROM pg_catalog.pg_ts_dict;` | ||
|
||
Configuration | ||
------------- | ||
By default, the text search language is set to english. | ||
|
||
In order to set the search language to a given value (french for example): | ||
|
||
* Go to: Settings / Technical / Parameters / System Parameters. | ||
* Create a new entry. | ||
* Set key to `postgresql_full_text_search_language`. | ||
* Set value to `french` (or your prefered language). | ||
* Save the new entry. | ||
|
||
That's it, your task are now indexed under the new language. | ||
|
||
Contributors | ||
------------ | ||
* Numigi (tm) and all its contributors (https://bit.ly/numigiens) | ||
|
||
More information | ||
---------------- | ||
* Meet us at https://bit.ly/numigi-com |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens) | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens) | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
{ | ||
"name": "Project Task Full Text Search", | ||
"version": "16.0.1.0.0", | ||
"author": "Numigi", | ||
"maintainer": "Numigi", | ||
"website": "https://bit.ly/numigi-com", | ||
"license": "LGPL-3", | ||
"category": "Project", | ||
"depends": ["project"], | ||
"external_dependencies": { | ||
"python": ["unidecode"], | ||
}, | ||
"data": [ | ||
"views/project_task.xml", | ||
], | ||
"installable": True, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Translation of Odoo Server. | ||
# This file contains the translation of the following modules: | ||
# * project_task_full_text_search | ||
# | ||
msgid "" | ||
msgstr "" | ||
"Project-Id-Version: Odoo Server 16.0\n" | ||
"Report-Msgid-Bugs-To: \n" | ||
"POT-Creation-Date: 2022-06-16 11:39-0400\n" | ||
"PO-Revision-Date: 2022-06-16 11:42-0400\n" | ||
"Last-Translator: <>\n" | ||
"Language-Team: \n" | ||
"Language: fr\n" | ||
"MIME-Version: 1.0\n" | ||
"Content-Type: text/plain; charset=UTF-8\n" | ||
"Content-Transfer-Encoding: 8bit\n" | ||
"Plural-Forms: \n" | ||
"X-Generator: Poedit 2.0.6\n" | ||
|
||
#. module: project_task_full_text_search | ||
#: model:ir.model.fields,field_description:project_task_full_text_search.field_project_task__full_text_search | ||
msgid "Full Text" | ||
msgstr "Plein texte" | ||
|
||
#. module: project_task_full_text_search | ||
#: model:ir.model.fields,field_description:project_task_full_text_search.field_project_task__full_text_content | ||
msgid "Indexed Content" | ||
msgstr "Contenu indexé" | ||
|
||
#. module: project_task_full_text_search | ||
#: model:ir.model,name:project_task_full_text_search.model_ir_config_parameter | ||
msgid "System Parameter" | ||
msgstr "" | ||
|
||
#. module: project_task_full_text_search | ||
#: model:ir.model,name:project_task_full_text_search.model_project_task | ||
msgid "Task" | ||
msgstr "Tâche" | ||
|
||
#. module: project_task_full_text_search | ||
#: code:addons/project_task_full_text_search/models/project_task.py:44 | ||
#, python-format | ||
msgid "" | ||
"The operator {operator} is not supported for full text search on tasks. You " | ||
"may use the equal operator instead." | ||
msgstr "" | ||
"L'opérateur {operator} n'est pas supporté pour la recherche plein texte sur " | ||
"les tâches. Vous pouvez toutefois utiliser l'opérateur d'égalité." |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens) | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
from . import ( | ||
ir_config_parameter, | ||
project_task, | ||
) |
34 changes: 34 additions & 0 deletions
34
project_task_full_text_search/models/ir_config_parameter.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens) | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
from odoo import api, models | ||
|
||
FULL_TEXT_SEARCH_PARAM_KEY = "postgresql_full_text_search_language" | ||
|
||
|
||
class IrConfigParameterWithFullTextSearchParamKey(models.Model): | ||
"""Automatically update the gin index on tasks when the full text search language is set.""" | ||
|
||
_inherit = "ir.config_parameter" | ||
|
||
@api.model | ||
def create(self, vals): | ||
param = super().create(vals) | ||
should_update_index = param.key == FULL_TEXT_SEARCH_PARAM_KEY | ||
if should_update_index: | ||
self.env["project.task"]._setup_content_index() | ||
return param | ||
|
||
def write(self, vals): | ||
super().write(vals) | ||
should_update_index = any(p.key == FULL_TEXT_SEARCH_PARAM_KEY for p in self) | ||
if should_update_index: | ||
self.env["project.task"]._setup_content_index() | ||
return True | ||
|
||
def unlink(self): | ||
should_update_index = any(p.key == FULL_TEXT_SEARCH_PARAM_KEY for p in self) | ||
super().unlink() | ||
if should_update_index: | ||
self.env["project.task"]._setup_content_index() | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens) | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
import logging | ||
|
||
from unidecode import unidecode | ||
|
||
from odoo import api, fields, models, _ | ||
from odoo.exceptions import ValidationError | ||
from .ir_config_parameter import FULL_TEXT_SEARCH_PARAM_KEY | ||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
FULL_TEXT_SEARCH_INDEX_NAME = "project_task_full_text_search_idx" | ||
|
||
|
||
class ProjectTaskWithFullTextSearch(models.Model): | ||
"""Add full test search to tasks.""" | ||
|
||
_inherit = "project.task" | ||
|
||
full_text_search = fields.Text( | ||
"Full Text", | ||
compute=lambda self: None, | ||
search="_search_full_text_content", | ||
) | ||
|
||
full_text_content = fields.Text( | ||
"Indexed Content", | ||
compute="_compute_full_text_content", | ||
store=True, | ||
) | ||
|
||
@api.depends("name", "description") | ||
def _compute_full_text_content(self): | ||
for task in self: | ||
text = " ".join((task.name, task.description or "")) | ||
text_with_no_accent = unidecode(text).lower() | ||
task.full_text_content = text_with_no_accent | ||
|
||
def _search_full_text_content(self, operator, value): | ||
if operator != "=": | ||
raise ValidationError( | ||
_( | ||
"The operator {operator} is not supported for full text search on tasks. " | ||
"You may use the equal operator instead." | ||
).format(operator=operator) | ||
) | ||
ids = self._find_tasks_from_full_text_content(value) if value else [] | ||
return [("id", "in", ids)] | ||
|
||
def _find_tasks_from_full_text_content(self, searched_text): | ||
"""Find tasks from the given searched text. | ||
:param searched_text: the text to search in task contents. | ||
""" | ||
lang = self._get_full_text_content_language() or "pg_catalog.english" | ||
words_to_search = unidecode(searched_text).lower().split(" ") | ||
self.env.cr.execute( | ||
""" | ||
SELECT id FROM project_task | ||
WHERE to_tsvector(%(lang)s, full_text_content) @@ plainto_tsquery( | ||
%(lang)s, %(words)s); | ||
""", | ||
{ | ||
"lang": lang, | ||
"words": " & ".join(words_to_search), | ||
}, | ||
) | ||
|
||
return [r[0] for r in self.env.cr.fetchall()] | ||
|
||
def _get_full_text_content_language(self): | ||
"""Get the language used for full text search on tasks. | ||
sudo() is required because the variable is required for searching content. | ||
""" | ||
return ( | ||
self.env["ir.config_parameter"].sudo().get_param(FULL_TEXT_SEARCH_PARAM_KEY) | ||
) | ||
|
||
|
||
class ProjectTaskWithFullTextSearchIndex(models.Model): | ||
"""Add a full text search index tasks. | ||
The index is optional for searching content from tasks. | ||
It only increases the spead of the full text search. | ||
""" | ||
|
||
_inherit = "project.task" | ||
|
||
def _setup_content_index(self): | ||
"""Setup a gin index on task content for the given language. | ||
:param pg_language_name: the name of the postgresql dictionnary to | ||
use for the the gin index. | ||
""" | ||
_logger.info("Droping the full text search index on project_task if it exists.") | ||
query = "DROP INDEX IF EXISTS {index_name}".format( | ||
index_name=FULL_TEXT_SEARCH_INDEX_NAME | ||
) | ||
self.env.cr.execute(query) | ||
|
||
lang = self._get_full_text_content_language() | ||
|
||
if lang: | ||
_logger.info( | ||
"Creating the full text search index on project_task " | ||
"with stemmings for the language {lang}.".format(lang=lang) | ||
) | ||
query = """ | ||
CREATE INDEX {index_name} ON project_task | ||
USING gin (to_tsvector(%(lang)s, full_text_content)); | ||
""".format( | ||
index_name=FULL_TEXT_SEARCH_INDEX_NAME | ||
) | ||
self.env.cr.execute(query, {"lang": lang}) | ||
else: | ||
_logger.info( | ||
"The system parameter {param_key} is not defined. " | ||
"The full text search index will not be created on project_task.".format( | ||
param_key=FULL_TEXT_SEARCH_PARAM_KEY | ||
) | ||
) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens) | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
from . import ( | ||
test_config_parameter, | ||
test_project_task, | ||
) |
Oops, something went wrong.